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