1*203c4805SLuis R. Rodriguez /* 2*203c4805SLuis R. Rodriguez * Copyright (c) 2008-2009 Atheros Communications Inc. 3*203c4805SLuis R. Rodriguez * 4*203c4805SLuis R. Rodriguez * Permission to use, copy, modify, and/or distribute this software for any 5*203c4805SLuis R. Rodriguez * purpose with or without fee is hereby granted, provided that the above 6*203c4805SLuis R. Rodriguez * copyright notice and this permission notice appear in all copies. 7*203c4805SLuis R. Rodriguez * 8*203c4805SLuis R. Rodriguez * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9*203c4805SLuis R. Rodriguez * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10*203c4805SLuis R. Rodriguez * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11*203c4805SLuis R. Rodriguez * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12*203c4805SLuis R. Rodriguez * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13*203c4805SLuis R. Rodriguez * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14*203c4805SLuis R. Rodriguez * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15*203c4805SLuis R. Rodriguez */ 16*203c4805SLuis R. Rodriguez 17*203c4805SLuis R. Rodriguez #include <asm/unaligned.h> 18*203c4805SLuis R. Rodriguez 19*203c4805SLuis R. Rodriguez #include "ath9k.h" 20*203c4805SLuis R. Rodriguez 21*203c4805SLuis R. Rodriguez static unsigned int ath9k_debug = DBG_DEFAULT; 22*203c4805SLuis R. Rodriguez module_param_named(debug, ath9k_debug, uint, 0); 23*203c4805SLuis R. Rodriguez 24*203c4805SLuis R. Rodriguez static struct dentry *ath9k_debugfs_root; 25*203c4805SLuis R. Rodriguez 26*203c4805SLuis R. Rodriguez void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) 27*203c4805SLuis R. Rodriguez { 28*203c4805SLuis R. Rodriguez if (!sc) 29*203c4805SLuis R. Rodriguez return; 30*203c4805SLuis R. Rodriguez 31*203c4805SLuis R. Rodriguez if (sc->debug.debug_mask & dbg_mask) { 32*203c4805SLuis R. Rodriguez va_list args; 33*203c4805SLuis R. Rodriguez 34*203c4805SLuis R. Rodriguez va_start(args, fmt); 35*203c4805SLuis R. Rodriguez printk(KERN_DEBUG "ath9k: "); 36*203c4805SLuis R. Rodriguez vprintk(fmt, args); 37*203c4805SLuis R. Rodriguez va_end(args); 38*203c4805SLuis R. Rodriguez } 39*203c4805SLuis R. Rodriguez } 40*203c4805SLuis R. Rodriguez 41*203c4805SLuis R. Rodriguez static int ath9k_debugfs_open(struct inode *inode, struct file *file) 42*203c4805SLuis R. Rodriguez { 43*203c4805SLuis R. Rodriguez file->private_data = inode->i_private; 44*203c4805SLuis R. Rodriguez return 0; 45*203c4805SLuis R. Rodriguez } 46*203c4805SLuis R. Rodriguez 47*203c4805SLuis R. Rodriguez static ssize_t read_file_dma(struct file *file, char __user *user_buf, 48*203c4805SLuis R. Rodriguez size_t count, loff_t *ppos) 49*203c4805SLuis R. Rodriguez { 50*203c4805SLuis R. Rodriguez struct ath_softc *sc = file->private_data; 51*203c4805SLuis R. Rodriguez struct ath_hw *ah = sc->sc_ah; 52*203c4805SLuis R. Rodriguez char buf[1024]; 53*203c4805SLuis R. Rodriguez unsigned int len = 0; 54*203c4805SLuis R. Rodriguez u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; 55*203c4805SLuis R. Rodriguez int i, qcuOffset = 0, dcuOffset = 0; 56*203c4805SLuis R. Rodriguez u32 *qcuBase = &val[0], *dcuBase = &val[4]; 57*203c4805SLuis R. Rodriguez 58*203c4805SLuis R. Rodriguez REG_WRITE(ah, AR_MACMISC, 59*203c4805SLuis R. Rodriguez ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | 60*203c4805SLuis R. Rodriguez (AR_MACMISC_MISC_OBS_BUS_1 << 61*203c4805SLuis R. Rodriguez AR_MACMISC_MISC_OBS_BUS_MSB_S))); 62*203c4805SLuis R. Rodriguez 63*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 64*203c4805SLuis R. Rodriguez "Raw DMA Debug values:\n"); 65*203c4805SLuis R. Rodriguez 66*203c4805SLuis R. Rodriguez for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { 67*203c4805SLuis R. Rodriguez if (i % 4 == 0) 68*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, "\n"); 69*203c4805SLuis R. Rodriguez 70*203c4805SLuis R. Rodriguez val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); 71*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ", 72*203c4805SLuis R. Rodriguez i, val[i]); 73*203c4805SLuis R. Rodriguez } 74*203c4805SLuis R. Rodriguez 75*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, "\n\n"); 76*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 77*203c4805SLuis R. Rodriguez "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); 78*203c4805SLuis R. Rodriguez 79*203c4805SLuis R. Rodriguez for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) { 80*203c4805SLuis R. Rodriguez if (i == 8) { 81*203c4805SLuis R. Rodriguez qcuOffset = 0; 82*203c4805SLuis R. Rodriguez qcuBase++; 83*203c4805SLuis R. Rodriguez } 84*203c4805SLuis R. Rodriguez 85*203c4805SLuis R. Rodriguez if (i == 6) { 86*203c4805SLuis R. Rodriguez dcuOffset = 0; 87*203c4805SLuis R. Rodriguez dcuBase++; 88*203c4805SLuis R. Rodriguez } 89*203c4805SLuis R. Rodriguez 90*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 91*203c4805SLuis R. Rodriguez "%2d %2x %1x %2x %2x\n", 92*203c4805SLuis R. Rodriguez i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, 93*203c4805SLuis R. Rodriguez (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), 94*203c4805SLuis R. Rodriguez val[2] & (0x7 << (i * 3)) >> (i * 3), 95*203c4805SLuis R. Rodriguez (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); 96*203c4805SLuis R. Rodriguez } 97*203c4805SLuis R. Rodriguez 98*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, "\n"); 99*203c4805SLuis R. Rodriguez 100*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 101*203c4805SLuis R. Rodriguez "qcu_stitch state: %2x qcu_fetch state: %2x\n", 102*203c4805SLuis R. Rodriguez (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); 103*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 104*203c4805SLuis R. Rodriguez "qcu_complete state: %2x dcu_complete state: %2x\n", 105*203c4805SLuis R. Rodriguez (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); 106*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 107*203c4805SLuis R. Rodriguez "dcu_arb state: %2x dcu_fp state: %2x\n", 108*203c4805SLuis R. Rodriguez (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); 109*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 110*203c4805SLuis R. Rodriguez "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", 111*203c4805SLuis R. Rodriguez (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); 112*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 113*203c4805SLuis R. Rodriguez "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", 114*203c4805SLuis R. Rodriguez (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); 115*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 116*203c4805SLuis R. Rodriguez "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", 117*203c4805SLuis R. Rodriguez (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); 118*203c4805SLuis R. Rodriguez 119*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n", 120*203c4805SLuis R. Rodriguez REG_READ(ah, AR_OBS_BUS_1)); 121*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 122*203c4805SLuis R. Rodriguez "AR_CR: 0x%x \n", REG_READ(ah, AR_CR)); 123*203c4805SLuis R. Rodriguez 124*203c4805SLuis R. Rodriguez return simple_read_from_buffer(user_buf, count, ppos, buf, len); 125*203c4805SLuis R. Rodriguez } 126*203c4805SLuis R. Rodriguez 127*203c4805SLuis R. Rodriguez static const struct file_operations fops_dma = { 128*203c4805SLuis R. Rodriguez .read = read_file_dma, 129*203c4805SLuis R. Rodriguez .open = ath9k_debugfs_open, 130*203c4805SLuis R. Rodriguez .owner = THIS_MODULE 131*203c4805SLuis R. Rodriguez }; 132*203c4805SLuis R. Rodriguez 133*203c4805SLuis R. Rodriguez 134*203c4805SLuis R. Rodriguez void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) 135*203c4805SLuis R. Rodriguez { 136*203c4805SLuis R. Rodriguez if (status) 137*203c4805SLuis R. Rodriguez sc->debug.stats.istats.total++; 138*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_RX) 139*203c4805SLuis R. Rodriguez sc->debug.stats.istats.rxok++; 140*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_RXEOL) 141*203c4805SLuis R. Rodriguez sc->debug.stats.istats.rxeol++; 142*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_RXORN) 143*203c4805SLuis R. Rodriguez sc->debug.stats.istats.rxorn++; 144*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_TX) 145*203c4805SLuis R. Rodriguez sc->debug.stats.istats.txok++; 146*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_TXURN) 147*203c4805SLuis R. Rodriguez sc->debug.stats.istats.txurn++; 148*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_MIB) 149*203c4805SLuis R. Rodriguez sc->debug.stats.istats.mib++; 150*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_RXPHY) 151*203c4805SLuis R. Rodriguez sc->debug.stats.istats.rxphyerr++; 152*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_RXKCM) 153*203c4805SLuis R. Rodriguez sc->debug.stats.istats.rx_keycache_miss++; 154*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_SWBA) 155*203c4805SLuis R. Rodriguez sc->debug.stats.istats.swba++; 156*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_BMISS) 157*203c4805SLuis R. Rodriguez sc->debug.stats.istats.bmiss++; 158*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_BNR) 159*203c4805SLuis R. Rodriguez sc->debug.stats.istats.bnr++; 160*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_CST) 161*203c4805SLuis R. Rodriguez sc->debug.stats.istats.cst++; 162*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_GTT) 163*203c4805SLuis R. Rodriguez sc->debug.stats.istats.gtt++; 164*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_TIM) 165*203c4805SLuis R. Rodriguez sc->debug.stats.istats.tim++; 166*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_CABEND) 167*203c4805SLuis R. Rodriguez sc->debug.stats.istats.cabend++; 168*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_DTIMSYNC) 169*203c4805SLuis R. Rodriguez sc->debug.stats.istats.dtimsync++; 170*203c4805SLuis R. Rodriguez if (status & ATH9K_INT_DTIM) 171*203c4805SLuis R. Rodriguez sc->debug.stats.istats.dtim++; 172*203c4805SLuis R. Rodriguez } 173*203c4805SLuis R. Rodriguez 174*203c4805SLuis R. Rodriguez static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, 175*203c4805SLuis R. Rodriguez size_t count, loff_t *ppos) 176*203c4805SLuis R. Rodriguez { 177*203c4805SLuis R. Rodriguez struct ath_softc *sc = file->private_data; 178*203c4805SLuis R. Rodriguez char buf[512]; 179*203c4805SLuis R. Rodriguez unsigned int len = 0; 180*203c4805SLuis R. Rodriguez 181*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 182*203c4805SLuis R. Rodriguez "%8s: %10u\n", "RX", sc->debug.stats.istats.rxok); 183*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 184*203c4805SLuis R. Rodriguez "%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol); 185*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 186*203c4805SLuis R. Rodriguez "%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn); 187*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 188*203c4805SLuis R. Rodriguez "%8s: %10u\n", "TX", sc->debug.stats.istats.txok); 189*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 190*203c4805SLuis R. Rodriguez "%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn); 191*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 192*203c4805SLuis R. Rodriguez "%8s: %10u\n", "MIB", sc->debug.stats.istats.mib); 193*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 194*203c4805SLuis R. Rodriguez "%8s: %10u\n", "RXPHY", sc->debug.stats.istats.rxphyerr); 195*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 196*203c4805SLuis R. Rodriguez "%8s: %10u\n", "RXKCM", sc->debug.stats.istats.rx_keycache_miss); 197*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 198*203c4805SLuis R. Rodriguez "%8s: %10u\n", "SWBA", sc->debug.stats.istats.swba); 199*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 200*203c4805SLuis R. Rodriguez "%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss); 201*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 202*203c4805SLuis R. Rodriguez "%8s: %10u\n", "BNR", sc->debug.stats.istats.bnr); 203*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 204*203c4805SLuis R. Rodriguez "%8s: %10u\n", "CST", sc->debug.stats.istats.cst); 205*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 206*203c4805SLuis R. Rodriguez "%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt); 207*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 208*203c4805SLuis R. Rodriguez "%8s: %10u\n", "TIM", sc->debug.stats.istats.tim); 209*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 210*203c4805SLuis R. Rodriguez "%8s: %10u\n", "CABEND", sc->debug.stats.istats.cabend); 211*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 212*203c4805SLuis R. Rodriguez "%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync); 213*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 214*203c4805SLuis R. Rodriguez "%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim); 215*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 216*203c4805SLuis R. Rodriguez "%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total); 217*203c4805SLuis R. Rodriguez 218*203c4805SLuis R. Rodriguez return simple_read_from_buffer(user_buf, count, ppos, buf, len); 219*203c4805SLuis R. Rodriguez } 220*203c4805SLuis R. Rodriguez 221*203c4805SLuis R. Rodriguez static const struct file_operations fops_interrupt = { 222*203c4805SLuis R. Rodriguez .read = read_file_interrupt, 223*203c4805SLuis R. Rodriguez .open = ath9k_debugfs_open, 224*203c4805SLuis R. Rodriguez .owner = THIS_MODULE 225*203c4805SLuis R. Rodriguez }; 226*203c4805SLuis R. Rodriguez 227*203c4805SLuis R. Rodriguez static void ath_debug_stat_11n_rc(struct ath_softc *sc, struct sk_buff *skb) 228*203c4805SLuis R. Rodriguez { 229*203c4805SLuis R. Rodriguez struct ath_tx_info_priv *tx_info_priv = NULL; 230*203c4805SLuis R. Rodriguez struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 231*203c4805SLuis R. Rodriguez struct ieee80211_tx_rate *rates = tx_info->status.rates; 232*203c4805SLuis R. Rodriguez int final_ts_idx, idx; 233*203c4805SLuis R. Rodriguez 234*203c4805SLuis R. Rodriguez tx_info_priv = ATH_TX_INFO_PRIV(tx_info); 235*203c4805SLuis R. Rodriguez final_ts_idx = tx_info_priv->tx.ts_rateindex; 236*203c4805SLuis R. Rodriguez idx = sc->cur_rate_table->info[rates[final_ts_idx].idx].dot11rate; 237*203c4805SLuis R. Rodriguez 238*203c4805SLuis R. Rodriguez sc->debug.stats.n_rcstats[idx].success++; 239*203c4805SLuis R. Rodriguez } 240*203c4805SLuis R. Rodriguez 241*203c4805SLuis R. Rodriguez static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb) 242*203c4805SLuis R. Rodriguez { 243*203c4805SLuis R. Rodriguez struct ath_tx_info_priv *tx_info_priv = NULL; 244*203c4805SLuis R. Rodriguez struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 245*203c4805SLuis R. Rodriguez struct ieee80211_tx_rate *rates = tx_info->status.rates; 246*203c4805SLuis R. Rodriguez int final_ts_idx, idx; 247*203c4805SLuis R. Rodriguez 248*203c4805SLuis R. Rodriguez tx_info_priv = ATH_TX_INFO_PRIV(tx_info); 249*203c4805SLuis R. Rodriguez final_ts_idx = tx_info_priv->tx.ts_rateindex; 250*203c4805SLuis R. Rodriguez idx = rates[final_ts_idx].idx; 251*203c4805SLuis R. Rodriguez 252*203c4805SLuis R. Rodriguez sc->debug.stats.legacy_rcstats[idx].success++; 253*203c4805SLuis R. Rodriguez } 254*203c4805SLuis R. Rodriguez 255*203c4805SLuis R. Rodriguez void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) 256*203c4805SLuis R. Rodriguez { 257*203c4805SLuis R. Rodriguez if (conf_is_ht(&sc->hw->conf)) 258*203c4805SLuis R. Rodriguez ath_debug_stat_11n_rc(sc, skb); 259*203c4805SLuis R. Rodriguez else 260*203c4805SLuis R. Rodriguez ath_debug_stat_legacy_rc(sc, skb); 261*203c4805SLuis R. Rodriguez } 262*203c4805SLuis R. Rodriguez 263*203c4805SLuis R. Rodriguez /* FIXME: legacy rates, later on .. */ 264*203c4805SLuis R. Rodriguez void ath_debug_stat_retries(struct ath_softc *sc, int rix, 265*203c4805SLuis R. Rodriguez int xretries, int retries, u8 per) 266*203c4805SLuis R. Rodriguez { 267*203c4805SLuis R. Rodriguez if (conf_is_ht(&sc->hw->conf)) { 268*203c4805SLuis R. Rodriguez int idx = sc->cur_rate_table->info[rix].dot11rate; 269*203c4805SLuis R. Rodriguez 270*203c4805SLuis R. Rodriguez sc->debug.stats.n_rcstats[idx].xretries += xretries; 271*203c4805SLuis R. Rodriguez sc->debug.stats.n_rcstats[idx].retries += retries; 272*203c4805SLuis R. Rodriguez sc->debug.stats.n_rcstats[idx].per = per; 273*203c4805SLuis R. Rodriguez } 274*203c4805SLuis R. Rodriguez } 275*203c4805SLuis R. Rodriguez 276*203c4805SLuis R. Rodriguez static ssize_t ath_read_file_stat_11n_rc(struct file *file, 277*203c4805SLuis R. Rodriguez char __user *user_buf, 278*203c4805SLuis R. Rodriguez size_t count, loff_t *ppos) 279*203c4805SLuis R. Rodriguez { 280*203c4805SLuis R. Rodriguez struct ath_softc *sc = file->private_data; 281*203c4805SLuis R. Rodriguez char buf[1024]; 282*203c4805SLuis R. Rodriguez unsigned int len = 0; 283*203c4805SLuis R. Rodriguez int i = 0; 284*203c4805SLuis R. Rodriguez 285*203c4805SLuis R. Rodriguez len += sprintf(buf, "%7s %13s %8s %8s %6s\n\n", "Rate", "Success", 286*203c4805SLuis R. Rodriguez "Retries", "XRetries", "PER"); 287*203c4805SLuis R. Rodriguez 288*203c4805SLuis R. Rodriguez for (i = 0; i <= 15; i++) { 289*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 290*203c4805SLuis R. Rodriguez "%5s%3d: %8u %8u %8u %8u\n", "MCS", i, 291*203c4805SLuis R. Rodriguez sc->debug.stats.n_rcstats[i].success, 292*203c4805SLuis R. Rodriguez sc->debug.stats.n_rcstats[i].retries, 293*203c4805SLuis R. Rodriguez sc->debug.stats.n_rcstats[i].xretries, 294*203c4805SLuis R. Rodriguez sc->debug.stats.n_rcstats[i].per); 295*203c4805SLuis R. Rodriguez } 296*203c4805SLuis R. Rodriguez 297*203c4805SLuis R. Rodriguez return simple_read_from_buffer(user_buf, count, ppos, buf, len); 298*203c4805SLuis R. Rodriguez } 299*203c4805SLuis R. Rodriguez 300*203c4805SLuis R. Rodriguez static ssize_t ath_read_file_stat_legacy_rc(struct file *file, 301*203c4805SLuis R. Rodriguez char __user *user_buf, 302*203c4805SLuis R. Rodriguez size_t count, loff_t *ppos) 303*203c4805SLuis R. Rodriguez { 304*203c4805SLuis R. Rodriguez struct ath_softc *sc = file->private_data; 305*203c4805SLuis R. Rodriguez char buf[512]; 306*203c4805SLuis R. Rodriguez unsigned int len = 0; 307*203c4805SLuis R. Rodriguez int i = 0; 308*203c4805SLuis R. Rodriguez 309*203c4805SLuis R. Rodriguez len += sprintf(buf, "%7s %13s\n\n", "Rate", "Success"); 310*203c4805SLuis R. Rodriguez 311*203c4805SLuis R. Rodriguez for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { 312*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, "%5u: %12u\n", 313*203c4805SLuis R. Rodriguez sc->cur_rate_table->info[i].ratekbps / 1000, 314*203c4805SLuis R. Rodriguez sc->debug.stats.legacy_rcstats[i].success); 315*203c4805SLuis R. Rodriguez } 316*203c4805SLuis R. Rodriguez 317*203c4805SLuis R. Rodriguez return simple_read_from_buffer(user_buf, count, ppos, buf, len); 318*203c4805SLuis R. Rodriguez } 319*203c4805SLuis R. Rodriguez 320*203c4805SLuis R. Rodriguez static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, 321*203c4805SLuis R. Rodriguez size_t count, loff_t *ppos) 322*203c4805SLuis R. Rodriguez { 323*203c4805SLuis R. Rodriguez struct ath_softc *sc = file->private_data; 324*203c4805SLuis R. Rodriguez 325*203c4805SLuis R. Rodriguez if (sc->cur_rate_table == NULL) 326*203c4805SLuis R. Rodriguez return 0; 327*203c4805SLuis R. Rodriguez 328*203c4805SLuis R. Rodriguez if (conf_is_ht(&sc->hw->conf)) 329*203c4805SLuis R. Rodriguez return ath_read_file_stat_11n_rc(file, user_buf, count, ppos); 330*203c4805SLuis R. Rodriguez else 331*203c4805SLuis R. Rodriguez return ath_read_file_stat_legacy_rc(file, user_buf, count ,ppos); 332*203c4805SLuis R. Rodriguez } 333*203c4805SLuis R. Rodriguez 334*203c4805SLuis R. Rodriguez static const struct file_operations fops_rcstat = { 335*203c4805SLuis R. Rodriguez .read = read_file_rcstat, 336*203c4805SLuis R. Rodriguez .open = ath9k_debugfs_open, 337*203c4805SLuis R. Rodriguez .owner = THIS_MODULE 338*203c4805SLuis R. Rodriguez }; 339*203c4805SLuis R. Rodriguez 340*203c4805SLuis R. Rodriguez static const char * ath_wiphy_state_str(enum ath_wiphy_state state) 341*203c4805SLuis R. Rodriguez { 342*203c4805SLuis R. Rodriguez switch (state) { 343*203c4805SLuis R. Rodriguez case ATH_WIPHY_INACTIVE: 344*203c4805SLuis R. Rodriguez return "INACTIVE"; 345*203c4805SLuis R. Rodriguez case ATH_WIPHY_ACTIVE: 346*203c4805SLuis R. Rodriguez return "ACTIVE"; 347*203c4805SLuis R. Rodriguez case ATH_WIPHY_PAUSING: 348*203c4805SLuis R. Rodriguez return "PAUSING"; 349*203c4805SLuis R. Rodriguez case ATH_WIPHY_PAUSED: 350*203c4805SLuis R. Rodriguez return "PAUSED"; 351*203c4805SLuis R. Rodriguez case ATH_WIPHY_SCAN: 352*203c4805SLuis R. Rodriguez return "SCAN"; 353*203c4805SLuis R. Rodriguez } 354*203c4805SLuis R. Rodriguez return "?"; 355*203c4805SLuis R. Rodriguez } 356*203c4805SLuis R. Rodriguez 357*203c4805SLuis R. Rodriguez static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, 358*203c4805SLuis R. Rodriguez size_t count, loff_t *ppos) 359*203c4805SLuis R. Rodriguez { 360*203c4805SLuis R. Rodriguez struct ath_softc *sc = file->private_data; 361*203c4805SLuis R. Rodriguez char buf[512]; 362*203c4805SLuis R. Rodriguez unsigned int len = 0; 363*203c4805SLuis R. Rodriguez int i; 364*203c4805SLuis R. Rodriguez u8 addr[ETH_ALEN]; 365*203c4805SLuis R. Rodriguez 366*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 367*203c4805SLuis R. Rodriguez "primary: %s (%s chan=%d ht=%d)\n", 368*203c4805SLuis R. Rodriguez wiphy_name(sc->pri_wiphy->hw->wiphy), 369*203c4805SLuis R. Rodriguez ath_wiphy_state_str(sc->pri_wiphy->state), 370*203c4805SLuis R. Rodriguez sc->pri_wiphy->chan_idx, sc->pri_wiphy->chan_is_ht); 371*203c4805SLuis R. Rodriguez for (i = 0; i < sc->num_sec_wiphy; i++) { 372*203c4805SLuis R. Rodriguez struct ath_wiphy *aphy = sc->sec_wiphy[i]; 373*203c4805SLuis R. Rodriguez if (aphy == NULL) 374*203c4805SLuis R. Rodriguez continue; 375*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 376*203c4805SLuis R. Rodriguez "secondary: %s (%s chan=%d ht=%d)\n", 377*203c4805SLuis R. Rodriguez wiphy_name(aphy->hw->wiphy), 378*203c4805SLuis R. Rodriguez ath_wiphy_state_str(aphy->state), 379*203c4805SLuis R. Rodriguez aphy->chan_idx, aphy->chan_is_ht); 380*203c4805SLuis R. Rodriguez } 381*203c4805SLuis R. Rodriguez 382*203c4805SLuis R. Rodriguez put_unaligned_le32(REG_READ(sc->sc_ah, AR_STA_ID0), addr); 383*203c4805SLuis R. Rodriguez put_unaligned_le16(REG_READ(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); 384*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 385*203c4805SLuis R. Rodriguez "addr: %pM\n", addr); 386*203c4805SLuis R. Rodriguez put_unaligned_le32(REG_READ(sc->sc_ah, AR_BSSMSKL), addr); 387*203c4805SLuis R. Rodriguez put_unaligned_le16(REG_READ(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4); 388*203c4805SLuis R. Rodriguez len += snprintf(buf + len, sizeof(buf) - len, 389*203c4805SLuis R. Rodriguez "addrmask: %pM\n", addr); 390*203c4805SLuis R. Rodriguez 391*203c4805SLuis R. Rodriguez return simple_read_from_buffer(user_buf, count, ppos, buf, len); 392*203c4805SLuis R. Rodriguez } 393*203c4805SLuis R. Rodriguez 394*203c4805SLuis R. Rodriguez static struct ath_wiphy * get_wiphy(struct ath_softc *sc, const char *name) 395*203c4805SLuis R. Rodriguez { 396*203c4805SLuis R. Rodriguez int i; 397*203c4805SLuis R. Rodriguez if (strcmp(name, wiphy_name(sc->pri_wiphy->hw->wiphy)) == 0) 398*203c4805SLuis R. Rodriguez return sc->pri_wiphy; 399*203c4805SLuis R. Rodriguez for (i = 0; i < sc->num_sec_wiphy; i++) { 400*203c4805SLuis R. Rodriguez struct ath_wiphy *aphy = sc->sec_wiphy[i]; 401*203c4805SLuis R. Rodriguez if (aphy && strcmp(name, wiphy_name(aphy->hw->wiphy)) == 0) 402*203c4805SLuis R. Rodriguez return aphy; 403*203c4805SLuis R. Rodriguez } 404*203c4805SLuis R. Rodriguez return NULL; 405*203c4805SLuis R. Rodriguez } 406*203c4805SLuis R. Rodriguez 407*203c4805SLuis R. Rodriguez static int del_wiphy(struct ath_softc *sc, const char *name) 408*203c4805SLuis R. Rodriguez { 409*203c4805SLuis R. Rodriguez struct ath_wiphy *aphy = get_wiphy(sc, name); 410*203c4805SLuis R. Rodriguez if (!aphy) 411*203c4805SLuis R. Rodriguez return -ENOENT; 412*203c4805SLuis R. Rodriguez return ath9k_wiphy_del(aphy); 413*203c4805SLuis R. Rodriguez } 414*203c4805SLuis R. Rodriguez 415*203c4805SLuis R. Rodriguez static int pause_wiphy(struct ath_softc *sc, const char *name) 416*203c4805SLuis R. Rodriguez { 417*203c4805SLuis R. Rodriguez struct ath_wiphy *aphy = get_wiphy(sc, name); 418*203c4805SLuis R. Rodriguez if (!aphy) 419*203c4805SLuis R. Rodriguez return -ENOENT; 420*203c4805SLuis R. Rodriguez return ath9k_wiphy_pause(aphy); 421*203c4805SLuis R. Rodriguez } 422*203c4805SLuis R. Rodriguez 423*203c4805SLuis R. Rodriguez static int unpause_wiphy(struct ath_softc *sc, const char *name) 424*203c4805SLuis R. Rodriguez { 425*203c4805SLuis R. Rodriguez struct ath_wiphy *aphy = get_wiphy(sc, name); 426*203c4805SLuis R. Rodriguez if (!aphy) 427*203c4805SLuis R. Rodriguez return -ENOENT; 428*203c4805SLuis R. Rodriguez return ath9k_wiphy_unpause(aphy); 429*203c4805SLuis R. Rodriguez } 430*203c4805SLuis R. Rodriguez 431*203c4805SLuis R. Rodriguez static int select_wiphy(struct ath_softc *sc, const char *name) 432*203c4805SLuis R. Rodriguez { 433*203c4805SLuis R. Rodriguez struct ath_wiphy *aphy = get_wiphy(sc, name); 434*203c4805SLuis R. Rodriguez if (!aphy) 435*203c4805SLuis R. Rodriguez return -ENOENT; 436*203c4805SLuis R. Rodriguez return ath9k_wiphy_select(aphy); 437*203c4805SLuis R. Rodriguez } 438*203c4805SLuis R. Rodriguez 439*203c4805SLuis R. Rodriguez static int schedule_wiphy(struct ath_softc *sc, const char *msec) 440*203c4805SLuis R. Rodriguez { 441*203c4805SLuis R. Rodriguez ath9k_wiphy_set_scheduler(sc, simple_strtoul(msec, NULL, 0)); 442*203c4805SLuis R. Rodriguez return 0; 443*203c4805SLuis R. Rodriguez } 444*203c4805SLuis R. Rodriguez 445*203c4805SLuis R. Rodriguez static ssize_t write_file_wiphy(struct file *file, const char __user *user_buf, 446*203c4805SLuis R. Rodriguez size_t count, loff_t *ppos) 447*203c4805SLuis R. Rodriguez { 448*203c4805SLuis R. Rodriguez struct ath_softc *sc = file->private_data; 449*203c4805SLuis R. Rodriguez char buf[50]; 450*203c4805SLuis R. Rodriguez size_t len; 451*203c4805SLuis R. Rodriguez 452*203c4805SLuis R. Rodriguez len = min(count, sizeof(buf) - 1); 453*203c4805SLuis R. Rodriguez if (copy_from_user(buf, user_buf, len)) 454*203c4805SLuis R. Rodriguez return -EFAULT; 455*203c4805SLuis R. Rodriguez buf[len] = '\0'; 456*203c4805SLuis R. Rodriguez if (len > 0 && buf[len - 1] == '\n') 457*203c4805SLuis R. Rodriguez buf[len - 1] = '\0'; 458*203c4805SLuis R. Rodriguez 459*203c4805SLuis R. Rodriguez if (strncmp(buf, "add", 3) == 0) { 460*203c4805SLuis R. Rodriguez int res = ath9k_wiphy_add(sc); 461*203c4805SLuis R. Rodriguez if (res < 0) 462*203c4805SLuis R. Rodriguez return res; 463*203c4805SLuis R. Rodriguez } else if (strncmp(buf, "del=", 4) == 0) { 464*203c4805SLuis R. Rodriguez int res = del_wiphy(sc, buf + 4); 465*203c4805SLuis R. Rodriguez if (res < 0) 466*203c4805SLuis R. Rodriguez return res; 467*203c4805SLuis R. Rodriguez } else if (strncmp(buf, "pause=", 6) == 0) { 468*203c4805SLuis R. Rodriguez int res = pause_wiphy(sc, buf + 6); 469*203c4805SLuis R. Rodriguez if (res < 0) 470*203c4805SLuis R. Rodriguez return res; 471*203c4805SLuis R. Rodriguez } else if (strncmp(buf, "unpause=", 8) == 0) { 472*203c4805SLuis R. Rodriguez int res = unpause_wiphy(sc, buf + 8); 473*203c4805SLuis R. Rodriguez if (res < 0) 474*203c4805SLuis R. Rodriguez return res; 475*203c4805SLuis R. Rodriguez } else if (strncmp(buf, "select=", 7) == 0) { 476*203c4805SLuis R. Rodriguez int res = select_wiphy(sc, buf + 7); 477*203c4805SLuis R. Rodriguez if (res < 0) 478*203c4805SLuis R. Rodriguez return res; 479*203c4805SLuis R. Rodriguez } else if (strncmp(buf, "schedule=", 9) == 0) { 480*203c4805SLuis R. Rodriguez int res = schedule_wiphy(sc, buf + 9); 481*203c4805SLuis R. Rodriguez if (res < 0) 482*203c4805SLuis R. Rodriguez return res; 483*203c4805SLuis R. Rodriguez } else 484*203c4805SLuis R. Rodriguez return -EOPNOTSUPP; 485*203c4805SLuis R. Rodriguez 486*203c4805SLuis R. Rodriguez return count; 487*203c4805SLuis R. Rodriguez } 488*203c4805SLuis R. Rodriguez 489*203c4805SLuis R. Rodriguez static const struct file_operations fops_wiphy = { 490*203c4805SLuis R. Rodriguez .read = read_file_wiphy, 491*203c4805SLuis R. Rodriguez .write = write_file_wiphy, 492*203c4805SLuis R. Rodriguez .open = ath9k_debugfs_open, 493*203c4805SLuis R. Rodriguez .owner = THIS_MODULE 494*203c4805SLuis R. Rodriguez }; 495*203c4805SLuis R. Rodriguez 496*203c4805SLuis R. Rodriguez 497*203c4805SLuis R. Rodriguez int ath9k_init_debug(struct ath_softc *sc) 498*203c4805SLuis R. Rodriguez { 499*203c4805SLuis R. Rodriguez sc->debug.debug_mask = ath9k_debug; 500*203c4805SLuis R. Rodriguez 501*203c4805SLuis R. Rodriguez if (!ath9k_debugfs_root) 502*203c4805SLuis R. Rodriguez return -ENOENT; 503*203c4805SLuis R. Rodriguez 504*203c4805SLuis R. Rodriguez sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy), 505*203c4805SLuis R. Rodriguez ath9k_debugfs_root); 506*203c4805SLuis R. Rodriguez if (!sc->debug.debugfs_phy) 507*203c4805SLuis R. Rodriguez goto err; 508*203c4805SLuis R. Rodriguez 509*203c4805SLuis R. Rodriguez sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, 510*203c4805SLuis R. Rodriguez sc->debug.debugfs_phy, sc, &fops_dma); 511*203c4805SLuis R. Rodriguez if (!sc->debug.debugfs_dma) 512*203c4805SLuis R. Rodriguez goto err; 513*203c4805SLuis R. Rodriguez 514*203c4805SLuis R. Rodriguez sc->debug.debugfs_interrupt = debugfs_create_file("interrupt", 515*203c4805SLuis R. Rodriguez S_IRUGO, 516*203c4805SLuis R. Rodriguez sc->debug.debugfs_phy, 517*203c4805SLuis R. Rodriguez sc, &fops_interrupt); 518*203c4805SLuis R. Rodriguez if (!sc->debug.debugfs_interrupt) 519*203c4805SLuis R. Rodriguez goto err; 520*203c4805SLuis R. Rodriguez 521*203c4805SLuis R. Rodriguez sc->debug.debugfs_rcstat = debugfs_create_file("rcstat", 522*203c4805SLuis R. Rodriguez S_IRUGO, 523*203c4805SLuis R. Rodriguez sc->debug.debugfs_phy, 524*203c4805SLuis R. Rodriguez sc, &fops_rcstat); 525*203c4805SLuis R. Rodriguez if (!sc->debug.debugfs_rcstat) 526*203c4805SLuis R. Rodriguez goto err; 527*203c4805SLuis R. Rodriguez 528*203c4805SLuis R. Rodriguez sc->debug.debugfs_wiphy = debugfs_create_file( 529*203c4805SLuis R. Rodriguez "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, 530*203c4805SLuis R. Rodriguez &fops_wiphy); 531*203c4805SLuis R. Rodriguez if (!sc->debug.debugfs_wiphy) 532*203c4805SLuis R. Rodriguez goto err; 533*203c4805SLuis R. Rodriguez 534*203c4805SLuis R. Rodriguez return 0; 535*203c4805SLuis R. Rodriguez err: 536*203c4805SLuis R. Rodriguez ath9k_exit_debug(sc); 537*203c4805SLuis R. Rodriguez return -ENOMEM; 538*203c4805SLuis R. Rodriguez } 539*203c4805SLuis R. Rodriguez 540*203c4805SLuis R. Rodriguez void ath9k_exit_debug(struct ath_softc *sc) 541*203c4805SLuis R. Rodriguez { 542*203c4805SLuis R. Rodriguez debugfs_remove(sc->debug.debugfs_wiphy); 543*203c4805SLuis R. Rodriguez debugfs_remove(sc->debug.debugfs_rcstat); 544*203c4805SLuis R. Rodriguez debugfs_remove(sc->debug.debugfs_interrupt); 545*203c4805SLuis R. Rodriguez debugfs_remove(sc->debug.debugfs_dma); 546*203c4805SLuis R. Rodriguez debugfs_remove(sc->debug.debugfs_phy); 547*203c4805SLuis R. Rodriguez } 548*203c4805SLuis R. Rodriguez 549*203c4805SLuis R. Rodriguez int ath9k_debug_create_root(void) 550*203c4805SLuis R. Rodriguez { 551*203c4805SLuis R. Rodriguez ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); 552*203c4805SLuis R. Rodriguez if (!ath9k_debugfs_root) 553*203c4805SLuis R. Rodriguez return -ENOENT; 554*203c4805SLuis R. Rodriguez 555*203c4805SLuis R. Rodriguez return 0; 556*203c4805SLuis R. Rodriguez } 557*203c4805SLuis R. Rodriguez 558*203c4805SLuis R. Rodriguez void ath9k_debug_remove_root(void) 559*203c4805SLuis R. Rodriguez { 560*203c4805SLuis R. Rodriguez debugfs_remove(ath9k_debugfs_root); 561*203c4805SLuis R. Rodriguez ath9k_debugfs_root = NULL; 562*203c4805SLuis R. Rodriguez } 563