debug.c 11.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (c) 2008 Atheros Communications Inc.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

S
Sujith 已提交
17
#include "ath9k.h"
18 19 20 21 22 23 24 25 26

static unsigned int ath9k_debug = DBG_DEFAULT;
module_param_named(debug, ath9k_debug, uint, 0);

void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...)
{
	if (!sc)
		return;

S
Sujith 已提交
27
	if (sc->debug.debug_mask & dbg_mask) {
28 29 30 31 32 33 34 35 36
		va_list args;

		va_start(args, fmt);
		printk(KERN_DEBUG "ath9k: ");
		vprintk(fmt, args);
		va_end(args);
	}
}

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
static int ath9k_debugfs_open(struct inode *inode, struct file *file)
{
	file->private_data = inode->i_private;
	return 0;
}

static ssize_t read_file_dma(struct file *file, char __user *user_buf,
			     size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	struct ath_hal *ah = sc->sc_ah;
	char buf[1024];
	unsigned int len = 0;
	u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
	int i, qcuOffset = 0, dcuOffset = 0;
	u32 *qcuBase = &val[0], *dcuBase = &val[4];

	REG_WRITE(ah, AR_MACMISC,
		  ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
		   (AR_MACMISC_MISC_OBS_BUS_1 <<
		    AR_MACMISC_MISC_OBS_BUS_MSB_S)));

	len += snprintf(buf + len, sizeof(buf) - len,
			"Raw DMA Debug values:\n");

	for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
		if (i % 4 == 0)
			len += snprintf(buf + len, sizeof(buf) - len, "\n");

		val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32)));
		len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ",
				i, val[i]);
	}

	len += snprintf(buf + len, sizeof(buf) - len, "\n\n");
	len += snprintf(buf + len, sizeof(buf) - len,
			"Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");

	for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) {
		if (i == 8) {
			qcuOffset = 0;
			qcuBase++;
		}

		if (i == 6) {
			dcuOffset = 0;
			dcuBase++;
		}

		len += snprintf(buf + len, sizeof(buf) - len,
			"%2d          %2x      %1x     %2x           %2x\n",
			i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
			(*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3),
			val[2] & (0x7 << (i * 3)) >> (i * 3),
			(*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
	}

	len += snprintf(buf + len, sizeof(buf) - len, "\n");

	len += snprintf(buf + len, sizeof(buf) - len,
		"qcu_stitch state:   %2x    qcu_fetch state:        %2x\n",
		(val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
	len += snprintf(buf + len, sizeof(buf) - len,
		"qcu_complete state: %2x    dcu_complete state:     %2x\n",
		(val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
	len += snprintf(buf + len, sizeof(buf) - len,
		"dcu_arb state:      %2x    dcu_fp state:           %2x\n",
		(val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
	len += snprintf(buf + len, sizeof(buf) - len,
		"chan_idle_dur:     %3d    chan_idle_dur_valid:     %1d\n",
		(val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
	len += snprintf(buf + len, sizeof(buf) - len,
		"txfifo_valid_0:      %1d    txfifo_valid_1:          %1d\n",
		(val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
	len += snprintf(buf + len, sizeof(buf) - len,
		"txfifo_dcu_num_0:   %2d    txfifo_dcu_num_1:       %2d\n",
		(val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);

	len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n",
			REG_READ(ah, AR_OBS_BUS_1));
	len += snprintf(buf + len, sizeof(buf) - len,
			"AR_CR: 0x%x \n", REG_READ(ah, AR_CR));

	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static const struct file_operations fops_dma = {
	.read = read_file_dma,
	.open = ath9k_debugfs_open,
	.owner = THIS_MODULE
};

129 130 131 132

void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
{
	if (status)
S
Sujith 已提交
133
		sc->debug.stats.istats.total++;
134
	if (status & ATH9K_INT_RX)
S
Sujith 已提交
135
		sc->debug.stats.istats.rxok++;
136
	if (status & ATH9K_INT_RXEOL)
S
Sujith 已提交
137
		sc->debug.stats.istats.rxeol++;
138
	if (status & ATH9K_INT_RXORN)
S
Sujith 已提交
139
		sc->debug.stats.istats.rxorn++;
140
	if (status & ATH9K_INT_TX)
S
Sujith 已提交
141
		sc->debug.stats.istats.txok++;
142
	if (status & ATH9K_INT_TXURN)
S
Sujith 已提交
143
		sc->debug.stats.istats.txurn++;
144
	if (status & ATH9K_INT_MIB)
S
Sujith 已提交
145
		sc->debug.stats.istats.mib++;
146
	if (status & ATH9K_INT_RXPHY)
S
Sujith 已提交
147
		sc->debug.stats.istats.rxphyerr++;
148
	if (status & ATH9K_INT_RXKCM)
S
Sujith 已提交
149
		sc->debug.stats.istats.rx_keycache_miss++;
150
	if (status & ATH9K_INT_SWBA)
S
Sujith 已提交
151
		sc->debug.stats.istats.swba++;
152
	if (status & ATH9K_INT_BMISS)
S
Sujith 已提交
153
		sc->debug.stats.istats.bmiss++;
154
	if (status & ATH9K_INT_BNR)
S
Sujith 已提交
155
		sc->debug.stats.istats.bnr++;
156
	if (status & ATH9K_INT_CST)
S
Sujith 已提交
157
		sc->debug.stats.istats.cst++;
158
	if (status & ATH9K_INT_GTT)
S
Sujith 已提交
159
		sc->debug.stats.istats.gtt++;
160
	if (status & ATH9K_INT_TIM)
S
Sujith 已提交
161
		sc->debug.stats.istats.tim++;
162
	if (status & ATH9K_INT_CABEND)
S
Sujith 已提交
163
		sc->debug.stats.istats.cabend++;
164
	if (status & ATH9K_INT_DTIMSYNC)
S
Sujith 已提交
165
		sc->debug.stats.istats.dtimsync++;
166
	if (status & ATH9K_INT_DTIM)
S
Sujith 已提交
167
		sc->debug.stats.istats.dtim++;
168 169 170 171 172 173 174 175 176 177
}

static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
				   size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	char buf[512];
	unsigned int len = 0;

	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
178
		"%8s: %10u\n", "RX", sc->debug.stats.istats.rxok);
179
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
180
		"%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol);
181
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
182
		"%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn);
183
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
184
		"%8s: %10u\n", "TX", sc->debug.stats.istats.txok);
185
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
186
		"%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn);
187
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
188
		"%8s: %10u\n", "MIB", sc->debug.stats.istats.mib);
189
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
190
		"%8s: %10u\n", "RXPHY", sc->debug.stats.istats.rxphyerr);
191
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
192
		"%8s: %10u\n", "RXKCM", sc->debug.stats.istats.rx_keycache_miss);
193
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
194
		"%8s: %10u\n", "SWBA", sc->debug.stats.istats.swba);
195
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
196
		"%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss);
197
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
198
		"%8s: %10u\n", "BNR", sc->debug.stats.istats.bnr);
199
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
200
		"%8s: %10u\n", "CST", sc->debug.stats.istats.cst);
201
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
202
		"%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt);
203
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
204
		"%8s: %10u\n", "TIM", sc->debug.stats.istats.tim);
205
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
206
		"%8s: %10u\n", "CABEND", sc->debug.stats.istats.cabend);
207
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
208
		"%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync);
209
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
210
		"%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim);
211
	len += snprintf(buf + len, sizeof(buf) - len,
S
Sujith 已提交
212
		"%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total);
213 214 215 216 217 218 219 220 221 222

	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static const struct file_operations fops_interrupt = {
	.read = read_file_interrupt,
	.open = ath9k_debugfs_open,
	.owner = THIS_MODULE
};

223 224 225 226 227 228 229 230 231 232 233
static void ath_debug_stat_11n_rc(struct ath_softc *sc, struct sk_buff *skb)
{
	struct ath_tx_info_priv *tx_info_priv = NULL;
	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
	struct ieee80211_tx_rate *rates = tx_info->status.rates;
	int final_ts_idx, idx;

	tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
	final_ts_idx = tx_info_priv->tx.ts_rateindex;
	idx = sc->cur_rate_table->info[rates[final_ts_idx].idx].dot11rate;

S
Sujith 已提交
234
	sc->debug.stats.n_rcstats[idx].success++;
235 236 237 238 239 240 241 242 243 244 245 246 247
}

static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb)
{
	struct ath_tx_info_priv *tx_info_priv = NULL;
	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
	struct ieee80211_tx_rate *rates = tx_info->status.rates;
	int final_ts_idx, idx;

	tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
	final_ts_idx = tx_info_priv->tx.ts_rateindex;
	idx = rates[final_ts_idx].idx;

S
Sujith 已提交
248
	sc->debug.stats.legacy_rcstats[idx].success++;
249 250 251 252 253 254 255 256 257 258
}

void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
{
	if (conf_is_ht(&sc->hw->conf))
		ath_debug_stat_11n_rc(sc, skb);
	else
		ath_debug_stat_legacy_rc(sc, skb);
}

259 260 261 262 263 264 265
/* FIXME: legacy rates, later on .. */
void ath_debug_stat_retries(struct ath_softc *sc, int rix,
			    int xretries, int retries)
{
	if (conf_is_ht(&sc->hw->conf)) {
		int idx = sc->cur_rate_table->info[rix].dot11rate;

S
Sujith 已提交
266 267
		sc->debug.stats.n_rcstats[idx].xretries += xretries;
		sc->debug.stats.n_rcstats[idx].retries += retries;
268 269 270
	}
}

271 272 273 274 275
static ssize_t ath_read_file_stat_11n_rc(struct file *file,
					 char __user *user_buf,
					 size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
276
	char buf[1024];
277 278 279
	unsigned int len = 0;
	int i = 0;

280 281
	len += sprintf(buf, "%7s %13s %8s %8s\n\n", "Rate", "Success",
		       "Retries", "XRetries");
282 283 284

	for (i = 0; i <= 15; i++) {
		len += snprintf(buf + len, sizeof(buf) - len,
285
				"%5s%3d: %8u %8u %8u\n", "MCS", i,
S
Sujith 已提交
286 287 288
				sc->debug.stats.n_rcstats[i].success,
				sc->debug.stats.n_rcstats[i].retries,
				sc->debug.stats.n_rcstats[i].xretries);
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
	}

	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static ssize_t ath_read_file_stat_legacy_rc(struct file *file,
					    char __user *user_buf,
					    size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	char buf[512];
	unsigned int len = 0;
	int i = 0;

	len += sprintf(buf, "%7s %13s\n\n", "Rate", "Success");

	for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) {
		len += snprintf(buf + len, sizeof(buf) - len, "%5u: %12u\n",
				sc->cur_rate_table->info[i].ratekbps / 1000,
S
Sujith 已提交
308
				sc->debug.stats.legacy_rcstats[i].success);
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
	}

	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
				size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;

	if (conf_is_ht(&sc->hw->conf))
		return ath_read_file_stat_11n_rc(file, user_buf, count, ppos);
	else
		return ath_read_file_stat_legacy_rc(file, user_buf, count ,ppos);
}

static const struct file_operations fops_rcstat = {
	.read = read_file_rcstat,
	.open = ath9k_debugfs_open,
	.owner = THIS_MODULE
};
330

331
int ath9k_init_debug(struct ath_softc *sc)
332
{
S
Sujith 已提交
333
	sc->debug.debug_mask = ath9k_debug;
334

S
Sujith 已提交
335 336
	sc->debug.debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
	if (!sc->debug.debugfs_root)
337 338
		goto err;

S
Sujith 已提交
339 340 341
	sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
						      sc->debug.debugfs_root);
	if (!sc->debug.debugfs_phy)
342 343
		goto err;

S
Sujith 已提交
344 345 346
	sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
				       sc->debug.debugfs_phy, sc, &fops_dma);
	if (!sc->debug.debugfs_dma)
347 348
		goto err;

S
Sujith 已提交
349
	sc->debug.debugfs_interrupt = debugfs_create_file("interrupt",
350
						     S_IRUGO,
S
Sujith 已提交
351
						     sc->debug.debugfs_phy,
352
						     sc, &fops_interrupt);
S
Sujith 已提交
353
	if (!sc->debug.debugfs_interrupt)
354 355
		goto err;

S
Sujith 已提交
356
	sc->debug.debugfs_rcstat = debugfs_create_file("rcstat",
357
						  S_IRUGO,
S
Sujith 已提交
358
						  sc->debug.debugfs_phy,
359
						  sc, &fops_rcstat);
S
Sujith 已提交
360
	if (!sc->debug.debugfs_rcstat)
361 362
		goto err;

363 364 365 366 367 368 369 370
	return 0;
err:
	ath9k_exit_debug(sc);
	return -ENOMEM;
}

void ath9k_exit_debug(struct ath_softc *sc)
{
S
Sujith 已提交
371 372 373 374 375
	debugfs_remove(sc->debug.debugfs_rcstat);
	debugfs_remove(sc->debug.debugfs_interrupt);
	debugfs_remove(sc->debug.debugfs_dma);
	debugfs_remove(sc->debug.debugfs_phy);
	debugfs_remove(sc->debug.debugfs_root);
376
}