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 <asm/unaligned.h> 18 19 #include "ath9k.h" 20 21 static unsigned int ath9k_debug = DBG_DEFAULT; 22 module_param_named(debug, ath9k_debug, uint, 0); 23 24 static struct dentry *ath9k_debugfs_root; 25 26 void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) 27 { 28 if (!sc) 29 return; 30 31 if (sc->debug.debug_mask & dbg_mask) { 32 va_list args; 33 34 va_start(args, fmt); 35 printk(KERN_DEBUG "ath9k: "); 36 vprintk(fmt, args); 37 va_end(args); 38 } 39 } 40 41 static int ath9k_debugfs_open(struct inode *inode, struct file *file) 42 { 43 file->private_data = inode->i_private; 44 return 0; 45 } 46 47 static ssize_t read_file_debug(struct file *file, char __user *user_buf, 48 size_t count, loff_t *ppos) 49 { 50 struct ath_softc *sc = file->private_data; 51 char buf[32]; 52 unsigned int len; 53 54 len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.debug_mask); 55 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 56 } 57 58 static ssize_t write_file_debug(struct file *file, const char __user *user_buf, 59 size_t count, loff_t *ppos) 60 { 61 struct ath_softc *sc = file->private_data; 62 unsigned long mask; 63 char buf[32]; 64 ssize_t len; 65 66 len = min(count, sizeof(buf) - 1); 67 if (copy_from_user(buf, user_buf, len)) 68 return -EINVAL; 69 70 buf[len] = '\0'; 71 if (strict_strtoul(buf, 0, &mask)) 72 return -EINVAL; 73 74 sc->debug.debug_mask = mask; 75 return count; 76 } 77 78 static const struct file_operations fops_debug = { 79 .read = read_file_debug, 80 .write = write_file_debug, 81 .open = ath9k_debugfs_open, 82 .owner = THIS_MODULE 83 }; 84 85 static ssize_t read_file_dma(struct file *file, char __user *user_buf, 86 size_t count, loff_t *ppos) 87 { 88 struct ath_softc *sc = file->private_data; 89 struct ath_hw *ah = sc->sc_ah; 90 char buf[1024]; 91 unsigned int len = 0; 92 u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; 93 int i, qcuOffset = 0, dcuOffset = 0; 94 u32 *qcuBase = &val[0], *dcuBase = &val[4]; 95 96 ath9k_ps_wakeup(sc); 97 98 REG_WRITE(ah, AR_MACMISC, 99 ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | 100 (AR_MACMISC_MISC_OBS_BUS_1 << 101 AR_MACMISC_MISC_OBS_BUS_MSB_S))); 102 103 len += snprintf(buf + len, sizeof(buf) - len, 104 "Raw DMA Debug values:\n"); 105 106 for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { 107 if (i % 4 == 0) 108 len += snprintf(buf + len, sizeof(buf) - len, "\n"); 109 110 val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); 111 len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ", 112 i, val[i]); 113 } 114 115 len += snprintf(buf + len, sizeof(buf) - len, "\n\n"); 116 len += snprintf(buf + len, sizeof(buf) - len, 117 "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); 118 119 for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) { 120 if (i == 8) { 121 qcuOffset = 0; 122 qcuBase++; 123 } 124 125 if (i == 6) { 126 dcuOffset = 0; 127 dcuBase++; 128 } 129 130 len += snprintf(buf + len, sizeof(buf) - len, 131 "%2d %2x %1x %2x %2x\n", 132 i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, 133 (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), 134 val[2] & (0x7 << (i * 3)) >> (i * 3), 135 (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); 136 } 137 138 len += snprintf(buf + len, sizeof(buf) - len, "\n"); 139 140 len += snprintf(buf + len, sizeof(buf) - len, 141 "qcu_stitch state: %2x qcu_fetch state: %2x\n", 142 (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); 143 len += snprintf(buf + len, sizeof(buf) - len, 144 "qcu_complete state: %2x dcu_complete state: %2x\n", 145 (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); 146 len += snprintf(buf + len, sizeof(buf) - len, 147 "dcu_arb state: %2x dcu_fp state: %2x\n", 148 (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); 149 len += snprintf(buf + len, sizeof(buf) - len, 150 "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", 151 (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); 152 len += snprintf(buf + len, sizeof(buf) - len, 153 "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", 154 (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); 155 len += snprintf(buf + len, sizeof(buf) - len, 156 "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", 157 (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); 158 159 len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n", 160 REG_READ(ah, AR_OBS_BUS_1)); 161 len += snprintf(buf + len, sizeof(buf) - len, 162 "AR_CR: 0x%x \n", REG_READ(ah, AR_CR)); 163 164 ath9k_ps_restore(sc); 165 166 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 167 } 168 169 static const struct file_operations fops_dma = { 170 .read = read_file_dma, 171 .open = ath9k_debugfs_open, 172 .owner = THIS_MODULE 173 }; 174 175 176 void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) 177 { 178 if (status) 179 sc->debug.stats.istats.total++; 180 if (status & ATH9K_INT_RX) 181 sc->debug.stats.istats.rxok++; 182 if (status & ATH9K_INT_RXEOL) 183 sc->debug.stats.istats.rxeol++; 184 if (status & ATH9K_INT_RXORN) 185 sc->debug.stats.istats.rxorn++; 186 if (status & ATH9K_INT_TX) 187 sc->debug.stats.istats.txok++; 188 if (status & ATH9K_INT_TXURN) 189 sc->debug.stats.istats.txurn++; 190 if (status & ATH9K_INT_MIB) 191 sc->debug.stats.istats.mib++; 192 if (status & ATH9K_INT_RXPHY) 193 sc->debug.stats.istats.rxphyerr++; 194 if (status & ATH9K_INT_RXKCM) 195 sc->debug.stats.istats.rx_keycache_miss++; 196 if (status & ATH9K_INT_SWBA) 197 sc->debug.stats.istats.swba++; 198 if (status & ATH9K_INT_BMISS) 199 sc->debug.stats.istats.bmiss++; 200 if (status & ATH9K_INT_BNR) 201 sc->debug.stats.istats.bnr++; 202 if (status & ATH9K_INT_CST) 203 sc->debug.stats.istats.cst++; 204 if (status & ATH9K_INT_GTT) 205 sc->debug.stats.istats.gtt++; 206 if (status & ATH9K_INT_TIM) 207 sc->debug.stats.istats.tim++; 208 if (status & ATH9K_INT_CABEND) 209 sc->debug.stats.istats.cabend++; 210 if (status & ATH9K_INT_DTIMSYNC) 211 sc->debug.stats.istats.dtimsync++; 212 if (status & ATH9K_INT_DTIM) 213 sc->debug.stats.istats.dtim++; 214 } 215 216 static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, 217 size_t count, loff_t *ppos) 218 { 219 struct ath_softc *sc = file->private_data; 220 char buf[512]; 221 unsigned int len = 0; 222 223 len += snprintf(buf + len, sizeof(buf) - len, 224 "%8s: %10u\n", "RX", sc->debug.stats.istats.rxok); 225 len += snprintf(buf + len, sizeof(buf) - len, 226 "%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol); 227 len += snprintf(buf + len, sizeof(buf) - len, 228 "%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn); 229 len += snprintf(buf + len, sizeof(buf) - len, 230 "%8s: %10u\n", "TX", sc->debug.stats.istats.txok); 231 len += snprintf(buf + len, sizeof(buf) - len, 232 "%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn); 233 len += snprintf(buf + len, sizeof(buf) - len, 234 "%8s: %10u\n", "MIB", sc->debug.stats.istats.mib); 235 len += snprintf(buf + len, sizeof(buf) - len, 236 "%8s: %10u\n", "RXPHY", sc->debug.stats.istats.rxphyerr); 237 len += snprintf(buf + len, sizeof(buf) - len, 238 "%8s: %10u\n", "RXKCM", sc->debug.stats.istats.rx_keycache_miss); 239 len += snprintf(buf + len, sizeof(buf) - len, 240 "%8s: %10u\n", "SWBA", sc->debug.stats.istats.swba); 241 len += snprintf(buf + len, sizeof(buf) - len, 242 "%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss); 243 len += snprintf(buf + len, sizeof(buf) - len, 244 "%8s: %10u\n", "BNR", sc->debug.stats.istats.bnr); 245 len += snprintf(buf + len, sizeof(buf) - len, 246 "%8s: %10u\n", "CST", sc->debug.stats.istats.cst); 247 len += snprintf(buf + len, sizeof(buf) - len, 248 "%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt); 249 len += snprintf(buf + len, sizeof(buf) - len, 250 "%8s: %10u\n", "TIM", sc->debug.stats.istats.tim); 251 len += snprintf(buf + len, sizeof(buf) - len, 252 "%8s: %10u\n", "CABEND", sc->debug.stats.istats.cabend); 253 len += snprintf(buf + len, sizeof(buf) - len, 254 "%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync); 255 len += snprintf(buf + len, sizeof(buf) - len, 256 "%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim); 257 len += snprintf(buf + len, sizeof(buf) - len, 258 "%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total); 259 260 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 261 } 262 263 static const struct file_operations fops_interrupt = { 264 .read = read_file_interrupt, 265 .open = ath9k_debugfs_open, 266 .owner = THIS_MODULE 267 }; 268 269 void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) 270 { 271 struct ath_tx_info_priv *tx_info_priv = NULL; 272 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 273 struct ieee80211_tx_rate *rates = tx_info->status.rates; 274 int final_ts_idx, idx; 275 struct ath_rc_stats *stats; 276 277 tx_info_priv = ATH_TX_INFO_PRIV(tx_info); 278 final_ts_idx = tx_info_priv->tx.ts_rateindex; 279 idx = rates[final_ts_idx].idx; 280 stats = &sc->debug.stats.rcstats[idx]; 281 stats->success++; 282 } 283 284 void ath_debug_stat_retries(struct ath_softc *sc, int rix, 285 int xretries, int retries, u8 per) 286 { 287 struct ath_rc_stats *stats = &sc->debug.stats.rcstats[rix]; 288 289 stats->xretries += xretries; 290 stats->retries += retries; 291 stats->per = per; 292 } 293 294 static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, 295 size_t count, loff_t *ppos) 296 { 297 struct ath_softc *sc = file->private_data; 298 char *buf; 299 unsigned int len = 0, max; 300 int i = 0; 301 ssize_t retval; 302 303 if (sc->cur_rate_table == NULL) 304 return 0; 305 306 max = 80 + sc->cur_rate_table->rate_cnt * 64; 307 buf = kmalloc(max + 1, GFP_KERNEL); 308 if (buf == NULL) 309 return 0; 310 buf[max] = 0; 311 312 len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success", 313 "Retries", "XRetries", "PER"); 314 315 for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { 316 u32 ratekbps = sc->cur_rate_table->info[i].ratekbps; 317 struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i]; 318 319 len += snprintf(buf + len, max - len, 320 "%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000, 321 (ratekbps % 1000) / 100, stats->success, 322 stats->retries, stats->xretries, 323 stats->per); 324 } 325 326 retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); 327 kfree(buf); 328 return retval; 329 } 330 331 static const struct file_operations fops_rcstat = { 332 .read = read_file_rcstat, 333 .open = ath9k_debugfs_open, 334 .owner = THIS_MODULE 335 }; 336 337 static const char * ath_wiphy_state_str(enum ath_wiphy_state state) 338 { 339 switch (state) { 340 case ATH_WIPHY_INACTIVE: 341 return "INACTIVE"; 342 case ATH_WIPHY_ACTIVE: 343 return "ACTIVE"; 344 case ATH_WIPHY_PAUSING: 345 return "PAUSING"; 346 case ATH_WIPHY_PAUSED: 347 return "PAUSED"; 348 case ATH_WIPHY_SCAN: 349 return "SCAN"; 350 } 351 return "?"; 352 } 353 354 static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, 355 size_t count, loff_t *ppos) 356 { 357 struct ath_softc *sc = file->private_data; 358 char buf[512]; 359 unsigned int len = 0; 360 int i; 361 u8 addr[ETH_ALEN]; 362 363 len += snprintf(buf + len, sizeof(buf) - len, 364 "primary: %s (%s chan=%d ht=%d)\n", 365 wiphy_name(sc->pri_wiphy->hw->wiphy), 366 ath_wiphy_state_str(sc->pri_wiphy->state), 367 sc->pri_wiphy->chan_idx, sc->pri_wiphy->chan_is_ht); 368 for (i = 0; i < sc->num_sec_wiphy; i++) { 369 struct ath_wiphy *aphy = sc->sec_wiphy[i]; 370 if (aphy == NULL) 371 continue; 372 len += snprintf(buf + len, sizeof(buf) - len, 373 "secondary: %s (%s chan=%d ht=%d)\n", 374 wiphy_name(aphy->hw->wiphy), 375 ath_wiphy_state_str(aphy->state), 376 aphy->chan_idx, aphy->chan_is_ht); 377 } 378 379 put_unaligned_le32(REG_READ(sc->sc_ah, AR_STA_ID0), addr); 380 put_unaligned_le16(REG_READ(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); 381 len += snprintf(buf + len, sizeof(buf) - len, 382 "addr: %pM\n", addr); 383 put_unaligned_le32(REG_READ(sc->sc_ah, AR_BSSMSKL), addr); 384 put_unaligned_le16(REG_READ(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4); 385 len += snprintf(buf + len, sizeof(buf) - len, 386 "addrmask: %pM\n", addr); 387 388 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 389 } 390 391 static struct ath_wiphy * get_wiphy(struct ath_softc *sc, const char *name) 392 { 393 int i; 394 if (strcmp(name, wiphy_name(sc->pri_wiphy->hw->wiphy)) == 0) 395 return sc->pri_wiphy; 396 for (i = 0; i < sc->num_sec_wiphy; i++) { 397 struct ath_wiphy *aphy = sc->sec_wiphy[i]; 398 if (aphy && strcmp(name, wiphy_name(aphy->hw->wiphy)) == 0) 399 return aphy; 400 } 401 return NULL; 402 } 403 404 static int del_wiphy(struct ath_softc *sc, const char *name) 405 { 406 struct ath_wiphy *aphy = get_wiphy(sc, name); 407 if (!aphy) 408 return -ENOENT; 409 return ath9k_wiphy_del(aphy); 410 } 411 412 static int pause_wiphy(struct ath_softc *sc, const char *name) 413 { 414 struct ath_wiphy *aphy = get_wiphy(sc, name); 415 if (!aphy) 416 return -ENOENT; 417 return ath9k_wiphy_pause(aphy); 418 } 419 420 static int unpause_wiphy(struct ath_softc *sc, const char *name) 421 { 422 struct ath_wiphy *aphy = get_wiphy(sc, name); 423 if (!aphy) 424 return -ENOENT; 425 return ath9k_wiphy_unpause(aphy); 426 } 427 428 static int select_wiphy(struct ath_softc *sc, const char *name) 429 { 430 struct ath_wiphy *aphy = get_wiphy(sc, name); 431 if (!aphy) 432 return -ENOENT; 433 return ath9k_wiphy_select(aphy); 434 } 435 436 static int schedule_wiphy(struct ath_softc *sc, const char *msec) 437 { 438 ath9k_wiphy_set_scheduler(sc, simple_strtoul(msec, NULL, 0)); 439 return 0; 440 } 441 442 static ssize_t write_file_wiphy(struct file *file, const char __user *user_buf, 443 size_t count, loff_t *ppos) 444 { 445 struct ath_softc *sc = file->private_data; 446 char buf[50]; 447 size_t len; 448 449 len = min(count, sizeof(buf) - 1); 450 if (copy_from_user(buf, user_buf, len)) 451 return -EFAULT; 452 buf[len] = '\0'; 453 if (len > 0 && buf[len - 1] == '\n') 454 buf[len - 1] = '\0'; 455 456 if (strncmp(buf, "add", 3) == 0) { 457 int res = ath9k_wiphy_add(sc); 458 if (res < 0) 459 return res; 460 } else if (strncmp(buf, "del=", 4) == 0) { 461 int res = del_wiphy(sc, buf + 4); 462 if (res < 0) 463 return res; 464 } else if (strncmp(buf, "pause=", 6) == 0) { 465 int res = pause_wiphy(sc, buf + 6); 466 if (res < 0) 467 return res; 468 } else if (strncmp(buf, "unpause=", 8) == 0) { 469 int res = unpause_wiphy(sc, buf + 8); 470 if (res < 0) 471 return res; 472 } else if (strncmp(buf, "select=", 7) == 0) { 473 int res = select_wiphy(sc, buf + 7); 474 if (res < 0) 475 return res; 476 } else if (strncmp(buf, "schedule=", 9) == 0) { 477 int res = schedule_wiphy(sc, buf + 9); 478 if (res < 0) 479 return res; 480 } else 481 return -EOPNOTSUPP; 482 483 return count; 484 } 485 486 static const struct file_operations fops_wiphy = { 487 .read = read_file_wiphy, 488 .write = write_file_wiphy, 489 .open = ath9k_debugfs_open, 490 .owner = THIS_MODULE 491 }; 492 493 #define PR(str, elem) \ 494 do { \ 495 len += snprintf(buf + len, size - len, \ 496 "%s%13u%11u%10u%10u\n", str, \ 497 sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BE]].elem, \ 498 sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BK]].elem, \ 499 sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VI]].elem, \ 500 sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VO]].elem); \ 501 } while(0) 502 503 static ssize_t read_file_xmit(struct file *file, char __user *user_buf, 504 size_t count, loff_t *ppos) 505 { 506 struct ath_softc *sc = file->private_data; 507 char *buf; 508 unsigned int len = 0, size = 2048; 509 ssize_t retval = 0; 510 511 buf = kzalloc(size, GFP_KERNEL); 512 if (buf == NULL) 513 return 0; 514 515 len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO"); 516 517 PR("MPDUs Queued: ", queued); 518 PR("MPDUs Completed: ", completed); 519 PR("Aggregates: ", a_aggr); 520 PR("AMPDUs Queued: ", a_queued); 521 PR("AMPDUs Completed:", a_completed); 522 PR("AMPDUs Retried: ", a_retries); 523 PR("AMPDUs XRetried: ", a_xretries); 524 PR("FIFO Underrun: ", fifo_underrun); 525 PR("TXOP Exceeded: ", xtxop); 526 PR("TXTIMER Expiry: ", timer_exp); 527 PR("DESC CFG Error: ", desc_cfg_err); 528 PR("DATA Underrun: ", data_underrun); 529 PR("DELIM Underrun: ", delim_underrun); 530 531 retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); 532 kfree(buf); 533 534 return retval; 535 } 536 537 void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, 538 struct ath_buf *bf) 539 { 540 struct ath_desc *ds = bf->bf_desc; 541 542 if (bf_isampdu(bf)) { 543 if (bf_isxretried(bf)) 544 TX_STAT_INC(txq->axq_qnum, a_xretries); 545 else 546 TX_STAT_INC(txq->axq_qnum, a_completed); 547 } else { 548 TX_STAT_INC(txq->axq_qnum, completed); 549 } 550 551 if (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO) 552 TX_STAT_INC(txq->axq_qnum, fifo_underrun); 553 if (ds->ds_txstat.ts_status & ATH9K_TXERR_XTXOP) 554 TX_STAT_INC(txq->axq_qnum, xtxop); 555 if (ds->ds_txstat.ts_status & ATH9K_TXERR_TIMER_EXPIRED) 556 TX_STAT_INC(txq->axq_qnum, timer_exp); 557 if (ds->ds_txstat.ts_flags & ATH9K_TX_DESC_CFG_ERR) 558 TX_STAT_INC(txq->axq_qnum, desc_cfg_err); 559 if (ds->ds_txstat.ts_flags & ATH9K_TX_DATA_UNDERRUN) 560 TX_STAT_INC(txq->axq_qnum, data_underrun); 561 if (ds->ds_txstat.ts_flags & ATH9K_TX_DELIM_UNDERRUN) 562 TX_STAT_INC(txq->axq_qnum, delim_underrun); 563 } 564 565 static const struct file_operations fops_xmit = { 566 .read = read_file_xmit, 567 .open = ath9k_debugfs_open, 568 .owner = THIS_MODULE 569 }; 570 571 int ath9k_init_debug(struct ath_softc *sc) 572 { 573 sc->debug.debug_mask = ath9k_debug; 574 575 if (!ath9k_debugfs_root) 576 return -ENOENT; 577 578 sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy), 579 ath9k_debugfs_root); 580 if (!sc->debug.debugfs_phy) 581 goto err; 582 583 sc->debug.debugfs_debug = debugfs_create_file("debug", 584 S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); 585 if (!sc->debug.debugfs_debug) 586 goto err; 587 588 sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR, 589 sc->debug.debugfs_phy, sc, &fops_dma); 590 if (!sc->debug.debugfs_dma) 591 goto err; 592 593 sc->debug.debugfs_interrupt = debugfs_create_file("interrupt", 594 S_IRUSR, 595 sc->debug.debugfs_phy, 596 sc, &fops_interrupt); 597 if (!sc->debug.debugfs_interrupt) 598 goto err; 599 600 sc->debug.debugfs_rcstat = debugfs_create_file("rcstat", 601 S_IRUSR, 602 sc->debug.debugfs_phy, 603 sc, &fops_rcstat); 604 if (!sc->debug.debugfs_rcstat) 605 goto err; 606 607 sc->debug.debugfs_wiphy = debugfs_create_file( 608 "wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, 609 &fops_wiphy); 610 if (!sc->debug.debugfs_wiphy) 611 goto err; 612 613 sc->debug.debugfs_xmit = debugfs_create_file("xmit", 614 S_IRUSR, 615 sc->debug.debugfs_phy, 616 sc, &fops_xmit); 617 if (!sc->debug.debugfs_xmit) 618 goto err; 619 620 return 0; 621 err: 622 ath9k_exit_debug(sc); 623 return -ENOMEM; 624 } 625 626 void ath9k_exit_debug(struct ath_softc *sc) 627 { 628 debugfs_remove(sc->debug.debugfs_xmit); 629 debugfs_remove(sc->debug.debugfs_wiphy); 630 debugfs_remove(sc->debug.debugfs_rcstat); 631 debugfs_remove(sc->debug.debugfs_interrupt); 632 debugfs_remove(sc->debug.debugfs_dma); 633 debugfs_remove(sc->debug.debugfs_debug); 634 debugfs_remove(sc->debug.debugfs_phy); 635 } 636 637 int ath9k_debug_create_root(void) 638 { 639 ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); 640 if (!ath9k_debugfs_root) 641 return -ENOENT; 642 643 return 0; 644 } 645 646 void ath9k_debug_remove_root(void) 647 { 648 debugfs_remove(ath9k_debugfs_root); 649 ath9k_debugfs_root = NULL; 650 } 651