~ubuntu-branches/ubuntu/karmic/linux-ports/karmic

« back to all changes in this revision

Viewing changes to drivers/net/wireless/ath9k/debug.c

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich, Luke Yelavich, Michael Casadevall, Tim Gardner, Upstream Kernel Changes
  • Date: 2009-05-06 18:18:55 UTC
  • Revision ID: james.westby@ubuntu.com-20090506181855-t00baeevpnvd9o7a
Tags: 2.6.30-1.1
[ Luke Yelavich ]
* initial release for karmic
* SAUCE: rebase-ports - adjust for the karmic ports kernel
* SAUCE: rebase-ports - also remove abi dirs/files on rebase
* Update configs after rebase against mainline Jaunty tree
* [Config] Disable CONFIG_BLK_DEV_UB and CONFIG_USB_LIBUSUAL as per
  mainline jaunty
* forward-port patch to drbd for powerpc compilation
* [Config] disable CONFIG_LENOVO_SL_LAPTOP for i386 due to FTBFS
* add .o files found in arch/powerpc/lib to all powerpc kernel header
  packages
* [Config] enable CONFIG_DRM_I915_KMS for i386 as per karmic mainline

[ Michael Casadevall ]

* Disable kgdb on sparc64
* [sparc] [Config] Disable GPIO LEDS
* [ia64] Rename -ia64-generic to -ia64 in line with other architectures
* Correct kernel image path for sparc builds
* [hppa] Fix HPPA config files to build modules for all udebian

Rebase on top of karmic mainline 2.6.30-1.1

[ Tim Gardner ]

* [Config] armel: disable staging drivers, fixes FTBS
* [Config] armel imx51: Disable CONFIG_MTD_NAND_MXC, fixes FTBS

[ Upstream Kernel Changes ]

* mpt2sas: Change reset_type enum to avoid namespace collision.
  Submitted upstream.

* Initial release after rebasing against v2.6.30-rc3

Show diffs side-by-side

added added

removed removed

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