debug.c 31.6 KB
Newer Older
1
/*
2
 * Copyright (c) 2008-2009 Atheros Communications Inc.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 *
 * 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.
 */

17
#include <linux/slab.h>
18
19
#include <asm/unaligned.h>

Sujith's avatar
Sujith committed
20
#include "ath9k.h"
21

22
23
24
25
26
#define REG_WRITE_D(_ah, _reg, _val) \
	ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg))
#define REG_READ_D(_ah, _reg) \
	ath9k_hw_common(_ah)->ops->read((_ah), (_reg))

27
28
29
30
31
32
static int ath9k_debugfs_open(struct inode *inode, struct file *file)
{
	file->private_data = inode->i_private;
	return 0;
}

33
34
#ifdef CONFIG_ATH_DEBUG

35
36
37
38
static ssize_t read_file_debug(struct file *file, char __user *user_buf,
			     size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
39
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
40
	char buf[32];
41
42
	unsigned int len;

43
	len = sprintf(buf, "0x%08x\n", common->debug_mask);
44
45
46
47
48
49
50
	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
			     size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
51
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
52
53
	unsigned long mask;
	char buf[32];
54
55
56
57
	ssize_t len;

	len = min(count, sizeof(buf) - 1);
	if (copy_from_user(buf, user_buf, len))
58
		return -EFAULT;
59
60
61
62
63

	buf[len] = '\0';
	if (strict_strtoul(buf, 0, &mask))
		return -EINVAL;

64
	common->debug_mask = mask;
65
66
67
68
69
70
71
	return count;
}

static const struct file_operations fops_debug = {
	.read = read_file_debug,
	.write = write_file_debug,
	.open = ath9k_debugfs_open,
72
73
	.owner = THIS_MODULE,
	.llseek = default_llseek,
74
75
};

76
77
#endif

78
79
#define DMA_BUF_LEN 1024

80
81
82
83
84
85
86
87
static ssize_t read_file_tx_chainmask(struct file *file, char __user *user_buf,
			     size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
	char buf[32];
	unsigned int len;

88
	len = sprintf(buf, "0x%08x\n", common->tx_chainmask);
89
90
91
92
93
94
95
96
97
98
99
100
101
102
	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static ssize_t write_file_tx_chainmask(struct file *file, const char __user *user_buf,
			     size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
	unsigned long mask;
	char buf[32];
	ssize_t len;

	len = min(count, sizeof(buf) - 1);
	if (copy_from_user(buf, user_buf, len))
103
		return -EFAULT;
104
105
106
107
108
109
110
111
112
113
114
115
116
117

	buf[len] = '\0';
	if (strict_strtoul(buf, 0, &mask))
		return -EINVAL;

	common->tx_chainmask = mask;
	sc->sc_ah->caps.tx_chainmask = mask;
	return count;
}

static const struct file_operations fops_tx_chainmask = {
	.read = read_file_tx_chainmask,
	.write = write_file_tx_chainmask,
	.open = ath9k_debugfs_open,
118
119
	.owner = THIS_MODULE,
	.llseek = default_llseek,
120
121
122
123
124
125
126
127
128
129
130
};


static ssize_t read_file_rx_chainmask(struct file *file, char __user *user_buf,
			     size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
	char buf[32];
	unsigned int len;

131
	len = sprintf(buf, "0x%08x\n", common->rx_chainmask);
132
133
134
135
136
137
138
139
140
141
142
143
144
145
	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static ssize_t write_file_rx_chainmask(struct file *file, const char __user *user_buf,
			     size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
	unsigned long mask;
	char buf[32];
	ssize_t len;

	len = min(count, sizeof(buf) - 1);
	if (copy_from_user(buf, user_buf, len))
146
		return -EFAULT;
147
148
149
150
151
152
153
154
155
156
157
158
159
160

	buf[len] = '\0';
	if (strict_strtoul(buf, 0, &mask))
		return -EINVAL;

	common->rx_chainmask = mask;
	sc->sc_ah->caps.rx_chainmask = mask;
	return count;
}

static const struct file_operations fops_rx_chainmask = {
	.read = read_file_rx_chainmask,
	.write = write_file_rx_chainmask,
	.open = ath9k_debugfs_open,
161
162
	.owner = THIS_MODULE,
	.llseek = default_llseek,
163
164
165
};


166
167
168
169
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;
170
	struct ath_hw *ah = sc->sc_ah;
171
172
	char *buf;
	int retval;
173
174
175
176
177
	unsigned int len = 0;
	u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
	int i, qcuOffset = 0, dcuOffset = 0;
	u32 *qcuBase = &val[0], *dcuBase = &val[4];

178
179
	buf = kmalloc(DMA_BUF_LEN, GFP_KERNEL);
	if (!buf)
180
		return -ENOMEM;
181

182
183
	ath9k_ps_wakeup(sc);

184
	REG_WRITE_D(ah, AR_MACMISC,
185
186
187
188
		  ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
		   (AR_MACMISC_MISC_OBS_BUS_1 <<
		    AR_MACMISC_MISC_OBS_BUS_MSB_S)));

189
	len += snprintf(buf + len, DMA_BUF_LEN - len,
190
191
192
193
			"Raw DMA Debug values:\n");

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

196
		val[i] = REG_READ_D(ah, AR_DMADBG_0 + (i * sizeof(u32)));
197
		len += snprintf(buf + len, DMA_BUF_LEN - len, "%d: %08x ",
198
199
200
				i, val[i]);
	}

201
202
	len += snprintf(buf + len, DMA_BUF_LEN - len, "\n\n");
	len += snprintf(buf + len, DMA_BUF_LEN - len,
203
204
205
206
207
208
209
210
211
212
213
214
215
			"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++;
		}

216
		len += snprintf(buf + len, DMA_BUF_LEN - len,
217
218
219
220
221
222
223
			"%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);
	}

224
	len += snprintf(buf + len, DMA_BUF_LEN - len, "\n");
225

226
	len += snprintf(buf + len, DMA_BUF_LEN - len,
227
228
		"qcu_stitch state:   %2x    qcu_fetch state:        %2x\n",
		(val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
229
	len += snprintf(buf + len, DMA_BUF_LEN - len,
230
231
		"qcu_complete state: %2x    dcu_complete state:     %2x\n",
		(val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
232
	len += snprintf(buf + len, DMA_BUF_LEN - len,
233
234
		"dcu_arb state:      %2x    dcu_fp state:           %2x\n",
		(val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
235
	len += snprintf(buf + len, DMA_BUF_LEN - len,
236
237
		"chan_idle_dur:     %3d    chan_idle_dur_valid:     %1d\n",
		(val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
238
	len += snprintf(buf + len, DMA_BUF_LEN - len,
239
240
		"txfifo_valid_0:      %1d    txfifo_valid_1:          %1d\n",
		(val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
241
	len += snprintf(buf + len, DMA_BUF_LEN - len,
242
243
244
		"txfifo_dcu_num_0:   %2d    txfifo_dcu_num_1:       %2d\n",
		(val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);

245
	len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x\n",
246
			REG_READ_D(ah, AR_OBS_BUS_1));
247
	len += snprintf(buf + len, DMA_BUF_LEN - len,
248
			"AR_CR: 0x%x\n", REG_READ_D(ah, AR_CR));
249

250
251
	ath9k_ps_restore(sc);

252
253
254
	if (len > DMA_BUF_LEN)
		len = DMA_BUF_LEN;

255
256
257
	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
	kfree(buf);
	return retval;
258
259
260
261
262
}

static const struct file_operations fops_dma = {
	.read = read_file_dma,
	.open = ath9k_debugfs_open,
263
264
	.owner = THIS_MODULE,
	.llseek = default_llseek,
265
266
};

267
268
269
270

void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
{
	if (status)
Sujith's avatar
Sujith committed
271
		sc->debug.stats.istats.total++;
272
273
274
275
276
	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
		if (status & ATH9K_INT_RXLP)
			sc->debug.stats.istats.rxlp++;
		if (status & ATH9K_INT_RXHP)
			sc->debug.stats.istats.rxhp++;
277
278
		if (status & ATH9K_INT_BB_WATCHDOG)
			sc->debug.stats.istats.bb_watchdog++;
279
280
281
282
	} else {
		if (status & ATH9K_INT_RX)
			sc->debug.stats.istats.rxok++;
	}
283
	if (status & ATH9K_INT_RXEOL)
Sujith's avatar
Sujith committed
284
		sc->debug.stats.istats.rxeol++;
285
	if (status & ATH9K_INT_RXORN)
Sujith's avatar
Sujith committed
286
		sc->debug.stats.istats.rxorn++;
287
	if (status & ATH9K_INT_TX)
Sujith's avatar
Sujith committed
288
		sc->debug.stats.istats.txok++;
289
	if (status & ATH9K_INT_TXURN)
Sujith's avatar
Sujith committed
290
		sc->debug.stats.istats.txurn++;
291
	if (status & ATH9K_INT_MIB)
Sujith's avatar
Sujith committed
292
		sc->debug.stats.istats.mib++;
293
	if (status & ATH9K_INT_RXPHY)
Sujith's avatar
Sujith committed
294
		sc->debug.stats.istats.rxphyerr++;
295
	if (status & ATH9K_INT_RXKCM)
Sujith's avatar
Sujith committed
296
		sc->debug.stats.istats.rx_keycache_miss++;
297
	if (status & ATH9K_INT_SWBA)
Sujith's avatar
Sujith committed
298
		sc->debug.stats.istats.swba++;
299
	if (status & ATH9K_INT_BMISS)
Sujith's avatar
Sujith committed
300
		sc->debug.stats.istats.bmiss++;
301
	if (status & ATH9K_INT_BNR)
Sujith's avatar
Sujith committed
302
		sc->debug.stats.istats.bnr++;
303
	if (status & ATH9K_INT_CST)
Sujith's avatar
Sujith committed
304
		sc->debug.stats.istats.cst++;
305
	if (status & ATH9K_INT_GTT)
Sujith's avatar
Sujith committed
306
		sc->debug.stats.istats.gtt++;
307
	if (status & ATH9K_INT_TIM)
Sujith's avatar
Sujith committed
308
		sc->debug.stats.istats.tim++;
309
	if (status & ATH9K_INT_CABEND)
Sujith's avatar
Sujith committed
310
		sc->debug.stats.istats.cabend++;
311
	if (status & ATH9K_INT_DTIMSYNC)
Sujith's avatar
Sujith committed
312
		sc->debug.stats.istats.dtimsync++;
313
	if (status & ATH9K_INT_DTIM)
Sujith's avatar
Sujith committed
314
		sc->debug.stats.istats.dtim++;
315
316
317
318
319
320
321
322
323
}

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;

324
325
326
327
328
	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
		len += snprintf(buf + len, sizeof(buf) - len,
			"%8s: %10u\n", "RXLP", sc->debug.stats.istats.rxlp);
		len += snprintf(buf + len, sizeof(buf) - len,
			"%8s: %10u\n", "RXHP", sc->debug.stats.istats.rxhp);
329
330
331
		len += snprintf(buf + len, sizeof(buf) - len,
			"%8s: %10u\n", "WATCHDOG",
			sc->debug.stats.istats.bb_watchdog);
332
333
334
335
	} else {
		len += snprintf(buf + len, sizeof(buf) - len,
			"%8s: %10u\n", "RX", sc->debug.stats.istats.rxok);
	}
336
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
337
		"%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol);
338
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
339
		"%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn);
340
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
341
		"%8s: %10u\n", "TX", sc->debug.stats.istats.txok);
342
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
343
		"%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn);
344
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
345
		"%8s: %10u\n", "MIB", sc->debug.stats.istats.mib);
346
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
347
		"%8s: %10u\n", "RXPHY", sc->debug.stats.istats.rxphyerr);
348
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
349
		"%8s: %10u\n", "RXKCM", sc->debug.stats.istats.rx_keycache_miss);
350
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
351
		"%8s: %10u\n", "SWBA", sc->debug.stats.istats.swba);
352
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
353
		"%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss);
354
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
355
		"%8s: %10u\n", "BNR", sc->debug.stats.istats.bnr);
356
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
357
		"%8s: %10u\n", "CST", sc->debug.stats.istats.cst);
358
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
359
		"%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt);
360
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
361
		"%8s: %10u\n", "TIM", sc->debug.stats.istats.tim);
362
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
363
		"%8s: %10u\n", "CABEND", sc->debug.stats.istats.cabend);
364
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
365
		"%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync);
366
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
367
		"%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim);
368
	len += snprintf(buf + len, sizeof(buf) - len,
Sujith's avatar
Sujith committed
369
		"%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total);
370

371
372
373
	if (len > sizeof(buf))
		len = sizeof(buf);

374
375
376
377
378
379
	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,
380
381
	.owner = THIS_MODULE,
	.llseek = default_llseek,
382
383
};

384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
static const char * ath_wiphy_state_str(enum ath_wiphy_state state)
{
	switch (state) {
	case ATH_WIPHY_INACTIVE:
		return "INACTIVE";
	case ATH_WIPHY_ACTIVE:
		return "ACTIVE";
	case ATH_WIPHY_PAUSING:
		return "PAUSING";
	case ATH_WIPHY_PAUSED:
		return "PAUSED";
	case ATH_WIPHY_SCAN:
		return "SCAN";
	}
	return "?";
}

static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
			       size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
405
406
	struct ath_wiphy *aphy = sc->pri_wiphy;
	struct ieee80211_channel *chan = aphy->hw->conf.channel;
407
408
409
410
	char buf[512];
	unsigned int len = 0;
	int i;
	u8 addr[ETH_ALEN];
Ben Greear's avatar
Ben Greear committed
411
	u32 tmp;
412
413
414
415
416

	len += snprintf(buf + len, sizeof(buf) - len,
			"primary: %s (%s chan=%d ht=%d)\n",
			wiphy_name(sc->pri_wiphy->hw->wiphy),
			ath_wiphy_state_str(sc->pri_wiphy->state),
417
418
			ieee80211_frequency_to_channel(chan->center_freq),
			aphy->chan_is_ht);
419

420
421
	put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
	put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
422
423
	len += snprintf(buf + len, sizeof(buf) - len,
			"addr: %pM\n", addr);
424
425
	put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_BSSMSKL), addr);
	put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
426
427
	len += snprintf(buf + len, sizeof(buf) - len,
			"addrmask: %pM\n", addr);
Ben Greear's avatar
Ben Greear committed
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
	tmp = ath9k_hw_getrxfilter(sc->sc_ah);
	len += snprintf(buf + len, sizeof(buf) - len,
			"rfilt: 0x%x", tmp);
	if (tmp & ATH9K_RX_FILTER_UCAST)
		len += snprintf(buf + len, sizeof(buf) - len, " UCAST");
	if (tmp & ATH9K_RX_FILTER_MCAST)
		len += snprintf(buf + len, sizeof(buf) - len, " MCAST");
	if (tmp & ATH9K_RX_FILTER_BCAST)
		len += snprintf(buf + len, sizeof(buf) - len, " BCAST");
	if (tmp & ATH9K_RX_FILTER_CONTROL)
		len += snprintf(buf + len, sizeof(buf) - len, " CONTROL");
	if (tmp & ATH9K_RX_FILTER_BEACON)
		len += snprintf(buf + len, sizeof(buf) - len, " BEACON");
	if (tmp & ATH9K_RX_FILTER_PROM)
		len += snprintf(buf + len, sizeof(buf) - len, " PROM");
	if (tmp & ATH9K_RX_FILTER_PROBEREQ)
		len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
	if (tmp & ATH9K_RX_FILTER_PHYERR)
		len += snprintf(buf + len, sizeof(buf) - len, " PHYERR");
	if (tmp & ATH9K_RX_FILTER_MYBEACON)
		len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON");
	if (tmp & ATH9K_RX_FILTER_COMP_BAR)
		len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR");
	if (tmp & ATH9K_RX_FILTER_PSPOLL)
		len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL");
	if (tmp & ATH9K_RX_FILTER_PHYRADAR)
		len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR");
	if (tmp & ATH9K_RX_FILTER_MCAST_BCAST_ALL)
		len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL\n");
	else
		len += snprintf(buf + len, sizeof(buf) - len, "\n");

	/* Put variable-length stuff down here, and check for overflows. */
461
	for (i = 0; i < sc->num_sec_wiphy; i++) {
462
463
		struct ath_wiphy *aphy_tmp = sc->sec_wiphy[i];
		if (aphy_tmp == NULL)
464
			continue;
465
		chan = aphy_tmp->hw->conf.channel;
466
		len += snprintf(buf + len, sizeof(buf) - len,
467
			"secondary: %s (%s chan=%d ht=%d)\n",
468
469
			wiphy_name(aphy_tmp->hw->wiphy),
			ath_wiphy_state_str(aphy_tmp->state),
470
			ieee80211_frequency_to_channel(chan->center_freq),
471
						       aphy_tmp->chan_is_ht);
472
	}
473
474
475
	if (len > sizeof(buf))
		len = sizeof(buf);

476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static struct ath_wiphy * get_wiphy(struct ath_softc *sc, const char *name)
{
	int i;
	if (strcmp(name, wiphy_name(sc->pri_wiphy->hw->wiphy)) == 0)
		return sc->pri_wiphy;
	for (i = 0; i < sc->num_sec_wiphy; i++) {
		struct ath_wiphy *aphy = sc->sec_wiphy[i];
		if (aphy && strcmp(name, wiphy_name(aphy->hw->wiphy)) == 0)
			return aphy;
	}
	return NULL;
}

static int del_wiphy(struct ath_softc *sc, const char *name)
{
	struct ath_wiphy *aphy = get_wiphy(sc, name);
	if (!aphy)
		return -ENOENT;
	return ath9k_wiphy_del(aphy);
}

static int pause_wiphy(struct ath_softc *sc, const char *name)
{
	struct ath_wiphy *aphy = get_wiphy(sc, name);
	if (!aphy)
		return -ENOENT;
	return ath9k_wiphy_pause(aphy);
}

static int unpause_wiphy(struct ath_softc *sc, const char *name)
{
	struct ath_wiphy *aphy = get_wiphy(sc, name);
	if (!aphy)
		return -ENOENT;
	return ath9k_wiphy_unpause(aphy);
}

static int select_wiphy(struct ath_softc *sc, const char *name)
{
	struct ath_wiphy *aphy = get_wiphy(sc, name);
	if (!aphy)
		return -ENOENT;
	return ath9k_wiphy_select(aphy);
}

static int schedule_wiphy(struct ath_softc *sc, const char *msec)
{
	ath9k_wiphy_set_scheduler(sc, simple_strtoul(msec, NULL, 0));
	return 0;
}

static ssize_t write_file_wiphy(struct file *file, const char __user *user_buf,
				size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	char buf[50];
	size_t len;

	len = min(count, sizeof(buf) - 1);
	if (copy_from_user(buf, user_buf, len))
		return -EFAULT;
	buf[len] = '\0';
	if (len > 0 && buf[len - 1] == '\n')
		buf[len - 1] = '\0';

	if (strncmp(buf, "add", 3) == 0) {
		int res = ath9k_wiphy_add(sc);
		if (res < 0)
			return res;
	} else if (strncmp(buf, "del=", 4) == 0) {
		int res = del_wiphy(sc, buf + 4);
		if (res < 0)
			return res;
	} else if (strncmp(buf, "pause=", 6) == 0) {
		int res = pause_wiphy(sc, buf + 6);
		if (res < 0)
			return res;
	} else if (strncmp(buf, "unpause=", 8) == 0) {
		int res = unpause_wiphy(sc, buf + 8);
		if (res < 0)
			return res;
	} else if (strncmp(buf, "select=", 7) == 0) {
		int res = select_wiphy(sc, buf + 7);
		if (res < 0)
			return res;
	} else if (strncmp(buf, "schedule=", 9) == 0) {
		int res = schedule_wiphy(sc, buf + 9);
		if (res < 0)
			return res;
	} else
		return -EOPNOTSUPP;

	return count;
}

static const struct file_operations fops_wiphy = {
	.read = read_file_wiphy,
	.write = write_file_wiphy,
	.open = ath9k_debugfs_open,
578
579
	.owner = THIS_MODULE,
	.llseek = default_llseek,
580
581
};

Sujith's avatar
Sujith committed
582
583
584
585
#define PR(str, elem)							\
	do {								\
		len += snprintf(buf + len, size - len,			\
				"%s%13u%11u%10u%10u\n", str,		\
586
587
588
589
		sc->debug.stats.txstats[WME_AC_BE].elem, \
		sc->debug.stats.txstats[WME_AC_BK].elem, \
		sc->debug.stats.txstats[WME_AC_VI].elem, \
		sc->debug.stats.txstats[WME_AC_VO].elem); \
590
591
		if (len >= size)			  \
			goto done;			  \
Sujith's avatar
Sujith committed
592
593
} while(0)

594
595
596
597
598
599
600
601
#define PRX(str, elem)							\
do {									\
	len += snprintf(buf + len, size - len,				\
			"%s%13u%11u%10u%10u\n", str,			\
			(unsigned int)(sc->tx.txq[WME_AC_BE].elem),	\
			(unsigned int)(sc->tx.txq[WME_AC_BK].elem),	\
			(unsigned int)(sc->tx.txq[WME_AC_VI].elem),	\
			(unsigned int)(sc->tx.txq[WME_AC_VO].elem));	\
602
603
	if (len >= size)						\
		goto done;						\
604
605
} while(0)

606
607
608
609
610
611
612
613
#define PRQLE(str, elem)						\
do {									\
	len += snprintf(buf + len, size - len,				\
			"%s%13i%11i%10i%10i\n", str,			\
			list_empty(&sc->tx.txq[WME_AC_BE].elem),	\
			list_empty(&sc->tx.txq[WME_AC_BK].elem),	\
			list_empty(&sc->tx.txq[WME_AC_VI].elem),	\
			list_empty(&sc->tx.txq[WME_AC_VO].elem));	\
614
615
	if (len >= size)						\
		goto done;						\
616
617
} while (0)

Sujith's avatar
Sujith committed
618
619
620
621
622
static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
			      size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	char *buf;
623
	unsigned int len = 0, size = 8000;
624
	int i;
Sujith's avatar
Sujith committed
625
	ssize_t retval = 0;
626
	char tmp[32];
Sujith's avatar
Sujith committed
627
628
629

	buf = kzalloc(size, GFP_KERNEL);
	if (buf == NULL)
630
		return -ENOMEM;
Sujith's avatar
Sujith committed
631

632
633
634
635
	len += sprintf(buf, "Num-Tx-Queues: %i  tx-queues-setup: 0x%x\n"
		       "%30s %10s%10s%10s\n\n",
		       ATH9K_NUM_TX_QUEUES, sc->tx.txqsetup,
		       "BE", "BK", "VI", "VO");
Sujith's avatar
Sujith committed
636
637
638
639

	PR("MPDUs Queued:    ", queued);
	PR("MPDUs Completed: ", completed);
	PR("Aggregates:      ", a_aggr);
640
641
	PR("AMPDUs Queued HW:", a_queued_hw);
	PR("AMPDUs Queued SW:", a_queued_sw);
Sujith's avatar
Sujith committed
642
643
644
645
646
647
648
649
650
	PR("AMPDUs Completed:", a_completed);
	PR("AMPDUs Retried:  ", a_retries);
	PR("AMPDUs XRetried: ", a_xretries);
	PR("FIFO Underrun:   ", fifo_underrun);
	PR("TXOP Exceeded:   ", xtxop);
	PR("TXTIMER Expiry:  ", timer_exp);
	PR("DESC CFG Error:  ", desc_cfg_err);
	PR("DATA Underrun:   ", data_underrun);
	PR("DELIM Underrun:  ", delim_underrun);
651
652
	PR("TX-Pkts-All:     ", tx_pkts_all);
	PR("TX-Bytes-All:    ", tx_bytes_all);
653
654
655
	PR("hw-put-tx-buf:   ", puttxbuf);
	PR("hw-tx-start:     ", txstart);
	PR("hw-tx-proc-desc: ", txprocdesc);
656
657
658
659
660
661
662
663
	len += snprintf(buf + len, size - len,
			"%s%11p%11p%10p%10p\n", "txq-memory-address:",
			&(sc->tx.txq[WME_AC_BE]),
			&(sc->tx.txq[WME_AC_BK]),
			&(sc->tx.txq[WME_AC_VI]),
			&(sc->tx.txq[WME_AC_VO]));
	if (len >= size)
		goto done;
Sujith's avatar
Sujith committed
664

665
666
	PRX("axq-qnum:        ", axq_qnum);
	PRX("axq-depth:       ", axq_depth);
667
	PRX("axq-ampdu_depth: ", axq_ampdu_depth);
668
669
670
	PRX("axq-stopped      ", stopped);
	PRX("tx-in-progress   ", axq_tx_inprogress);
	PRX("pending-frames   ", pending_frames);
671
672
673
674
675
676
677
678
679
680
	PRX("txq_headidx:     ", txq_headidx);
	PRX("txq_tailidx:     ", txq_headidx);

	PRQLE("axq_q empty:       ", axq_q);
	PRQLE("axq_acq empty:     ", axq_acq);
	PRQLE("txq_fifo_pending:  ", txq_fifo_pending);
	for (i = 0; i < ATH_TXFIFO_DEPTH; i++) {
		snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i);
		PRQLE(tmp, txq_fifo[i]);
	}
681

682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
	/* Print out more detailed queue-info */
	for (i = 0; i <= WME_AC_BK; i++) {
		struct ath_txq *txq = &(sc->tx.txq[i]);
		struct ath_atx_ac *ac;
		struct ath_atx_tid *tid;
		if (len >= size)
			goto done;
		spin_lock_bh(&txq->axq_lock);
		if (!list_empty(&txq->axq_acq)) {
			ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac,
					      list);
			len += snprintf(buf + len, size - len,
					"txq[%i] first-ac: %p sched: %i\n",
					i, ac, ac->sched);
			if (list_empty(&ac->tid_q) || (len >= size))
				goto done_for;
			tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
					       list);
			len += snprintf(buf + len, size - len,
					" first-tid: %p sched: %i paused: %i\n",
					tid, tid->sched, tid->paused);
		}
	done_for:
		spin_unlock_bh(&txq->axq_lock);
	}

708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
done:
	if (len > size)
		len = size;

	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
	kfree(buf);

	return retval;
}

static ssize_t read_file_stations(struct file *file, char __user *user_buf,
				  size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	char *buf;
	unsigned int len = 0, size = 64000;
	struct ath_node *an = NULL;
	ssize_t retval = 0;
	int q;

	buf = kzalloc(size, GFP_KERNEL);
	if (buf == NULL)
		return -ENOMEM;

	len += snprintf(buf + len, size - len,
			"Stations:\n"
			" tid: addr sched paused buf_q-empty an ac\n"
			" ac: addr sched tid_q-empty txq\n");

	spin_lock(&sc->nodes_lock);
	list_for_each_entry(an, &sc->nodes, list) {
		len += snprintf(buf + len, size - len,
				"%pM\n", an->sta->addr);
		if (len >= size)
			goto done;

		for (q = 0; q < WME_NUM_TID; q++) {
			struct ath_atx_tid *tid = &(an->tid[q]);
			len += snprintf(buf + len, size - len,
					" tid: %p %s %s %i %p %p\n",
					tid, tid->sched ? "sched" : "idle",
					tid->paused ? "paused" : "running",
					list_empty(&tid->buf_q),
					tid->an, tid->ac);
			if (len >= size)
				goto done;
		}

		for (q = 0; q < WME_NUM_AC; q++) {
			struct ath_atx_ac *ac = &(an->ac[q]);
			len += snprintf(buf + len, size - len,
					" ac: %p %s %i %p\n",
					ac, ac->sched ? "sched" : "idle",
					list_empty(&ac->tid_q), ac->txq);
			if (len >= size)
				goto done;
		}
	}

done:
	spin_unlock(&sc->nodes_lock);
769
770
771
	if (len > size)
		len = size;

Sujith's avatar
Sujith committed
772
773
774
775
776
777
	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
	kfree(buf);

	return retval;
}

778
779
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
		       struct ath_tx_status *ts)
Sujith's avatar
Sujith committed
780
{
781
782
783
784
	int qnum = skb_get_queue_mapping(bf->bf_mpdu);

	TX_STAT_INC(qnum, tx_pkts_all);
	sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len;
785

Sujith's avatar
Sujith committed
786
787
	if (bf_isampdu(bf)) {
		if (bf_isxretried(bf))
788
			TX_STAT_INC(qnum, a_xretries);
Sujith's avatar
Sujith committed
789
		else
790
			TX_STAT_INC(qnum, a_completed);
Sujith's avatar
Sujith committed
791
	} else {
792
		TX_STAT_INC(qnum, completed);
Sujith's avatar
Sujith committed
793
794
	}

795
	if (ts->ts_status & ATH9K_TXERR_FIFO)
796
		TX_STAT_INC(qnum, fifo_underrun);
797
	if (ts->ts_status & ATH9K_TXERR_XTXOP)
798
		TX_STAT_INC(qnum, xtxop);
799
	if (ts->ts_status & ATH9K_TXERR_TIMER_EXPIRED)
800
		TX_STAT_INC(qnum, timer_exp);
801
	if (ts->ts_flags & ATH9K_TX_DESC_CFG_ERR)
802
		TX_STAT_INC(qnum, desc_cfg_err);
803
	if (ts->ts_flags & ATH9K_TX_DATA_UNDERRUN)
804
		TX_STAT_INC(qnum, data_underrun);
805
	if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN)
806
		TX_STAT_INC(qnum, delim_underrun);
Sujith's avatar
Sujith committed
807
808
809
810
811
}

static const struct file_operations fops_xmit = {
	.read = read_file_xmit,
	.open = ath9k_debugfs_open,
812
813
	.owner = THIS_MODULE,
	.llseek = default_llseek,
Sujith's avatar
Sujith committed
814
};
815

816
817
818
819
820
821
822
static const struct file_operations fops_stations = {
	.read = read_file_stations,
	.open = ath9k_debugfs_open,
	.owner = THIS_MODULE,
	.llseek = default_llseek,
};

Sujith's avatar
Sujith committed
823
824
825
826
827
828
829
830
831
832
833
834
835
836
static ssize_t read_file_recv(struct file *file, char __user *user_buf,
			      size_t count, loff_t *ppos)
{
#define PHY_ERR(s, p) \
	len += snprintf(buf + len, size - len, "%18s : %10u\n", s, \
			sc->debug.stats.rxstats.phy_err_stats[p]);

	struct ath_softc *sc = file->private_data;
	char *buf;
	unsigned int len = 0, size = 1152;
	ssize_t retval = 0;

	buf = kzalloc(size, GFP_KERNEL);
	if (buf == NULL)
837
		return -ENOMEM;
Sujith's avatar
Sujith committed
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887

	len += snprintf(buf + len, size - len,
			"%18s : %10u\n", "CRC ERR",
			sc->debug.stats.rxstats.crc_err);
	len += snprintf(buf + len, size - len,
			"%18s : %10u\n", "DECRYPT CRC ERR",
			sc->debug.stats.rxstats.decrypt_crc_err);
	len += snprintf(buf + len, size - len,
			"%18s : %10u\n", "PHY ERR",
			sc->debug.stats.rxstats.phy_err);
	len += snprintf(buf + len, size - len,
			"%18s : %10u\n", "MIC ERR",
			sc->debug.stats.rxstats.mic_err);
	len += snprintf(buf + len, size - len,
			"%18s : %10u\n", "PRE-DELIM CRC ERR",
			sc->debug.stats.rxstats.pre_delim_crc_err);
	len += snprintf(buf + len, size - len,
			"%18s : %10u\n", "POST-DELIM CRC ERR",
			sc->debug.stats.rxstats.post_delim_crc_err);
	len += snprintf(buf + len, size - len,
			"%18s : %10u\n", "DECRYPT BUSY ERR",
			sc->debug.stats.rxstats.decrypt_busy_err);

	PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
	PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
	PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
	PHY_ERR("RATE", ATH9K_PHYERR_RATE);
	PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH);
	PHY_ERR("RADAR", ATH9K_PHYERR_RADAR);
	PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE);
	PHY_ERR("TOR", ATH9K_PHYERR_TOR);
	PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING);
	PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
	PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
	PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
	PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP);
	PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE);
	PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART);
	PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT);
	PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING);
	PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC);
	PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
	PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE);
	PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART);
	PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
	PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP);
	PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR);
	PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
	PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);

888
889
890
891
892
893
894
	len += snprintf(buf + len, size - len,
			"%18s : %10u\n", "RX-Pkts-All",
			sc->debug.stats.rxstats.rx_pkts_all);
	len += snprintf(buf + len, size - len,
			"%18s : %10u\n", "RX-Bytes-All",
			sc->debug.stats.rxstats.rx_bytes_all);

895
896
897
	if (len > size)
		len = size;

Sujith's avatar
Sujith committed
898
899
900
901
902
903
904
905
	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
	kfree(buf);

	return retval;

#undef PHY_ERR
}

906
void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
Sujith's avatar
Sujith committed
907
908
909
910
911
912
{
#define RX_STAT_INC(c) sc->debug.stats.rxstats.c++
#define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++

	u32 phyerr;

913
914
915
	RX_STAT_INC(rx_pkts_all);
	sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen;

916
	if (rs->rs_status & ATH9K_RXERR_CRC)
Sujith's avatar
Sujith committed
917
		RX_STAT_INC(crc_err);
918
	if (rs->rs_status & ATH9K_RXERR_DECRYPT)
Sujith's avatar
Sujith committed
919
		RX_STAT_INC(decrypt_crc_err);
920
	if (rs->rs_status & ATH9K_RXERR_MIC)
Sujith's avatar
Sujith committed
921
		RX_STAT_INC(mic_err);
922
	if (rs->rs_status & ATH9K_RX_DELIM_CRC_PRE)
Sujith's avatar
Sujith committed
923
		RX_STAT_INC(pre_delim_crc_err);
924
	if (rs->rs_status & ATH9K_RX_DELIM_CRC_POST)
Sujith's avatar
Sujith committed
925
		RX_STAT_INC(post_delim_crc_err);
926
	if (rs->rs_status & ATH9K_RX_DECRYPT_BUSY)
Sujith's avatar
Sujith committed
927
928
		RX_STAT_INC(decrypt_busy_err);

929
	if (rs->rs_status & ATH9K_RXERR_PHY) {
Sujith's avatar
Sujith committed
930
		RX_STAT_INC(phy_err);
931
		phyerr = rs->rs_phyerr & 0x24;
Sujith's avatar
Sujith committed
932
933
934
935
936
937
938
939
940
941
		RX_PHY_ERR_INC(phyerr);
	}

#undef RX_STAT_INC
#undef RX_PHY_ERR_INC
}

static const struct file_operations fops_recv = {
	.read = read_file_recv,
	.open = ath9k_debugfs_open,
942
943
	.owner = THIS_MODULE,
	.llseek = default_llseek,
Sujith's avatar
Sujith committed
944
945
};

946
947
948
949
950
951
952
static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
                                size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	char buf[32];
	unsigned int len;

953
	len = sprintf(buf, "0x%08x\n", sc->debug.regidx);
954
955
956
957
958
959
960
961
962
963
964
965
966
	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static ssize_t write_file_regidx(struct file *file, const char __user *user_buf,
			     size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	unsigned long regidx;
	char buf[32];
	ssize_t len;

	len = min(count, sizeof(buf) - 1);
	if (copy_from_user(buf, user_buf, len))
967
		return -EFAULT;
968
969
970
971
972
973
974
975
976
977
978
979
980

	buf[len] = '\0';
	if (strict_strtoul(buf, 0, &regidx))
		return -EINVAL;

	sc->debug.regidx = regidx;
	return count;
}

static const struct file_operations fops_regidx = {
	.read = read_file_regidx,
	.write = write_file_regidx,
	.open = ath9k_debugfs_open,
981
982
	.owner = THIS_MODULE,
	.llseek = default_llseek,
983
984
985
986
987
988
989
990
991
992
993
994
};

static ssize_t read_file_regval(struct file *file, char __user *user_buf,
			     size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	struct ath_hw *ah = sc->sc_ah;
	char buf[32];
	unsigned int len;
	u32 regval;

	regval = REG_READ_D(ah, sc->debug.regidx);
995
	len = sprintf(buf, "0x%08x\n", regval);
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static ssize_t write_file_regval(struct file *file, const char __user *user_buf,
			     size_t count, loff_t *ppos)
{
	struct ath_softc *sc = file->private_data;
	struct ath_hw *ah = sc->sc_ah;
	unsigned long regval;
	char buf[32];
	ssize_t len;

	len = min(count, sizeof(buf) - 1);
	if (copy_from_user(buf, user_buf, len))
1010
		return -EFAULT;
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023

	buf[len] = '\0';
	if (strict_strtoul(buf, 0, &regval))
		return -EINVAL;

	REG_WRITE_D(ah, sc->debug.regidx, regval);
	return count;
}

static const struct file_operations fops_regval = {
	.read = read_file_regval,
	.write = write_file_regval,
	.open = ath9k_debugfs_open,
1024
1025
	.owner = THIS_MODULE,
	.llseek = default_llseek,
1026
1027
};

1028
int ath9k_init_debug(struct ath_hw *ah)
1029
{
1030
1031
	struct ath_common *common = ath9k_hw_common(ah);
	struct ath_softc *sc = (struct ath_softc *) common->priv;
1032

1033
1034
	sc->debug.debugfs_phy = debugfs_create_dir("ath9k",
						   sc->hw->wiphy->debugfsdir);
Sujith's avatar
Sujith committed
1035
	if (!sc->debug.debugfs_phy)
1036
		return -ENOMEM;
1037

1038
#ifdef CONFIG_ATH_DEBUG
1039
1040
	if (!debugfs_create_file("debug", S_IRUSR | S_IWUSR,
			sc->debug.debugfs_phy, sc, &fops_debug))
1041
		goto err;
1042
#endif
1043

1044
1045
	if (!debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy,
			sc, &fops_dma))
1046
1047
		goto err;

1048
1049
	if (!debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy,
			sc, &fops_interrupt))
1050
1051
		goto err;

1052
1053
	if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR,
			sc->debug.debugfs_phy, sc, &fops_wiphy))
1054
1055
		goto err;

1056
1057
	if (!debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy,
			sc, &fops_xmit))
1058
1059
		goto err;

1060
1061
1062
1063
	if (!debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy,
			sc, &fops_stations))
		goto err;

1064
1065
	if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy,
			sc, &fops_recv))
1066
1067
		goto err;

1068
1069
	if (!debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR,
			sc->debug.debugfs_phy, sc, &fops_rx_chainmask))
1070
1071
		goto err;

1072
1073
	if (!debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
			sc->debug.debugfs_phy, sc, &fops_tx_chainmask))
1074
1075
		goto err;

1076
1077
	if (!debugfs_create_file("regidx", S_IRUSR | S_IWUSR,
			sc->debug.debugfs_phy, sc, &fops_regidx))
Sujith's avatar
Sujith committed
1078
1079
		goto err;

1080
1081
	if (!debugfs_create_file("regval", S_IRUSR | S_IWUSR,
			sc->debug.debugfs_phy, sc, &fops_regval))
Sujith's avatar
Sujith committed
1082
1083
		goto err;

1084
1085
1086
1087
	if (!debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR,
			sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca))
		goto err;

1088
	sc->debug.regidx = 0;
1089
1090
	return 0;
err:
1091
	debugfs_remove_recursive(sc->debug.debugfs_phy);
1092
1093
	sc->debug.debugfs_phy = NULL;
	return -ENOMEM;
1094
}