linux/drivers/net/wireless/ath/ath9k/debug.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2008-2009 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 <linux/slab.h>
  18#include <asm/unaligned.h>
  19
  20#include "ath9k.h"
  21
  22#define REG_WRITE_D(_ah, _reg, _val) \
  23        ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg))
  24#define REG_READ_D(_ah, _reg) \
  25        ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
  26
  27static int ath9k_debugfs_open(struct inode *inode, struct file *file)
  28{
  29        file->private_data = inode->i_private;
  30        return 0;
  31}
  32
  33#ifdef CONFIG_ATH_DEBUG
  34
  35static ssize_t read_file_debug(struct file *file, char __user *user_buf,
  36                             size_t count, loff_t *ppos)
  37{
  38        struct ath_softc *sc = file->private_data;
  39        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
  40        char buf[32];
  41        unsigned int len;
  42
  43        len = sprintf(buf, "0x%08x\n", common->debug_mask);
  44        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  45}
  46
  47static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
  48                             size_t count, loff_t *ppos)
  49{
  50        struct ath_softc *sc = file->private_data;
  51        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
  52        unsigned long mask;
  53        char buf[32];
  54        ssize_t len;
  55
  56        len = min(count, sizeof(buf) - 1);
  57        if (copy_from_user(buf, user_buf, len))
  58                return -EFAULT;
  59
  60        buf[len] = '\0';
  61        if (strict_strtoul(buf, 0, &mask))
  62                return -EINVAL;
  63
  64        common->debug_mask = mask;
  65        return count;
  66}
  67
  68static const struct file_operations fops_debug = {
  69        .read = read_file_debug,
  70        .write = write_file_debug,
  71        .open = ath9k_debugfs_open,
  72        .owner = THIS_MODULE,
  73        .llseek = default_llseek,
  74};
  75
  76#endif
  77
  78#define DMA_BUF_LEN 1024
  79
  80static ssize_t read_file_tx_chainmask(struct file *file, char __user *user_buf,
  81                             size_t count, loff_t *ppos)
  82{
  83        struct ath_softc *sc = file->private_data;
  84        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
  85        char buf[32];
  86        unsigned int len;
  87
  88        len = sprintf(buf, "0x%08x\n", common->tx_chainmask);
  89        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  90}
  91
  92static ssize_t write_file_tx_chainmask(struct file *file, const char __user *user_buf,
  93                             size_t count, loff_t *ppos)
  94{
  95        struct ath_softc *sc = file->private_data;
  96        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
  97        unsigned long mask;
  98        char buf[32];
  99        ssize_t len;
 100
 101        len = min(count, sizeof(buf) - 1);
 102        if (copy_from_user(buf, user_buf, len))
 103                return -EFAULT;
 104
 105        buf[len] = '\0';
 106        if (strict_strtoul(buf, 0, &mask))
 107                return -EINVAL;
 108
 109        common->tx_chainmask = mask;
 110        sc->sc_ah->caps.tx_chainmask = mask;
 111        return count;
 112}
 113
 114static const struct file_operations fops_tx_chainmask = {
 115        .read = read_file_tx_chainmask,
 116        .write = write_file_tx_chainmask,
 117        .open = ath9k_debugfs_open,
 118        .owner = THIS_MODULE,
 119        .llseek = default_llseek,
 120};
 121
 122
 123static ssize_t read_file_rx_chainmask(struct file *file, char __user *user_buf,
 124                             size_t count, loff_t *ppos)
 125{
 126        struct ath_softc *sc = file->private_data;
 127        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 128        char buf[32];
 129        unsigned int len;
 130
 131        len = sprintf(buf, "0x%08x\n", common->rx_chainmask);
 132        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 133}
 134
 135static ssize_t write_file_rx_chainmask(struct file *file, const char __user *user_buf,
 136                             size_t count, loff_t *ppos)
 137{
 138        struct ath_softc *sc = file->private_data;
 139        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 140        unsigned long mask;
 141        char buf[32];
 142        ssize_t len;
 143
 144        len = min(count, sizeof(buf) - 1);
 145        if (copy_from_user(buf, user_buf, len))
 146                return -EFAULT;
 147
 148        buf[len] = '\0';
 149        if (strict_strtoul(buf, 0, &mask))
 150                return -EINVAL;
 151
 152        common->rx_chainmask = mask;
 153        sc->sc_ah->caps.rx_chainmask = mask;
 154        return count;
 155}
 156
 157static const struct file_operations fops_rx_chainmask = {
 158        .read = read_file_rx_chainmask,
 159        .write = write_file_rx_chainmask,
 160        .open = ath9k_debugfs_open,
 161        .owner = THIS_MODULE,
 162        .llseek = default_llseek,
 163};
 164
 165
 166static ssize_t read_file_dma(struct file *file, char __user *user_buf,
 167                             size_t count, loff_t *ppos)
 168{
 169        struct ath_softc *sc = file->private_data;
 170        struct ath_hw *ah = sc->sc_ah;
 171        char *buf;
 172        int retval;
 173        unsigned int len = 0;
 174        u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
 175        int i, qcuOffset = 0, dcuOffset = 0;
 176        u32 *qcuBase = &val[0], *dcuBase = &val[4];
 177
 178        buf = kmalloc(DMA_BUF_LEN, GFP_KERNEL);
 179        if (!buf)
 180                return -ENOMEM;
 181
 182        ath9k_ps_wakeup(sc);
 183
 184        REG_WRITE_D(ah, AR_MACMISC,
 185                  ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
 186                   (AR_MACMISC_MISC_OBS_BUS_1 <<
 187                    AR_MACMISC_MISC_OBS_BUS_MSB_S)));
 188
 189        len += snprintf(buf + len, DMA_BUF_LEN - len,
 190                        "Raw DMA Debug values:\n");
 191
 192        for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
 193                if (i % 4 == 0)
 194                        len += snprintf(buf + len, DMA_BUF_LEN - len, "\n");
 195
 196                val[i] = REG_READ_D(ah, AR_DMADBG_0 + (i * sizeof(u32)));
 197                len += snprintf(buf + len, DMA_BUF_LEN - len, "%d: %08x ",
 198                                i, val[i]);
 199        }
 200
 201        len += snprintf(buf + len, DMA_BUF_LEN - len, "\n\n");
 202        len += snprintf(buf + len, DMA_BUF_LEN - len,
 203                        "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
 204
 205        for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) {
 206                if (i == 8) {
 207                        qcuOffset = 0;
 208                        qcuBase++;
 209                }
 210
 211                if (i == 6) {
 212                        dcuOffset = 0;
 213                        dcuBase++;
 214                }
 215
 216                len += snprintf(buf + len, DMA_BUF_LEN - len,
 217                        "%2d          %2x      %1x     %2x           %2x\n",
 218                        i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
 219                        (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3),
 220                        val[2] & (0x7 << (i * 3)) >> (i * 3),
 221                        (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
 222        }
 223
 224        len += snprintf(buf + len, DMA_BUF_LEN - len, "\n");
 225
 226        len += snprintf(buf + len, DMA_BUF_LEN - len,
 227                "qcu_stitch state:   %2x    qcu_fetch state:        %2x\n",
 228                (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
 229        len += snprintf(buf + len, DMA_BUF_LEN - len,
 230                "qcu_complete state: %2x    dcu_complete state:     %2x\n",
 231                (val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
 232        len += snprintf(buf + len, DMA_BUF_LEN - len,
 233                "dcu_arb state:      %2x    dcu_fp state:           %2x\n",
 234                (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
 235        len += snprintf(buf + len, DMA_BUF_LEN - len,
 236                "chan_idle_dur:     %3d    chan_idle_dur_valid:     %1d\n",
 237                (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
 238        len += snprintf(buf + len, DMA_BUF_LEN - len,
 239                "txfifo_valid_0:      %1d    txfifo_valid_1:          %1d\n",
 240                (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
 241        len += snprintf(buf + len, DMA_BUF_LEN - len,
 242                "txfifo_dcu_num_0:   %2d    txfifo_dcu_num_1:       %2d\n",
 243                (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
 244
 245        len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x\n",
 246                        REG_READ_D(ah, AR_OBS_BUS_1));
 247        len += snprintf(buf + len, DMA_BUF_LEN - len,
 248                        "AR_CR: 0x%x\n", REG_READ_D(ah, AR_CR));
 249
 250        ath9k_ps_restore(sc);
 251
 252        if (len > DMA_BUF_LEN)
 253                len = DMA_BUF_LEN;
 254
 255        retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 256        kfree(buf);
 257        return retval;
 258}
 259
 260static const struct file_operations fops_dma = {
 261        .read = read_file_dma,
 262        .open = ath9k_debugfs_open,
 263        .owner = THIS_MODULE,
 264        .llseek = default_llseek,
 265};
 266
 267
 268void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
 269{
 270        if (status)
 271                sc->debug.stats.istats.total++;
 272        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
 273                if (status & ATH9K_INT_RXLP)
 274                        sc->debug.stats.istats.rxlp++;
 275                if (status & ATH9K_INT_RXHP)
 276                        sc->debug.stats.istats.rxhp++;
 277                if (status & ATH9K_INT_BB_WATCHDOG)
 278                        sc->debug.stats.istats.bb_watchdog++;
 279        } else {
 280                if (status & ATH9K_INT_RX)
 281                        sc->debug.stats.istats.rxok++;
 282        }
 283        if (status & ATH9K_INT_RXEOL)
 284                sc->debug.stats.istats.rxeol++;
 285        if (status & ATH9K_INT_RXORN)
 286                sc->debug.stats.istats.rxorn++;
 287        if (status & ATH9K_INT_TX)
 288                sc->debug.stats.istats.txok++;
 289        if (status & ATH9K_INT_TXURN)
 290                sc->debug.stats.istats.txurn++;
 291        if (status & ATH9K_INT_MIB)
 292                sc->debug.stats.istats.mib++;
 293        if (status & ATH9K_INT_RXPHY)
 294                sc->debug.stats.istats.rxphyerr++;
 295        if (status & ATH9K_INT_RXKCM)
 296                sc->debug.stats.istats.rx_keycache_miss++;
 297        if (status & ATH9K_INT_SWBA)
 298                sc->debug.stats.istats.swba++;
 299        if (status & ATH9K_INT_BMISS)
 300                sc->debug.stats.istats.bmiss++;
 301        if (status & ATH9K_INT_BNR)
 302                sc->debug.stats.istats.bnr++;
 303        if (status & ATH9K_INT_CST)
 304                sc->debug.stats.istats.cst++;
 305        if (status & ATH9K_INT_GTT)
 306                sc->debug.stats.istats.gtt++;
 307        if (status & ATH9K_INT_TIM)
 308                sc->debug.stats.istats.tim++;
 309        if (status & ATH9K_INT_CABEND)
 310                sc->debug.stats.istats.cabend++;
 311        if (status & ATH9K_INT_DTIMSYNC)
 312                sc->debug.stats.istats.dtimsync++;
 313        if (status & ATH9K_INT_DTIM)
 314                sc->debug.stats.istats.dtim++;
 315}
 316
 317static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
 318                                   size_t count, loff_t *ppos)
 319{
 320        struct ath_softc *sc = file->private_data;
 321        char buf[512];
 322        unsigned int len = 0;
 323
 324        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
 325                len += snprintf(buf + len, sizeof(buf) - len,
 326                        "%8s: %10u\n", "RXLP", sc->debug.stats.istats.rxlp);
 327                len += snprintf(buf + len, sizeof(buf) - len,
 328                        "%8s: %10u\n", "RXHP", sc->debug.stats.istats.rxhp);
 329                len += snprintf(buf + len, sizeof(buf) - len,
 330                        "%8s: %10u\n", "WATCHDOG",
 331                        sc->debug.stats.istats.bb_watchdog);
 332        } else {
 333                len += snprintf(buf + len, sizeof(buf) - len,
 334                        "%8s: %10u\n", "RX", sc->debug.stats.istats.rxok);
 335        }
 336        len += snprintf(buf + len, sizeof(buf) - len,
 337                "%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol);
 338        len += snprintf(buf + len, sizeof(buf) - len,
 339                "%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn);
 340        len += snprintf(buf + len, sizeof(buf) - len,
 341                "%8s: %10u\n", "TX", sc->debug.stats.istats.txok);
 342        len += snprintf(buf + len, sizeof(buf) - len,
 343                "%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn);
 344        len += snprintf(buf + len, sizeof(buf) - len,
 345                "%8s: %10u\n", "MIB", sc->debug.stats.istats.mib);
 346        len += snprintf(buf + len, sizeof(buf) - len,
 347                "%8s: %10u\n", "RXPHY", sc->debug.stats.istats.rxphyerr);
 348        len += snprintf(buf + len, sizeof(buf) - len,
 349                "%8s: %10u\n", "RXKCM", sc->debug.stats.istats.rx_keycache_miss);
 350        len += snprintf(buf + len, sizeof(buf) - len,
 351                "%8s: %10u\n", "SWBA", sc->debug.stats.istats.swba);
 352        len += snprintf(buf + len, sizeof(buf) - len,
 353                "%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss);
 354        len += snprintf(buf + len, sizeof(buf) - len,
 355                "%8s: %10u\n", "BNR", sc->debug.stats.istats.bnr);
 356        len += snprintf(buf + len, sizeof(buf) - len,
 357                "%8s: %10u\n", "CST", sc->debug.stats.istats.cst);
 358        len += snprintf(buf + len, sizeof(buf) - len,
 359                "%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt);
 360        len += snprintf(buf + len, sizeof(buf) - len,
 361                "%8s: %10u\n", "TIM", sc->debug.stats.istats.tim);
 362        len += snprintf(buf + len, sizeof(buf) - len,
 363                "%8s: %10u\n", "CABEND", sc->debug.stats.istats.cabend);
 364        len += snprintf(buf + len, sizeof(buf) - len,
 365                "%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync);
 366        len += snprintf(buf + len, sizeof(buf) - len,
 367                "%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim);
 368        len += snprintf(buf + len, sizeof(buf) - len,
 369                "%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total);
 370
 371        if (len > sizeof(buf))
 372                len = sizeof(buf);
 373
 374        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 375}
 376
 377static const struct file_operations fops_interrupt = {
 378        .read = read_file_interrupt,
 379        .open = ath9k_debugfs_open,
 380        .owner = THIS_MODULE,
 381        .llseek = default_llseek,
 382};
 383
 384static const char * ath_wiphy_state_str(enum ath_wiphy_state state)
 385{
 386        switch (state) {
 387        case ATH_WIPHY_INACTIVE:
 388                return "INACTIVE";
 389        case ATH_WIPHY_ACTIVE:
 390                return "ACTIVE";
 391        case ATH_WIPHY_PAUSING:
 392                return "PAUSING";
 393        case ATH_WIPHY_PAUSED:
 394                return "PAUSED";
 395        case ATH_WIPHY_SCAN:
 396                return "SCAN";
 397        }
 398        return "?";
 399}
 400
 401static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
 402                               size_t count, loff_t *ppos)
 403{
 404        struct ath_softc *sc = file->private_data;
 405        struct ath_wiphy *aphy = sc->pri_wiphy;
 406        struct ieee80211_channel *chan = aphy->hw->conf.channel;
 407        char buf[512];
 408        unsigned int len = 0;
 409        int i;
 410        u8 addr[ETH_ALEN];
 411        u32 tmp;
 412
 413        len += snprintf(buf + len, sizeof(buf) - len,
 414                        "primary: %s (%s chan=%d ht=%d)\n",
 415                        wiphy_name(sc->pri_wiphy->hw->wiphy),
 416                        ath_wiphy_state_str(sc->pri_wiphy->state),
 417                        ieee80211_frequency_to_channel(chan->center_freq),
 418                        aphy->chan_is_ht);
 419
 420        put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
 421        put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
 422        len += snprintf(buf + len, sizeof(buf) - len,
 423                        "addr: %pM\n", addr);
 424        put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_BSSMSKL), addr);
 425        put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
 426        len += snprintf(buf + len, sizeof(buf) - len,
 427                        "addrmask: %pM\n", addr);
 428        tmp = ath9k_hw_getrxfilter(sc->sc_ah);
 429        len += snprintf(buf + len, sizeof(buf) - len,
 430                        "rfilt: 0x%x", tmp);
 431        if (tmp & ATH9K_RX_FILTER_UCAST)
 432                len += snprintf(buf + len, sizeof(buf) - len, " UCAST");
 433        if (tmp & ATH9K_RX_FILTER_MCAST)
 434                len += snprintf(buf + len, sizeof(buf) - len, " MCAST");
 435        if (tmp & ATH9K_RX_FILTER_BCAST)
 436                len += snprintf(buf + len, sizeof(buf) - len, " BCAST");
 437        if (tmp & ATH9K_RX_FILTER_CONTROL)
 438                len += snprintf(buf + len, sizeof(buf) - len, " CONTROL");
 439        if (tmp & ATH9K_RX_FILTER_BEACON)
 440                len += snprintf(buf + len, sizeof(buf) - len, " BEACON");
 441        if (tmp & ATH9K_RX_FILTER_PROM)
 442                len += snprintf(buf + len, sizeof(buf) - len, " PROM");
 443        if (tmp & ATH9K_RX_FILTER_PROBEREQ)
 444                len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
 445        if (tmp & ATH9K_RX_FILTER_PHYERR)
 446                len += snprintf(buf + len, sizeof(buf) - len, " PHYERR");
 447        if (tmp & ATH9K_RX_FILTER_MYBEACON)
 448                len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON");
 449        if (tmp & ATH9K_RX_FILTER_COMP_BAR)
 450                len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR");
 451        if (tmp & ATH9K_RX_FILTER_PSPOLL)
 452                len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL");
 453        if (tmp & ATH9K_RX_FILTER_PHYRADAR)
 454                len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR");
 455        if (tmp & ATH9K_RX_FILTER_MCAST_BCAST_ALL)
 456                len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL\n");
 457        else
 458                len += snprintf(buf + len, sizeof(buf) - len, "\n");
 459
 460        /* Put variable-length stuff down here, and check for overflows. */
 461        for (i = 0; i < sc->num_sec_wiphy; i++) {
 462                struct ath_wiphy *aphy_tmp = sc->sec_wiphy[i];
 463                if (aphy_tmp == NULL)
 464                        continue;
 465                chan = aphy_tmp->hw->conf.channel;
 466                len += snprintf(buf + len, sizeof(buf) - len,
 467                        "secondary: %s (%s chan=%d ht=%d)\n",
 468                        wiphy_name(aphy_tmp->hw->wiphy),
 469                        ath_wiphy_state_str(aphy_tmp->state),
 470                        ieee80211_frequency_to_channel(chan->center_freq),
 471                                                       aphy_tmp->chan_is_ht);
 472        }
 473        if (len > sizeof(buf))
 474                len = sizeof(buf);
 475
 476        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 477}
 478
 479static struct ath_wiphy * get_wiphy(struct ath_softc *sc, const char *name)
 480{
 481        int i;
 482        if (strcmp(name, wiphy_name(sc->pri_wiphy->hw->wiphy)) == 0)
 483                return sc->pri_wiphy;
 484        for (i = 0; i < sc->num_sec_wiphy; i++) {
 485                struct ath_wiphy *aphy = sc->sec_wiphy[i];
 486                if (aphy && strcmp(name, wiphy_name(aphy->hw->wiphy)) == 0)
 487                        return aphy;
 488        }
 489        return NULL;
 490}
 491
 492static int del_wiphy(struct ath_softc *sc, const char *name)
 493{
 494        struct ath_wiphy *aphy = get_wiphy(sc, name);
 495        if (!aphy)
 496                return -ENOENT;
 497        return ath9k_wiphy_del(aphy);
 498}
 499
 500static int pause_wiphy(struct ath_softc *sc, const char *name)
 501{
 502        struct ath_wiphy *aphy = get_wiphy(sc, name);
 503        if (!aphy)
 504                return -ENOENT;
 505        return ath9k_wiphy_pause(aphy);
 506}
 507
 508static int unpause_wiphy(struct ath_softc *sc, const char *name)
 509{
 510        struct ath_wiphy *aphy = get_wiphy(sc, name);
 511        if (!aphy)
 512                return -ENOENT;
 513        return ath9k_wiphy_unpause(aphy);
 514}
 515
 516static int select_wiphy(struct ath_softc *sc, const char *name)
 517{
 518        struct ath_wiphy *aphy = get_wiphy(sc, name);
 519        if (!aphy)
 520                return -ENOENT;
 521        return ath9k_wiphy_select(aphy);
 522}
 523
 524static int schedule_wiphy(struct ath_softc *sc, const char *msec)
 525{
 526        ath9k_wiphy_set_scheduler(sc, simple_strtoul(msec, NULL, 0));
 527        return 0;
 528}
 529
 530static ssize_t write_file_wiphy(struct file *file, const char __user *user_buf,
 531                                size_t count, loff_t *ppos)
 532{
 533        struct ath_softc *sc = file->private_data;
 534        char buf[50];
 535        size_t len;
 536
 537        len = min(count, sizeof(buf) - 1);
 538        if (copy_from_user(buf, user_buf, len))
 539                return -EFAULT;
 540        buf[len] = '\0';
 541        if (len > 0 && buf[len - 1] == '\n')
 542                buf[len - 1] = '\0';
 543
 544        if (strncmp(buf, "add", 3) == 0) {
 545                int res = ath9k_wiphy_add(sc);
 546                if (res < 0)
 547                        return res;
 548        } else if (strncmp(buf, "del=", 4) == 0) {
 549                int res = del_wiphy(sc, buf + 4);
 550                if (res < 0)
 551                        return res;
 552        } else if (strncmp(buf, "pause=", 6) == 0) {
 553                int res = pause_wiphy(sc, buf + 6);
 554                if (res < 0)
 555                        return res;
 556        } else if (strncmp(buf, "unpause=", 8) == 0) {
 557                int res = unpause_wiphy(sc, buf + 8);
 558                if (res < 0)
 559                        return res;
 560        } else if (strncmp(buf, "select=", 7) == 0) {
 561                int res = select_wiphy(sc, buf + 7);
 562                if (res < 0)
 563                        return res;
 564        } else if (strncmp(buf, "schedule=", 9) == 0) {
 565                int res = schedule_wiphy(sc, buf + 9);
 566                if (res < 0)
 567                        return res;
 568        } else
 569                return -EOPNOTSUPP;
 570
 571        return count;
 572}
 573
 574static const struct file_operations fops_wiphy = {
 575        .read = read_file_wiphy,
 576        .write = write_file_wiphy,
 577        .open = ath9k_debugfs_open,
 578        .owner = THIS_MODULE,
 579        .llseek = default_llseek,
 580};
 581
 582#define PR(str, elem)                                                   \
 583        do {                                                            \
 584                len += snprintf(buf + len, size - len,                  \
 585                                "%s%13u%11u%10u%10u\n", str,            \
 586                sc->debug.stats.txstats[WME_AC_BE].elem, \
 587                sc->debug.stats.txstats[WME_AC_BK].elem, \
 588                sc->debug.stats.txstats[WME_AC_VI].elem, \
 589                sc->debug.stats.txstats[WME_AC_VO].elem); \
 590} while(0)
 591
 592static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
 593                              size_t count, loff_t *ppos)
 594{
 595        struct ath_softc *sc = file->private_data;
 596        char *buf;
 597        unsigned int len = 0, size = 2048;
 598        ssize_t retval = 0;
 599
 600        buf = kzalloc(size, GFP_KERNEL);
 601        if (buf == NULL)
 602                return -ENOMEM;
 603
 604        len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO");
 605
 606        PR("MPDUs Queued:    ", queued);
 607        PR("MPDUs Completed: ", completed);
 608        PR("Aggregates:      ", a_aggr);
 609        PR("AMPDUs Queued:   ", a_queued);
 610        PR("AMPDUs Completed:", a_completed);
 611        PR("AMPDUs Retried:  ", a_retries);
 612        PR("AMPDUs XRetried: ", a_xretries);
 613        PR("FIFO Underrun:   ", fifo_underrun);
 614        PR("TXOP Exceeded:   ", xtxop);
 615        PR("TXTIMER Expiry:  ", timer_exp);
 616        PR("DESC CFG Error:  ", desc_cfg_err);
 617        PR("DATA Underrun:   ", data_underrun);
 618        PR("DELIM Underrun:  ", delim_underrun);
 619        PR("TX-Pkts-All:     ", tx_pkts_all);
 620        PR("TX-Bytes-All:    ", tx_bytes_all);
 621
 622        if (len > size)
 623                len = size;
 624
 625        retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 626        kfree(buf);
 627
 628        return retval;
 629}
 630
 631void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
 632                       struct ath_tx_status *ts)
 633{
 634        int qnum = skb_get_queue_mapping(bf->bf_mpdu);
 635
 636        TX_STAT_INC(qnum, tx_pkts_all);
 637        sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len;
 638
 639        if (bf_isampdu(bf)) {
 640                if (bf_isxretried(bf))
 641                        TX_STAT_INC(qnum, a_xretries);
 642                else
 643                        TX_STAT_INC(qnum, a_completed);
 644        } else {
 645                TX_STAT_INC(qnum, completed);
 646        }
 647
 648        if (ts->ts_status & ATH9K_TXERR_FIFO)
 649                TX_STAT_INC(qnum, fifo_underrun);
 650        if (ts->ts_status & ATH9K_TXERR_XTXOP)
 651                TX_STAT_INC(qnum, xtxop);
 652        if (ts->ts_status & ATH9K_TXERR_TIMER_EXPIRED)
 653                TX_STAT_INC(qnum, timer_exp);
 654        if (ts->ts_flags & ATH9K_TX_DESC_CFG_ERR)
 655                TX_STAT_INC(qnum, desc_cfg_err);
 656        if (ts->ts_flags & ATH9K_TX_DATA_UNDERRUN)
 657                TX_STAT_INC(qnum, data_underrun);
 658        if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN)
 659                TX_STAT_INC(qnum, delim_underrun);
 660}
 661
 662static const struct file_operations fops_xmit = {
 663        .read = read_file_xmit,
 664        .open = ath9k_debugfs_open,
 665        .owner = THIS_MODULE,
 666        .llseek = default_llseek,
 667};
 668
 669static ssize_t read_file_recv(struct file *file, char __user *user_buf,
 670                              size_t count, loff_t *ppos)
 671{
 672#define PHY_ERR(s, p) \
 673        len += snprintf(buf + len, size - len, "%18s : %10u\n", s, \
 674                        sc->debug.stats.rxstats.phy_err_stats[p]);
 675
 676        struct ath_softc *sc = file->private_data;
 677        char *buf;
 678        unsigned int len = 0, size = 1152;
 679        ssize_t retval = 0;
 680
 681        buf = kzalloc(size, GFP_KERNEL);
 682        if (buf == NULL)
 683                return -ENOMEM;
 684
 685        len += snprintf(buf + len, size - len,
 686                        "%18s : %10u\n", "CRC ERR",
 687                        sc->debug.stats.rxstats.crc_err);
 688        len += snprintf(buf + len, size - len,
 689                        "%18s : %10u\n", "DECRYPT CRC ERR",
 690                        sc->debug.stats.rxstats.decrypt_crc_err);
 691        len += snprintf(buf + len, size - len,
 692                        "%18s : %10u\n", "PHY ERR",
 693                        sc->debug.stats.rxstats.phy_err);
 694        len += snprintf(buf + len, size - len,
 695                        "%18s : %10u\n", "MIC ERR",
 696                        sc->debug.stats.rxstats.mic_err);
 697        len += snprintf(buf + len, size - len,
 698                        "%18s : %10u\n", "PRE-DELIM CRC ERR",
 699                        sc->debug.stats.rxstats.pre_delim_crc_err);
 700        len += snprintf(buf + len, size - len,
 701                        "%18s : %10u\n", "POST-DELIM CRC ERR",
 702                        sc->debug.stats.rxstats.post_delim_crc_err);
 703        len += snprintf(buf + len, size - len,
 704                        "%18s : %10u\n", "DECRYPT BUSY ERR",
 705                        sc->debug.stats.rxstats.decrypt_busy_err);
 706
 707        PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
 708        PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
 709        PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
 710        PHY_ERR("RATE", ATH9K_PHYERR_RATE);
 711        PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH);
 712        PHY_ERR("RADAR", ATH9K_PHYERR_RADAR);
 713        PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE);
 714        PHY_ERR("TOR", ATH9K_PHYERR_TOR);
 715        PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING);
 716        PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
 717        PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
 718        PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
 719        PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP);
 720        PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE);
 721        PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART);
 722        PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT);
 723        PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING);
 724        PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC);
 725        PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
 726        PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE);
 727        PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART);
 728        PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
 729        PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP);
 730        PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR);
 731        PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
 732        PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
 733
 734        len += snprintf(buf + len, size - len,
 735                        "%18s : %10u\n", "RX-Pkts-All",
 736                        sc->debug.stats.rxstats.rx_pkts_all);
 737        len += snprintf(buf + len, size - len,
 738                        "%18s : %10u\n", "RX-Bytes-All",
 739                        sc->debug.stats.rxstats.rx_bytes_all);
 740
 741        if (len > size)
 742                len = size;
 743
 744        retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 745        kfree(buf);
 746
 747        return retval;
 748
 749#undef PHY_ERR
 750}
 751
 752void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
 753{
 754#define RX_STAT_INC(c) sc->debug.stats.rxstats.c++
 755#define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++
 756
 757        u32 phyerr;
 758
 759        RX_STAT_INC(rx_pkts_all);
 760        sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen;
 761
 762        if (rs->rs_status & ATH9K_RXERR_CRC)
 763                RX_STAT_INC(crc_err);
 764        if (rs->rs_status & ATH9K_RXERR_DECRYPT)
 765                RX_STAT_INC(decrypt_crc_err);
 766        if (rs->rs_status & ATH9K_RXERR_MIC)
 767                RX_STAT_INC(mic_err);
 768        if (rs->rs_status & ATH9K_RX_DELIM_CRC_PRE)
 769                RX_STAT_INC(pre_delim_crc_err);
 770        if (rs->rs_status & ATH9K_RX_DELIM_CRC_POST)
 771                RX_STAT_INC(post_delim_crc_err);
 772        if (rs->rs_status & ATH9K_RX_DECRYPT_BUSY)
 773                RX_STAT_INC(decrypt_busy_err);
 774
 775        if (rs->rs_status & ATH9K_RXERR_PHY) {
 776                RX_STAT_INC(phy_err);
 777                phyerr = rs->rs_phyerr & 0x24;
 778                RX_PHY_ERR_INC(phyerr);
 779        }
 780
 781#undef RX_STAT_INC
 782#undef RX_PHY_ERR_INC
 783}
 784
 785static const struct file_operations fops_recv = {
 786        .read = read_file_recv,
 787        .open = ath9k_debugfs_open,
 788        .owner = THIS_MODULE,
 789        .llseek = default_llseek,
 790};
 791
 792static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
 793                                size_t count, loff_t *ppos)
 794{
 795        struct ath_softc *sc = file->private_data;
 796        char buf[32];
 797        unsigned int len;
 798
 799        len = sprintf(buf, "0x%08x\n", sc->debug.regidx);
 800        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 801}
 802
 803static ssize_t write_file_regidx(struct file *file, const char __user *user_buf,
 804                             size_t count, loff_t *ppos)
 805{
 806        struct ath_softc *sc = file->private_data;
 807        unsigned long regidx;
 808        char buf[32];
 809        ssize_t len;
 810
 811        len = min(count, sizeof(buf) - 1);
 812        if (copy_from_user(buf, user_buf, len))
 813                return -EFAULT;
 814
 815        buf[len] = '\0';
 816        if (strict_strtoul(buf, 0, &regidx))
 817                return -EINVAL;
 818
 819        sc->debug.regidx = regidx;
 820        return count;
 821}
 822
 823static const struct file_operations fops_regidx = {
 824        .read = read_file_regidx,
 825        .write = write_file_regidx,
 826        .open = ath9k_debugfs_open,
 827        .owner = THIS_MODULE,
 828        .llseek = default_llseek,
 829};
 830
 831static ssize_t read_file_regval(struct file *file, char __user *user_buf,
 832                             size_t count, loff_t *ppos)
 833{
 834        struct ath_softc *sc = file->private_data;
 835        struct ath_hw *ah = sc->sc_ah;
 836        char buf[32];
 837        unsigned int len;
 838        u32 regval;
 839
 840        regval = REG_READ_D(ah, sc->debug.regidx);
 841        len = sprintf(buf, "0x%08x\n", regval);
 842        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 843}
 844
 845static ssize_t write_file_regval(struct file *file, const char __user *user_buf,
 846                             size_t count, loff_t *ppos)
 847{
 848        struct ath_softc *sc = file->private_data;
 849        struct ath_hw *ah = sc->sc_ah;
 850        unsigned long regval;
 851        char buf[32];
 852        ssize_t len;
 853
 854        len = min(count, sizeof(buf) - 1);
 855        if (copy_from_user(buf, user_buf, len))
 856                return -EFAULT;
 857
 858        buf[len] = '\0';
 859        if (strict_strtoul(buf, 0, &regval))
 860                return -EINVAL;
 861
 862        REG_WRITE_D(ah, sc->debug.regidx, regval);
 863        return count;
 864}
 865
 866static const struct file_operations fops_regval = {
 867        .read = read_file_regval,
 868        .write = write_file_regval,
 869        .open = ath9k_debugfs_open,
 870        .owner = THIS_MODULE,
 871        .llseek = default_llseek,
 872};
 873
 874int ath9k_init_debug(struct ath_hw *ah)
 875{
 876        struct ath_common *common = ath9k_hw_common(ah);
 877        struct ath_softc *sc = (struct ath_softc *) common->priv;
 878
 879        sc->debug.debugfs_phy = debugfs_create_dir("ath9k",
 880                                                   sc->hw->wiphy->debugfsdir);
 881        if (!sc->debug.debugfs_phy)
 882                return -ENOMEM;
 883
 884#ifdef CONFIG_ATH_DEBUG
 885        if (!debugfs_create_file("debug", S_IRUSR | S_IWUSR,
 886                        sc->debug.debugfs_phy, sc, &fops_debug))
 887                goto err;
 888#endif
 889
 890        if (!debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy,
 891                        sc, &fops_dma))
 892                goto err;
 893
 894        if (!debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy,
 895                        sc, &fops_interrupt))
 896                goto err;
 897
 898        if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR,
 899                        sc->debug.debugfs_phy, sc, &fops_wiphy))
 900                goto err;
 901
 902        if (!debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy,
 903                        sc, &fops_xmit))
 904                goto err;
 905
 906        if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy,
 907                        sc, &fops_recv))
 908                goto err;
 909
 910        if (!debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR,
 911                        sc->debug.debugfs_phy, sc, &fops_rx_chainmask))
 912                goto err;
 913
 914        if (!debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
 915                        sc->debug.debugfs_phy, sc, &fops_tx_chainmask))
 916                goto err;
 917
 918        if (!debugfs_create_file("regidx", S_IRUSR | S_IWUSR,
 919                        sc->debug.debugfs_phy, sc, &fops_regidx))
 920                goto err;
 921
 922        if (!debugfs_create_file("regval", S_IRUSR | S_IWUSR,
 923                        sc->debug.debugfs_phy, sc, &fops_regval))
 924                goto err;
 925
 926        if (!debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR,
 927                        sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca))
 928                goto err;
 929
 930        sc->debug.regidx = 0;
 931        return 0;
 932err:
 933        debugfs_remove_recursive(sc->debug.debugfs_phy);
 934        sc->debug.debugfs_phy = NULL;
 935        return -ENOMEM;
 936}
 937