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