• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/src/linux/linux-2.6/drivers/net/wireless/bcm43xx/
1/*
2
3  Broadcom BCM43xx wireless driver
4
5  debugfs driver debugging code
6
7  Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
8
9  This program is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  GNU General Public License for more details.
18
19  You should have received a copy of the GNU General Public License
20  along with this program; see the file COPYING.  If not, write to
21  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
22  Boston, MA 02110-1301, USA.
23
24*/
25
26
27
28#include <linux/fs.h>
29#include <linux/debugfs.h>
30#include <linux/slab.h>
31#include <linux/netdevice.h>
32#include <linux/pci.h>
33#include <asm/io.h>
34
35#include "bcm43xx.h"
36#include "bcm43xx_main.h"
37#include "bcm43xx_debugfs.h"
38#include "bcm43xx_dma.h"
39#include "bcm43xx_pio.h"
40#include "bcm43xx_xmit.h"
41
42#define REALLY_BIG_BUFFER_SIZE	(1024*256)
43
44static struct bcm43xx_debugfs fs;
45static char really_big_buffer[REALLY_BIG_BUFFER_SIZE];
46static DECLARE_MUTEX(big_buffer_sem);
47
48
49static ssize_t write_file_dummy(struct file *file, const char __user *buf,
50				size_t count, loff_t *ppos)
51{
52	return count;
53}
54
55static int open_file_generic(struct inode *inode, struct file *file)
56{
57	file->private_data = inode->i_private;
58	return 0;
59}
60
61#define fappend(fmt, x...)	pos += snprintf(buf + pos, len - pos, fmt , ##x)
62
63static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
64				 size_t count, loff_t *ppos)
65{
66	const size_t len = REALLY_BIG_BUFFER_SIZE;
67
68	struct bcm43xx_private *bcm = file->private_data;
69	char *buf = really_big_buffer;
70	size_t pos = 0;
71	ssize_t res;
72	struct net_device *net_dev;
73	struct pci_dev *pci_dev;
74	unsigned long flags;
75	u16 tmp16;
76	int i;
77
78	down(&big_buffer_sem);
79
80	mutex_lock(&bcm->mutex);
81	spin_lock_irqsave(&bcm->irq_lock, flags);
82	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
83		fappend("Board not initialized.\n");
84		goto out;
85	}
86	net_dev = bcm->net_dev;
87	pci_dev = bcm->pci_dev;
88
89	/* This is where the information is written to the "devinfo" file */
90	fappend("*** %s devinfo ***\n", net_dev->name);
91	fappend("vendor:           0x%04x   device:           0x%04x\n",
92		pci_dev->vendor, pci_dev->device);
93	fappend("subsystem_vendor: 0x%04x   subsystem_device: 0x%04x\n",
94		pci_dev->subsystem_vendor, pci_dev->subsystem_device);
95	fappend("IRQ: %d\n", bcm->irq);
96	fappend("mmio_addr: 0x%p\n", bcm->mmio_addr);
97	fappend("chip_id: 0x%04x   chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev);
98	if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16)))
99		fappend("Radio disabled by hardware!\n");
100	if ((bcm->core_80211[0].rev < 3) && !(bcm43xx_read16(bcm, 0x049A) & (1 << 4)))
101		fappend("Radio disabled by hardware!\n");
102	fappend("board_vendor: 0x%04x   board_type: 0x%04x\n", bcm->board_vendor,
103	        bcm->board_type);
104
105	fappend("\nCores:\n");
106#define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, "	\
107					 "rev: 0x%02x, index: 0x%02x\n",		\
108					 (info).available				\
109						? "available" : "nonavailable",		\
110					 (info).enabled					\
111						? "enabled" : "disabled",		\
112					 (info).id, (info).rev, (info).index)
113	fappend_core("CHIPCOMMON", bcm->core_chipcommon);
114	fappend_core("PCI", bcm->core_pci);
115	fappend_core("first 80211", bcm->core_80211[0]);
116	fappend_core("second 80211", bcm->core_80211[1]);
117#undef fappend_core
118	tmp16 = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
119	fappend("LEDs: ");
120	for (i = 0; i < BCM43xx_NR_LEDS; i++)
121		fappend("%d ", !!(tmp16 & (1 << i)));
122	fappend("\n");
123
124out:
125	spin_unlock_irqrestore(&bcm->irq_lock, flags);
126	mutex_unlock(&bcm->mutex);
127	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
128	up(&big_buffer_sem);
129	return res;
130}
131
132static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf,
133				 size_t count, loff_t *ppos)
134{
135	const size_t len = REALLY_BIG_BUFFER_SIZE;
136
137	char *buf = really_big_buffer;
138	size_t pos = 0;
139	ssize_t res;
140
141	down(&big_buffer_sem);
142
143	/* This is where the information is written to the "driver" file */
144	fappend(KBUILD_MODNAME " driver\n");
145	fappend("Compiled at: %s %s\n", __DATE__, __TIME__);
146
147	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
148	up(&big_buffer_sem);
149	return res;
150}
151
152static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
153				 size_t count, loff_t *ppos)
154{
155	const size_t len = REALLY_BIG_BUFFER_SIZE;
156
157	struct bcm43xx_private *bcm = file->private_data;
158	char *buf = really_big_buffer;
159	size_t pos = 0;
160	ssize_t res;
161	unsigned long flags;
162
163	down(&big_buffer_sem);
164	mutex_lock(&bcm->mutex);
165	spin_lock_irqsave(&bcm->irq_lock, flags);
166	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
167		fappend("Board not initialized.\n");
168		goto out;
169	}
170
171	/* This is where the information is written to the "sprom_dump" file */
172	fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
173
174out:
175	spin_unlock_irqrestore(&bcm->irq_lock, flags);
176	mutex_unlock(&bcm->mutex);
177	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
178	up(&big_buffer_sem);
179	return res;
180}
181
182static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
183			     size_t count, loff_t *ppos)
184{
185	const size_t len = REALLY_BIG_BUFFER_SIZE;
186
187	struct bcm43xx_private *bcm = file->private_data;
188	char *buf = really_big_buffer;
189	size_t pos = 0;
190	ssize_t res;
191	unsigned long flags;
192	u64 tsf;
193
194	down(&big_buffer_sem);
195	mutex_lock(&bcm->mutex);
196	spin_lock_irqsave(&bcm->irq_lock, flags);
197	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
198		fappend("Board not initialized.\n");
199		goto out;
200	}
201	bcm43xx_tsf_read(bcm, &tsf);
202	fappend("0x%08x%08x\n",
203		(unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
204		(unsigned int)(tsf & 0xFFFFFFFFULL));
205
206out:
207	spin_unlock_irqrestore(&bcm->irq_lock, flags);
208	mutex_unlock(&bcm->mutex);
209	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
210	up(&big_buffer_sem);
211	return res;
212}
213
214static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
215			      size_t count, loff_t *ppos)
216{
217	struct bcm43xx_private *bcm = file->private_data;
218	char *buf = really_big_buffer;
219	ssize_t buf_size;
220	ssize_t res;
221	unsigned long flags;
222	u64 tsf;
223
224	buf_size = min(count, sizeof (really_big_buffer) - 1);
225	down(&big_buffer_sem);
226	if (copy_from_user(buf, user_buf, buf_size)) {
227	        res = -EFAULT;
228		goto out_up;
229	}
230	mutex_lock(&bcm->mutex);
231	spin_lock_irqsave(&bcm->irq_lock, flags);
232	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
233		printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
234		res = -EFAULT;
235		goto out_unlock;
236	}
237	if (sscanf(buf, "%lli", &tsf) != 1) {
238		printk(KERN_INFO PFX "debugfs: invalid values for \"tsf\"\n");
239		res = -EINVAL;
240		goto out_unlock;
241	}
242	bcm43xx_tsf_write(bcm, tsf);
243	mmiowb();
244	res = buf_size;
245
246out_unlock:
247	spin_unlock_irqrestore(&bcm->irq_lock, flags);
248	mutex_unlock(&bcm->mutex);
249out_up:
250	up(&big_buffer_sem);
251	return res;
252}
253
254static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
255				size_t count, loff_t *ppos)
256{
257	const size_t len = REALLY_BIG_BUFFER_SIZE;
258
259	struct bcm43xx_private *bcm = file->private_data;
260	char *buf = really_big_buffer;
261	size_t pos = 0;
262	ssize_t res;
263	unsigned long flags;
264	struct bcm43xx_dfsentry *e;
265	struct bcm43xx_xmitstatus *status;
266	int i, cnt, j = 0;
267
268	down(&big_buffer_sem);
269	mutex_lock(&bcm->mutex);
270	spin_lock_irqsave(&bcm->irq_lock, flags);
271
272	fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
273		BCM43xx_NR_LOGGED_XMITSTATUS);
274	e = bcm->dfsentry;
275	if (e->xmitstatus_printing == 0) {
276		/* At the beginning, make a copy of all data to avoid
277		 * concurrency, as this function is called multiple
278		 * times for big logs. Without copying, the data might
279		 * change between reads. This would result in total trash.
280		 */
281		e->xmitstatus_printing = 1;
282		e->saved_xmitstatus_ptr = e->xmitstatus_ptr;
283		e->saved_xmitstatus_cnt = e->xmitstatus_cnt;
284		memcpy(e->xmitstatus_print_buffer, e->xmitstatus_buffer,
285		       BCM43xx_NR_LOGGED_XMITSTATUS * sizeof(*(e->xmitstatus_buffer)));
286	}
287	i = e->saved_xmitstatus_ptr - 1;
288	if (i < 0)
289		i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
290	cnt = e->saved_xmitstatus_cnt;
291	while (cnt) {
292		status = e->xmitstatus_print_buffer + i;
293		fappend("0x%02x:   cookie: 0x%04x,  flags: 0x%02x,  "
294			"cnt1: 0x%02x,  cnt2: 0x%02x,  seq: 0x%04x,  "
295			"unk: 0x%04x\n", j,
296			status->cookie, status->flags,
297			status->cnt1, status->cnt2, status->seq,
298			status->unknown);
299		j++;
300		cnt--;
301		i--;
302		if (i < 0)
303			i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
304	}
305
306	spin_unlock_irqrestore(&bcm->irq_lock, flags);
307	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
308	spin_lock_irqsave(&bcm->irq_lock, flags);
309	if (*ppos == pos) {
310		/* Done. Drop the copied data. */
311		e->xmitstatus_printing = 0;
312	}
313	spin_unlock_irqrestore(&bcm->irq_lock, flags);
314	mutex_unlock(&bcm->mutex);
315	up(&big_buffer_sem);
316	return res;
317}
318
319static ssize_t restart_write_file(struct file *file, const char __user *user_buf,
320				  size_t count, loff_t *ppos)
321{
322	struct bcm43xx_private *bcm = file->private_data;
323	char *buf = really_big_buffer;
324	ssize_t buf_size;
325	ssize_t res;
326	unsigned long flags;
327
328	buf_size = min(count, sizeof (really_big_buffer) - 1);
329	down(&big_buffer_sem);
330	if (copy_from_user(buf, user_buf, buf_size)) {
331	        res = -EFAULT;
332		goto out_up;
333	}
334	mutex_lock(&(bcm)->mutex);
335	spin_lock_irqsave(&(bcm)->irq_lock, flags);
336	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
337		printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
338		res = -EFAULT;
339		goto out_unlock;
340	}
341	if (count > 0 && buf[0] == '1') {
342		bcm43xx_controller_restart(bcm, "manually restarted");
343		res = count;
344	} else
345		res = -EINVAL;
346
347out_unlock:
348	spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
349	mutex_unlock(&(bcm)->mutex);
350out_up:
351	up(&big_buffer_sem);
352	return res;
353}
354
355#undef fappend
356
357
358static const struct file_operations devinfo_fops = {
359	.read = devinfo_read_file,
360	.write = write_file_dummy,
361	.open = open_file_generic,
362};
363
364static const struct file_operations spromdump_fops = {
365	.read = spromdump_read_file,
366	.write = write_file_dummy,
367	.open = open_file_generic,
368};
369
370static const struct file_operations drvinfo_fops = {
371	.read = drvinfo_read_file,
372	.write = write_file_dummy,
373	.open = open_file_generic,
374};
375
376static const struct file_operations tsf_fops = {
377	.read = tsf_read_file,
378	.write = tsf_write_file,
379	.open = open_file_generic,
380};
381
382static const struct file_operations txstat_fops = {
383	.read = txstat_read_file,
384	.write = write_file_dummy,
385	.open = open_file_generic,
386};
387
388static const struct file_operations restart_fops = {
389	.write = restart_write_file,
390	.open = open_file_generic,
391};
392
393
394void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
395{
396	struct bcm43xx_dfsentry *e;
397	char devdir[IFNAMSIZ];
398
399	assert(bcm);
400	e = kzalloc(sizeof(*e), GFP_KERNEL);
401	if (!e) {
402		printk(KERN_ERR PFX "out of memory\n");
403		return;
404	}
405	e->bcm = bcm;
406	e->xmitstatus_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS
407				       * sizeof(*(e->xmitstatus_buffer)),
408				       GFP_KERNEL);
409	if (!e->xmitstatus_buffer) {
410		printk(KERN_ERR PFX "out of memory\n");
411		kfree(e);
412		return;
413	}
414	e->xmitstatus_print_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS
415					     * sizeof(*(e->xmitstatus_buffer)),
416					     GFP_KERNEL);
417	if (!e->xmitstatus_print_buffer) {
418		printk(KERN_ERR PFX "out of memory\n");
419		kfree(e);
420		return;
421	}
422
423
424	bcm->dfsentry = e;
425
426	strncpy(devdir, bcm->net_dev->name, ARRAY_SIZE(devdir));
427	e->subdir = debugfs_create_dir(devdir, fs.root);
428	e->dentry_devinfo = debugfs_create_file("devinfo", 0444, e->subdir,
429						bcm, &devinfo_fops);
430	if (!e->dentry_devinfo)
431		printk(KERN_ERR PFX "debugfs: creating \"devinfo\" for \"%s\" failed!\n", devdir);
432	e->dentry_spromdump = debugfs_create_file("sprom_dump", 0444, e->subdir,
433						  bcm, &spromdump_fops);
434	if (!e->dentry_spromdump)
435		printk(KERN_ERR PFX "debugfs: creating \"sprom_dump\" for \"%s\" failed!\n", devdir);
436	e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir,
437	                                    bcm, &tsf_fops);
438	if (!e->dentry_tsf)
439		printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir);
440	e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir,
441						bcm, &txstat_fops);
442	if (!e->dentry_txstat)
443		printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
444	e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir,
445						bcm, &restart_fops);
446	if (!e->dentry_restart)
447		printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir);
448}
449
450void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
451{
452	struct bcm43xx_dfsentry *e;
453
454	if (!bcm)
455		return;
456
457	e = bcm->dfsentry;
458	assert(e);
459	debugfs_remove(e->dentry_spromdump);
460	debugfs_remove(e->dentry_devinfo);
461	debugfs_remove(e->dentry_tsf);
462	debugfs_remove(e->dentry_txstat);
463	debugfs_remove(e->dentry_restart);
464	debugfs_remove(e->subdir);
465	kfree(e->xmitstatus_buffer);
466	kfree(e->xmitstatus_print_buffer);
467	kfree(e);
468}
469
470void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
471				struct bcm43xx_xmitstatus *status)
472{
473	struct bcm43xx_dfsentry *e;
474	struct bcm43xx_xmitstatus *savedstatus;
475
476	/* This is protected by bcm->_lock */
477	e = bcm->dfsentry;
478	assert(e);
479	savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr;
480	memcpy(savedstatus, status, sizeof(*status));
481	e->xmitstatus_ptr++;
482	if (e->xmitstatus_ptr >= BCM43xx_NR_LOGGED_XMITSTATUS)
483		e->xmitstatus_ptr = 0;
484	if (e->xmitstatus_cnt < BCM43xx_NR_LOGGED_XMITSTATUS)
485		e->xmitstatus_cnt++;
486}
487
488void bcm43xx_debugfs_init(void)
489{
490	memset(&fs, 0, sizeof(fs));
491	fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL);
492	if (!fs.root)
493		printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n");
494	fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops);
495	if (!fs.dentry_driverinfo)
496		printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n");
497}
498
499void bcm43xx_debugfs_exit(void)
500{
501	debugfs_remove(fs.dentry_driverinfo);
502	debugfs_remove(fs.root);
503}
504
505void bcm43xx_printk_dump(const char *data,
506			 size_t size,
507			 const char *description)
508{
509	size_t i;
510	char c;
511
512	printk(KERN_INFO PFX "Data dump (%s, %zd bytes):",
513	       description, size);
514	for (i = 0; i < size; i++) {
515		c = data[i];
516		if (i % 8 == 0)
517			printk("\n" KERN_INFO PFX "0x%08zx:  0x%02x, ", i, c & 0xff);
518		else
519			printk("0x%02x, ", c & 0xff);
520	}
521	printk("\n");
522}
523
524void bcm43xx_printk_bitdump(const unsigned char *data,
525			    size_t bytes, int msb_to_lsb,
526			    const char *description)
527{
528	size_t i;
529	int j;
530	const unsigned char *d;
531
532	printk(KERN_INFO PFX "*** Bitdump (%s, %zd bytes, %s) ***",
533	       description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB");
534	for (i = 0; i < bytes; i++) {
535		d = data + i;
536		if (i % 8 == 0)
537			printk("\n" KERN_INFO PFX "0x%08zx:  ", i);
538		if (msb_to_lsb) {
539			for (j = 7; j >= 0; j--) {
540				if (*d & (1 << j))
541					printk("1");
542				else
543					printk("0");
544			}
545		} else {
546			for (j = 0; j < 8; j++) {
547				if (*d & (1 << j))
548					printk("1");
549				else
550					printk("0");
551			}
552		}
553		printk(" ");
554	}
555	printk("\n");
556}
557