aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2x00debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00debug.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c182
1 files changed, 181 insertions, 1 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 3aa7e0ab513b..e72c98133c05 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -26,10 +26,12 @@
26#include <linux/debugfs.h> 26#include <linux/debugfs.h>
27#include <linux/kernel.h> 27#include <linux/kernel.h>
28#include <linux/module.h> 28#include <linux/module.h>
29#include <linux/poll.h>
29#include <linux/uaccess.h> 30#include <linux/uaccess.h>
30 31
31#include "rt2x00.h" 32#include "rt2x00.h"
32#include "rt2x00lib.h" 33#include "rt2x00lib.h"
34#include "rt2x00dump.h"
33 35
34#define PRINT_LINE_LEN_MAX 32 36#define PRINT_LINE_LEN_MAX 32
35 37
@@ -58,6 +60,8 @@ struct rt2x00debug_intf {
58 * - eeprom offset/value files 60 * - eeprom offset/value files
59 * - bbp offset/value files 61 * - bbp offset/value files
60 * - rf offset/value files 62 * - rf offset/value files
63 * - frame dump folder
64 * - frame dump file
61 */ 65 */
62 struct dentry *driver_folder; 66 struct dentry *driver_folder;
63 struct dentry *driver_entry; 67 struct dentry *driver_entry;
@@ -72,6 +76,24 @@ struct rt2x00debug_intf {
72 struct dentry *bbp_val_entry; 76 struct dentry *bbp_val_entry;
73 struct dentry *rf_off_entry; 77 struct dentry *rf_off_entry;
74 struct dentry *rf_val_entry; 78 struct dentry *rf_val_entry;
79 struct dentry *frame_folder;
80 struct dentry *frame_dump_entry;
81
82 /*
83 * The frame dump file only allows a single reader,
84 * so we need to store the current state here.
85 */
86 unsigned long frame_dump_flags;
87#define FRAME_DUMP_FILE_OPEN 1
88
89 /*
90 * We queue each frame before dumping it to the user,
91 * per read command we will pass a single skb structure
92 * so we should be prepared to queue multiple sk buffers
93 * before sending it to userspace.
94 */
95 struct sk_buff_head frame_dump_skbqueue;
96 wait_queue_head_t frame_dump_waitqueue;
75 97
76 /* 98 /*
77 * Driver and chipset files will use a data buffer 99 * Driver and chipset files will use a data buffer
@@ -90,6 +112,63 @@ struct rt2x00debug_intf {
90 unsigned int offset_rf; 112 unsigned int offset_rf;
91}; 113};
92 114
115void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
116 struct sk_buff *skb)
117{
118 struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
119 struct skb_desc *desc = get_skb_desc(skb);
120 struct sk_buff *skbcopy;
121 struct rt2x00dump_hdr *dump_hdr;
122 struct timeval timestamp;
123 unsigned int ring_index;
124 unsigned int entry_index;
125
126 do_gettimeofday(&timestamp);
127 ring_index = ARRAY_INDEX(desc->ring, rt2x00dev->rx);
128 entry_index = ARRAY_INDEX(desc->entry, desc->ring->entry);
129
130 if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
131 return;
132
133 if (skb_queue_len(&intf->frame_dump_skbqueue) > 20) {
134 DEBUG(rt2x00dev, "txrx dump queue length exceeded.\n");
135 return;
136 }
137
138 skbcopy = alloc_skb(sizeof(*dump_hdr) + desc->desc_len + desc->data_len,
139 GFP_ATOMIC);
140 if (!skbcopy) {
141 DEBUG(rt2x00dev, "Failed to copy skb for dump.\n");
142 return;
143 }
144
145 dump_hdr = (struct rt2x00dump_hdr *)skb_put(skbcopy, sizeof(*dump_hdr));
146 dump_hdr->version = cpu_to_le32(DUMP_HEADER_VERSION);
147 dump_hdr->header_length = cpu_to_le32(sizeof(*dump_hdr));
148 dump_hdr->desc_length = cpu_to_le32(desc->desc_len);
149 dump_hdr->data_length = cpu_to_le32(desc->data_len);
150 dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);
151 dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
152 dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev);
153 dump_hdr->type = cpu_to_le16(desc->frame_type);
154 dump_hdr->ring_index = ring_index;
155 dump_hdr->entry_index = entry_index;
156 dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);
157 dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec);
158
159 memcpy(skb_put(skbcopy, desc->desc_len), desc->desc, desc->desc_len);
160 memcpy(skb_put(skbcopy, desc->data_len), desc->data, desc->data_len);
161
162 skb_queue_tail(&intf->frame_dump_skbqueue, skbcopy);
163 wake_up_interruptible(&intf->frame_dump_waitqueue);
164
165 /*
166 * Verify that the file has not been closed while we were working.
167 */
168 if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
169 skb_queue_purge(&intf->frame_dump_skbqueue);
170}
171
93static int rt2x00debug_file_open(struct inode *inode, struct file *file) 172static int rt2x00debug_file_open(struct inode *inode, struct file *file)
94{ 173{
95 struct rt2x00debug_intf *intf = inode->i_private; 174 struct rt2x00debug_intf *intf = inode->i_private;
@@ -111,6 +190,89 @@ static int rt2x00debug_file_release(struct inode *inode, struct file *file)
111 return 0; 190 return 0;
112} 191}
113 192
193static int rt2x00debug_open_ring_dump(struct inode *inode, struct file *file)
194{
195 struct rt2x00debug_intf *intf = inode->i_private;
196 int retval;
197
198 retval = rt2x00debug_file_open(inode, file);
199 if (retval)
200 return retval;
201
202 if (test_and_set_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags)) {
203 rt2x00debug_file_release(inode, file);
204 return -EBUSY;
205 }
206
207 return 0;
208}
209
210static int rt2x00debug_release_ring_dump(struct inode *inode, struct file *file)
211{
212 struct rt2x00debug_intf *intf = inode->i_private;
213
214 skb_queue_purge(&intf->frame_dump_skbqueue);
215
216 clear_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags);
217
218 return rt2x00debug_file_release(inode, file);
219}
220
221static ssize_t rt2x00debug_read_ring_dump(struct file *file,
222 char __user *buf,
223 size_t length,
224 loff_t *offset)
225{
226 struct rt2x00debug_intf *intf = file->private_data;
227 struct sk_buff *skb;
228 size_t status;
229 int retval;
230
231 if (file->f_flags & O_NONBLOCK)
232 return -EAGAIN;
233
234 retval =
235 wait_event_interruptible(intf->frame_dump_waitqueue,
236 (skb =
237 skb_dequeue(&intf->frame_dump_skbqueue)));
238 if (retval)
239 return retval;
240
241 status = min((size_t)skb->len, length);
242 if (copy_to_user(buf, skb->data, status)) {
243 status = -EFAULT;
244 goto exit;
245 }
246
247 *offset += status;
248
249exit:
250 kfree_skb(skb);
251
252 return status;
253}
254
255static unsigned int rt2x00debug_poll_ring_dump(struct file *file,
256 poll_table *wait)
257{
258 struct rt2x00debug_intf *intf = file->private_data;
259
260 poll_wait(file, &intf->frame_dump_waitqueue, wait);
261
262 if (!skb_queue_empty(&intf->frame_dump_skbqueue))
263 return POLLOUT | POLLWRNORM;
264
265 return 0;
266}
267
268static const struct file_operations rt2x00debug_fop_ring_dump = {
269 .owner = THIS_MODULE,
270 .read = rt2x00debug_read_ring_dump,
271 .poll = rt2x00debug_poll_ring_dump,
272 .open = rt2x00debug_open_ring_dump,
273 .release = rt2x00debug_release_ring_dump,
274};
275
114#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \ 276#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \
115static ssize_t rt2x00debug_read_##__name(struct file *file, \ 277static ssize_t rt2x00debug_read_##__name(struct file *file, \
116 char __user *buf, \ 278 char __user *buf, \
@@ -339,6 +501,20 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
339 501
340#undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY 502#undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY
341 503
504 intf->frame_folder =
505 debugfs_create_dir("frame", intf->driver_folder);
506 if (IS_ERR(intf->frame_folder))
507 goto exit;
508
509 intf->frame_dump_entry =
510 debugfs_create_file("dump", S_IRUGO, intf->frame_folder,
511 intf, &rt2x00debug_fop_ring_dump);
512 if (IS_ERR(intf->frame_dump_entry))
513 goto exit;
514
515 skb_queue_head_init(&intf->frame_dump_skbqueue);
516 init_waitqueue_head(&intf->frame_dump_waitqueue);
517
342 return; 518 return;
343 519
344exit: 520exit:
@@ -350,11 +526,15 @@ exit:
350 526
351void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) 527void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
352{ 528{
353 const struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; 529 struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
354 530
355 if (unlikely(!intf)) 531 if (unlikely(!intf))
356 return; 532 return;
357 533
534 skb_queue_purge(&intf->frame_dump_skbqueue);
535
536 debugfs_remove(intf->frame_dump_entry);
537 debugfs_remove(intf->frame_folder);
358 debugfs_remove(intf->rf_val_entry); 538 debugfs_remove(intf->rf_val_entry);
359 debugfs_remove(intf->rf_off_entry); 539 debugfs_remove(intf->rf_off_entry);
360 debugfs_remove(intf->bbp_val_entry); 540 debugfs_remove(intf->bbp_val_entry);