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 REG_WRITE(ah, AR_MACMISC, 97 ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | 98 (AR_MACMISC_MISC_OBS_BUS_1 << 99 AR_MACMISC_MISC_OBS_BUS_MSB_S))); 100 101 len += snprintf(buf + len, sizeof(buf) - len, 102 "Raw DMA Debug values:\n"); 103 104 for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { 105 if (i % 4 == 0) 106 len += snprintf(buf + len, sizeof(buf) - len, "\n"); 107 108 val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); 109 len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ", 110 i, val[i]); 111 } 112 113 len += snprintf(buf + len, sizeof(buf) - len, "\n\n"); 114 len += snprintf(buf + len, sizeof(buf) - len, 115 "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); 116 117 for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) { 118 if (i == 8) { 119 qcuOffset = 0; 120 qcuBase++; 121 } 122 123 if (i == 6) { 124 dcuOffset = 0; 125 dcuBase++; 126 } 127 128 len += snprintf(buf + len, sizeof(buf) - len, 129 "%2d %2x %1x %2x %2x\n", 130 i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, 131 (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), 132 val[2] & (0x7 << (i * 3)) >> (i * 3), 133 (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); 134 } 135 136 len += snprintf(buf + len, sizeof(buf) - len, "\n"); 137 138 len += snprintf(buf + len, sizeof(buf) - len, 139 "qcu_stitch state: %2x qcu_fetch state: %2x\n", 140 (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); 141 len += snprintf(buf + len, sizeof(buf) - len, 142 "qcu_complete state: %2x dcu_complete state: %2x\n", 143 (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); 144 len += snprintf(buf + len, sizeof(buf) - len, 145 "dcu_arb state: %2x dcu_fp state: %2x\n", 146 (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); 147 len += snprintf(buf + len, sizeof(buf) - len, 148 "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", 149 (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); 150 len += snprintf(buf + len, sizeof(buf) - len, 151 "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", 152 (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); 153 len += snprintf(buf + len, sizeof(buf) - len, 154 "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", 155 (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); 156 157 len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n", 158 REG_READ(ah, AR_OBS_BUS_1)); 159 len += snprintf(buf + len, sizeof(buf) - len, 160 "AR_CR: 0x%x \n", REG_READ(ah, AR_CR)); 161 162 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 163 } 164 165 static const struct file_operations fops_dma = { 166 .read = read_file_dma, 167 .open = ath9k_debugfs_open, 168 .owner = THIS_MODULE 169 }; 170 171 172 void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) 173 { 174 if (status) 175 sc->debug.stats.istats.total++; 176 if (status & ATH9K_INT_RX) 177 sc->debug.stats.istats.rxok++; 178 if (status & ATH9K_INT_RXEOL) 179 sc->debug.stats.istats.rxeol++; 180 if (status & ATH9K_INT_RXORN) 181 sc->debug.stats.istats.rxorn++; 182 if (status & ATH9K_INT_TX) 183 sc->debug.stats.istats.txok++; 184 if (status & ATH9K_INT_TXURN) 185 sc->debug.stats.istats.txurn++; 186 if (status & ATH9K_INT_MIB) 187 sc->debug.stats.istats.mib++; 188 if (status & ATH9K_INT_RXPHY) 189 sc->debug.stats.istats.rxphyerr++; 190 if (status & ATH9K_INT_RXKCM) 191 sc->debug.stats.istats.rx_keycache_miss++; 192 if (status & ATH9K_INT_SWBA) 193 sc->debug.stats.istats.swba++; 194 if (status & ATH9K_INT_BMISS) 195 sc->debug.stats.istats.bmiss++; 196 if (status & ATH9K_INT_BNR) 197 sc->debug.stats.istats.bnr++; 198 if (status & ATH9K_INT_CST) 199 sc->debug.stats.istats.cst++; 200 if (status & ATH9K_INT_GTT) 201 sc->debug.stats.istats.gtt++; 202 if (status & ATH9K_INT_TIM) 203 sc->debug.stats.istats.tim++; 204 if (status & ATH9K_INT_CABEND) 205 sc->debug.stats.istats.cabend++; 206 if (status & ATH9K_INT_DTIMSYNC) 207 sc->debug.stats.istats.dtimsync++; 208 if (status & ATH9K_INT_DTIM) 209 sc->debug.stats.istats.dtim++; 210 } 211 212 static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, 213 size_t count, loff_t *ppos) 214 { 215 struct ath_softc *sc = file->private_data; 216 char buf[512]; 217 unsigned int len = 0; 218 219 len += snprintf(buf + len, sizeof(buf) - len, 220 "%8s: %10u\n", "RX", sc->debug.stats.istats.rxok); 221 len += snprintf(buf + len, sizeof(buf) - len, 222 "%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol); 223 len += snprintf(buf + len, sizeof(buf) - len, 224 "%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn); 225 len += snprintf(buf + len, sizeof(buf) - len, 226 "%8s: %10u\n", "TX", sc->debug.stats.istats.txok); 227 len += snprintf(buf + len, sizeof(buf) - len, 228 "%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn); 229 len += snprintf(buf + len, sizeof(buf) - len, 230 "%8s: %10u\n", "MIB", sc->debug.stats.istats.mib); 231 len += snprintf(buf + len, sizeof(buf) - len, 232 "%8s: %10u\n", "RXPHY", sc->debug.stats.istats.rxphyerr); 233 len += snprintf(buf + len, sizeof(buf) - len, 234 "%8s: %10u\n", "RXKCM", sc->debug.stats.istats.rx_keycache_miss); 235 len += snprintf(buf + len, sizeof(buf) - len, 236 "%8s: %10u\n", "SWBA", sc->debug.stats.istats.swba); 237 len += snprintf(buf + len, sizeof(buf) - len, 238 "%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss); 239 len += snprintf(buf + len, sizeof(buf) - len, 240 "%8s: %10u\n", "BNR", sc->debug.stats.istats.bnr); 241 len += snprintf(buf + len, sizeof(buf) - len, 242 "%8s: %10u\n", "CST", sc->debug.stats.istats.cst); 243 len += snprintf(buf + len, sizeof(buf) - len, 244 "%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt); 245 len += snprintf(buf + len, sizeof(buf) - len, 246 "%8s: %10u\n", "TIM", sc->debug.stats.istats.tim); 247 len += snprintf(buf + len, sizeof(buf) - len, 248 "%8s: %10u\n", "CABEND", sc->debug.stats.istats.cabend); 249 len += snprintf(buf + len, sizeof(buf) - len, 250 "%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync); 251 len += snprintf(buf + len, sizeof(buf) - len, 252 "%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim); 253 len += snprintf(buf + len, sizeof(buf) - len, 254 "%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total); 255 256 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 257 } 258 259 static const struct file_operations fops_interrupt = { 260 .read = read_file_interrupt, 261 .open = ath9k_debugfs_open, 262 .owner = THIS_MODULE 263 }; 264 265 void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) 266 { 267 struct ath_tx_info_priv *tx_info_priv = NULL; 268 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 269 struct ieee80211_tx_rate *rates = tx_info->status.rates; 270 int final_ts_idx, idx; 271 struct ath_rc_stats *stats; 272 273 tx_info_priv = ATH_TX_INFO_PRIV(tx_info); 274 final_ts_idx = tx_info_priv->tx.ts_rateindex; 275 idx = rates[final_ts_idx].idx; 276 stats = &sc->debug.stats.rcstats[idx]; 277 stats->success++; 278 } 279 280 void ath_debug_stat_retries(struct ath_softc *sc, int rix, 281 int xretries, int retries, u8 per) 282 { 283 struct ath_rc_stats *stats = &sc->debug.stats.rcstats[rix]; 284 285 stats->xretries += xretries; 286 stats->retries += retries; 287 stats->per = per; 288 } 289 290 static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, 291 size_t count, loff_t *ppos) 292 { 293 struct ath_softc *sc = file->private_data; 294 char *buf; 295 unsigned int len = 0, max; 296 int i = 0; 297 ssize_t retval; 298 299 if (sc->cur_rate_table == NULL) 300 return 0; 301 302 max = 80 + sc->cur_rate_table->rate_cnt * 64; 303 buf = kmalloc(max + 1, GFP_KERNEL); 304 if (buf == NULL) 305 return 0; 306 buf[max] = 0; 307 308 len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success", 309 "Retries", "XRetries", "PER"); 310 311 for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { 312 u32 ratekbps = sc->cur_rate_table->info[i].ratekbps; 313 struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i]; 314 315 len += snprintf(buf + len, max - len, 316 "%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000, 317 (ratekbps % 1000) / 100, stats->success, 318 stats->retries, stats->xretries, 319 stats->per); 320 } 321 322 retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); 323 kfree(buf); 324 return retval; 325 } 326 327 static const struct file_operations fops_rcstat = { 328 .read = read_file_rcstat, 329 .open = ath9k_debugfs_open, 330 .owner = THIS_MODULE 331 }; 332 333 static const char * ath_wiphy_state_str(enum ath_wiphy_state state) 334 { 335 switch (state) { 336 case ATH_WIPHY_INACTIVE: 337 return "INACTIVE"; 338 case ATH_WIPHY_ACTIVE: 339 return "ACTIVE"; 340 case ATH_WIPHY_PAUSING: 341 return "PAUSING"; 342 case ATH_WIPHY_PAUSED: 343 return "PAUSED"; 344 case ATH_WIPHY_SCAN: 345 return "SCAN"; 346 } 347 return "?"; 348 } 349 350 static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, 351 size_t count, loff_t *ppos) 352 { 353 struct ath_softc *sc = file->private_data; 354 char buf[512]; 355 unsigned int len = 0; 356 int i; 357 u8 addr[ETH_ALEN]; 358 359 len += snprintf(buf + len, sizeof(buf) - len, 360 "primary: %s (%s chan=%d ht=%d)\n", 361 wiphy_name(sc->pri_wiphy->hw->wiphy), 362 ath_wiphy_state_str(sc->pri_wiphy->state), 363 sc->pri_wiphy->chan_idx, sc->pri_wiphy->chan_is_ht); 364 for (i = 0; i < sc->num_sec_wiphy; i++) { 365 struct ath_wiphy *aphy = sc->sec_wiphy[i]; 366 if (aphy == NULL) 367 continue; 368 len += snprintf(buf + len, sizeof(buf) - len, 369 "secondary: %s (%s chan=%d ht=%d)\n", 370 wiphy_name(aphy->hw->wiphy), 371 ath_wiphy_state_str(aphy->state), 372 aphy->chan_idx, aphy->chan_is_ht); 373 } 374 375 put_unaligned_le32(REG_READ(sc->sc_ah, AR_STA_ID0), addr); 376 put_unaligned_le16(REG_READ(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); 377 len += snprintf(buf + len, sizeof(buf) - len, 378 "addr: %pM\n", addr); 379 put_unaligned_le32(REG_READ(sc->sc_ah, AR_BSSMSKL), addr); 380 put_unaligned_le16(REG_READ(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4); 381 len += snprintf(buf + len, sizeof(buf) - len, 382 "addrmask: %pM\n", addr); 383 384 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 385 } 386 387 static struct ath_wiphy * get_wiphy(struct ath_softc *sc, const char *name) 388 { 389 int i; 390 if (strcmp(name, wiphy_name(sc->pri_wiphy->hw->wiphy)) == 0) 391 return sc->pri_wiphy; 392 for (i = 0; i < sc->num_sec_wiphy; i++) { 393 struct ath_wiphy *aphy = sc->sec_wiphy[i]; 394 if (aphy && strcmp(name, wiphy_name(aphy->hw->wiphy)) == 0) 395 return aphy; 396 } 397 return NULL; 398 } 399 400 static int del_wiphy(struct ath_softc *sc, const char *name) 401 { 402 struct ath_wiphy *aphy = get_wiphy(sc, name); 403 if (!aphy) 404 return -ENOENT; 405 return ath9k_wiphy_del(aphy); 406 } 407 408 static int pause_wiphy(struct ath_softc *sc, const char *name) 409 { 410 struct ath_wiphy *aphy = get_wiphy(sc, name); 411 if (!aphy) 412 return -ENOENT; 413 return ath9k_wiphy_pause(aphy); 414 } 415 416 static int unpause_wiphy(struct ath_softc *sc, const char *name) 417 { 418 struct ath_wiphy *aphy = get_wiphy(sc, name); 419 if (!aphy) 420 return -ENOENT; 421 return ath9k_wiphy_unpause(aphy); 422 } 423 424 static int select_wiphy(struct ath_softc *sc, const char *name) 425 { 426 struct ath_wiphy *aphy = get_wiphy(sc, name); 427 if (!aphy) 428 return -ENOENT; 429 return ath9k_wiphy_select(aphy); 430 } 431 432 static int schedule_wiphy(struct ath_softc *sc, const char *msec) 433 { 434 ath9k_wiphy_set_scheduler(sc, simple_strtoul(msec, NULL, 0)); 435 return 0; 436 } 437 438 static ssize_t write_file_wiphy(struct file *file, const char __user *user_buf, 439 size_t count, loff_t *ppos) 440 { 441 struct ath_softc *sc = file->private_data; 442 char buf[50]; 443 size_t len; 444 445 len = min(count, sizeof(buf) - 1); 446 if (copy_from_user(buf, user_buf, len)) 447 return -EFAULT; 448 buf[len] = '\0'; 449 if (len > 0 && buf[len - 1] == '\n') 450 buf[len - 1] = '\0'; 451 452 if (strncmp(buf, "add", 3) == 0) { 453 int res = ath9k_wiphy_add(sc); 454 if (res < 0) 455 return res; 456 } else if (strncmp(buf, "del=", 4) == 0) { 457 int res = del_wiphy(sc, buf + 4); 458 if (res < 0) 459 return res; 460 } else if (strncmp(buf, "pause=", 6) == 0) { 461 int res = pause_wiphy(sc, buf + 6); 462 if (res < 0) 463 return res; 464 } else if (strncmp(buf, "unpause=", 8) == 0) { 465 int res = unpause_wiphy(sc, buf + 8); 466 if (res < 0) 467 return res; 468 } else if (strncmp(buf, "select=", 7) == 0) { 469 int res = select_wiphy(sc, buf + 7); 470 if (res < 0) 471 return res; 472 } else if (strncmp(buf, "schedule=", 9) == 0) { 473 int res = schedule_wiphy(sc, buf + 9); 474 if (res < 0) 475 return res; 476 } else 477 return -EOPNOTSUPP; 478 479 return count; 480 } 481 482 static const struct file_operations fops_wiphy = { 483 .read = read_file_wiphy, 484 .write = write_file_wiphy, 485 .open = ath9k_debugfs_open, 486 .owner = THIS_MODULE 487 }; 488 489 490 int ath9k_init_debug(struct ath_softc *sc) 491 { 492 sc->debug.debug_mask = ath9k_debug; 493 494 if (!ath9k_debugfs_root) 495 return -ENOENT; 496 497 sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy), 498 ath9k_debugfs_root); 499 if (!sc->debug.debugfs_phy) 500 goto err; 501 502 sc->debug.debugfs_debug = debugfs_create_file("debug", 503 S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); 504 if (!sc->debug.debugfs_debug) 505 goto err; 506 507 sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, 508 sc->debug.debugfs_phy, sc, &fops_dma); 509 if (!sc->debug.debugfs_dma) 510 goto err; 511 512 sc->debug.debugfs_interrupt = debugfs_create_file("interrupt", 513 S_IRUGO, 514 sc->debug.debugfs_phy, 515 sc, &fops_interrupt); 516 if (!sc->debug.debugfs_interrupt) 517 goto err; 518 519 sc->debug.debugfs_rcstat = debugfs_create_file("rcstat", 520 S_IRUGO, 521 sc->debug.debugfs_phy, 522 sc, &fops_rcstat); 523 if (!sc->debug.debugfs_rcstat) 524 goto err; 525 526 sc->debug.debugfs_wiphy = debugfs_create_file( 527 "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, 528 &fops_wiphy); 529 if (!sc->debug.debugfs_wiphy) 530 goto err; 531 532 return 0; 533 err: 534 ath9k_exit_debug(sc); 535 return -ENOMEM; 536 } 537 538 void ath9k_exit_debug(struct ath_softc *sc) 539 { 540 debugfs_remove(sc->debug.debugfs_wiphy); 541 debugfs_remove(sc->debug.debugfs_rcstat); 542 debugfs_remove(sc->debug.debugfs_interrupt); 543 debugfs_remove(sc->debug.debugfs_dma); 544 debugfs_remove(sc->debug.debugfs_debug); 545 debugfs_remove(sc->debug.debugfs_phy); 546 } 547 548 int ath9k_debug_create_root(void) 549 { 550 ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); 551 if (!ath9k_debugfs_root) 552 return -ENOENT; 553 554 return 0; 555 } 556 557 void ath9k_debug_remove_root(void) 558 { 559 debugfs_remove(ath9k_debugfs_root); 560 ath9k_debugfs_root = NULL; 561 } 562