• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 
3   Broadcom B43 wireless driver
4 
5   debugfs driver debugging code
6 
7   Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.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 #include <linux/fs.h>
27 #include <linux/debugfs.h>
28 #include <linux/slab.h>
29 #include <linux/netdevice.h>
30 #include <linux/pci.h>
31 #include <linux/mutex.h>
32 
33 #include "b43.h"
34 #include "main.h"
35 #include "debugfs.h"
36 #include "dma.h"
37 #include "xmit.h"
38 
39 
40 /* The root directory. */
41 static struct dentry *rootdir;
42 
43 struct b43_debugfs_fops {
44 	ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize);
45 	int (*write)(struct b43_wldev *dev, const char *buf, size_t count);
46 	struct file_operations fops;
47 	/* Offset of struct b43_dfs_file in struct b43_dfsentry */
48 	size_t file_struct_offset;
49 	/* Take wl->irq_lock before calling read/write? */
50 	bool take_irqlock;
51 };
52 
53 static inline
fops_to_dfs_file(struct b43_wldev * dev,const struct b43_debugfs_fops * dfops)54 struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev,
55 				       const struct b43_debugfs_fops *dfops)
56 {
57 	void *p;
58 
59 	p = dev->dfsentry;
60 	p += dfops->file_struct_offset;
61 
62 	return p;
63 }
64 
65 
66 #define fappend(fmt, x...)	\
67 	do {							\
68 		if (bufsize - count)				\
69 			count += snprintf(buf + count,		\
70 					  bufsize - count,	\
71 					  fmt , ##x);		\
72 		else						\
73 			printk(KERN_ERR "b43: fappend overflow\n"); \
74 	} while (0)
75 
76 
77 /* The biggest address values for SHM access from the debugfs files. */
78 #define B43_MAX_SHM_ROUTING	4
79 #define B43_MAX_SHM_ADDR	0xFFFF
80 
shm16read__read_file(struct b43_wldev * dev,char * buf,size_t bufsize)81 static ssize_t shm16read__read_file(struct b43_wldev *dev,
82 				    char *buf, size_t bufsize)
83 {
84 	ssize_t count = 0;
85 	unsigned int routing, addr;
86 	u16 val;
87 
88 	routing = dev->dfsentry->shm16read_routing_next;
89 	addr = dev->dfsentry->shm16read_addr_next;
90 	if ((routing > B43_MAX_SHM_ROUTING) ||
91 	    (addr > B43_MAX_SHM_ADDR))
92 		return -EDESTADDRREQ;
93 
94 	val = b43_shm_read16(dev, routing, addr);
95 	fappend("0x%04X\n", val);
96 
97 	return count;
98 }
99 
shm16read__write_file(struct b43_wldev * dev,const char * buf,size_t count)100 static int shm16read__write_file(struct b43_wldev *dev,
101 				 const char *buf, size_t count)
102 {
103 	unsigned int routing, addr;
104 	int res;
105 
106 	res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
107 	if (res != 2)
108 		return -EINVAL;
109 	if (routing > B43_MAX_SHM_ROUTING)
110 		return -EADDRNOTAVAIL;
111 	if (addr > B43_MAX_SHM_ADDR)
112 		return -EADDRNOTAVAIL;
113 	if (routing == B43_SHM_SHARED) {
114 		if ((addr % 2) != 0)
115 			return -EADDRNOTAVAIL;
116 	}
117 
118 	dev->dfsentry->shm16read_routing_next = routing;
119 	dev->dfsentry->shm16read_addr_next = addr;
120 
121 	return 0;
122 }
123 
shm16write__write_file(struct b43_wldev * dev,const char * buf,size_t count)124 static int shm16write__write_file(struct b43_wldev *dev,
125 				  const char *buf, size_t count)
126 {
127 	unsigned int routing, addr, mask, set;
128 	u16 val;
129 	int res;
130 	unsigned long flags;
131 
132 	res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
133 		     &routing, &addr, &mask, &set);
134 	if (res != 4)
135 		return -EINVAL;
136 	if (routing > B43_MAX_SHM_ROUTING)
137 		return -EADDRNOTAVAIL;
138 	if (addr > B43_MAX_SHM_ADDR)
139 		return -EADDRNOTAVAIL;
140 	if (routing == B43_SHM_SHARED) {
141 		if ((addr % 2) != 0)
142 			return -EADDRNOTAVAIL;
143 	}
144 	if ((mask > 0xFFFF) || (set > 0xFFFF))
145 		return -E2BIG;
146 
147 	spin_lock_irqsave(&dev->wl->shm_lock, flags);
148 	if (mask == 0)
149 		val = 0;
150 	else
151 		val = __b43_shm_read16(dev, routing, addr);
152 	val &= mask;
153 	val |= set;
154 	__b43_shm_write16(dev, routing, addr, val);
155 	spin_unlock_irqrestore(&dev->wl->shm_lock, flags);
156 
157 	return 0;
158 }
159 
shm32read__read_file(struct b43_wldev * dev,char * buf,size_t bufsize)160 static ssize_t shm32read__read_file(struct b43_wldev *dev,
161 				    char *buf, size_t bufsize)
162 {
163 	ssize_t count = 0;
164 	unsigned int routing, addr;
165 	u32 val;
166 
167 	routing = dev->dfsentry->shm32read_routing_next;
168 	addr = dev->dfsentry->shm32read_addr_next;
169 	if ((routing > B43_MAX_SHM_ROUTING) ||
170 	    (addr > B43_MAX_SHM_ADDR))
171 		return -EDESTADDRREQ;
172 
173 	val = b43_shm_read32(dev, routing, addr);
174 	fappend("0x%08X\n", val);
175 
176 	return count;
177 }
178 
shm32read__write_file(struct b43_wldev * dev,const char * buf,size_t count)179 static int shm32read__write_file(struct b43_wldev *dev,
180 				 const char *buf, size_t count)
181 {
182 	unsigned int routing, addr;
183 	int res;
184 
185 	res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
186 	if (res != 2)
187 		return -EINVAL;
188 	if (routing > B43_MAX_SHM_ROUTING)
189 		return -EADDRNOTAVAIL;
190 	if (addr > B43_MAX_SHM_ADDR)
191 		return -EADDRNOTAVAIL;
192 	if (routing == B43_SHM_SHARED) {
193 		if ((addr % 2) != 0)
194 			return -EADDRNOTAVAIL;
195 	}
196 
197 	dev->dfsentry->shm32read_routing_next = routing;
198 	dev->dfsentry->shm32read_addr_next = addr;
199 
200 	return 0;
201 }
202 
shm32write__write_file(struct b43_wldev * dev,const char * buf,size_t count)203 static int shm32write__write_file(struct b43_wldev *dev,
204 				  const char *buf, size_t count)
205 {
206 	unsigned int routing, addr, mask, set;
207 	u32 val;
208 	int res;
209 	unsigned long flags;
210 
211 	res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
212 		     &routing, &addr, &mask, &set);
213 	if (res != 4)
214 		return -EINVAL;
215 	if (routing > B43_MAX_SHM_ROUTING)
216 		return -EADDRNOTAVAIL;
217 	if (addr > B43_MAX_SHM_ADDR)
218 		return -EADDRNOTAVAIL;
219 	if (routing == B43_SHM_SHARED) {
220 		if ((addr % 2) != 0)
221 			return -EADDRNOTAVAIL;
222 	}
223 	if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
224 		return -E2BIG;
225 
226 	spin_lock_irqsave(&dev->wl->shm_lock, flags);
227 	if (mask == 0)
228 		val = 0;
229 	else
230 		val = __b43_shm_read32(dev, routing, addr);
231 	val &= mask;
232 	val |= set;
233 	__b43_shm_write32(dev, routing, addr, val);
234 	spin_unlock_irqrestore(&dev->wl->shm_lock, flags);
235 
236 	return 0;
237 }
238 
239 /* The biggest MMIO address that we allow access to from the debugfs files. */
240 #define B43_MAX_MMIO_ACCESS	(0xF00 - 1)
241 
mmio16read__read_file(struct b43_wldev * dev,char * buf,size_t bufsize)242 static ssize_t mmio16read__read_file(struct b43_wldev *dev,
243 				     char *buf, size_t bufsize)
244 {
245 	ssize_t count = 0;
246 	unsigned int addr;
247 	u16 val;
248 
249 	addr = dev->dfsentry->mmio16read_next;
250 	if (addr > B43_MAX_MMIO_ACCESS)
251 		return -EDESTADDRREQ;
252 
253 	val = b43_read16(dev, addr);
254 	fappend("0x%04X\n", val);
255 
256 	return count;
257 }
258 
mmio16read__write_file(struct b43_wldev * dev,const char * buf,size_t count)259 static int mmio16read__write_file(struct b43_wldev *dev,
260 				  const char *buf, size_t count)
261 {
262 	unsigned int addr;
263 	int res;
264 
265 	res = sscanf(buf, "0x%X", &addr);
266 	if (res != 1)
267 		return -EINVAL;
268 	if (addr > B43_MAX_MMIO_ACCESS)
269 		return -EADDRNOTAVAIL;
270 	if ((addr % 2) != 0)
271 		return -EINVAL;
272 
273 	dev->dfsentry->mmio16read_next = addr;
274 
275 	return 0;
276 }
277 
mmio16write__write_file(struct b43_wldev * dev,const char * buf,size_t count)278 static int mmio16write__write_file(struct b43_wldev *dev,
279 				   const char *buf, size_t count)
280 {
281 	unsigned int addr, mask, set;
282 	int res;
283 	u16 val;
284 
285 	res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
286 	if (res != 3)
287 		return -EINVAL;
288 	if (addr > B43_MAX_MMIO_ACCESS)
289 		return -EADDRNOTAVAIL;
290 	if ((mask > 0xFFFF) || (set > 0xFFFF))
291 		return -E2BIG;
292 	if ((addr % 2) != 0)
293 		return -EINVAL;
294 
295 	if (mask == 0)
296 		val = 0;
297 	else
298 		val = b43_read16(dev, addr);
299 	val &= mask;
300 	val |= set;
301 	b43_write16(dev, addr, val);
302 
303 	return 0;
304 }
305 
mmio32read__read_file(struct b43_wldev * dev,char * buf,size_t bufsize)306 static ssize_t mmio32read__read_file(struct b43_wldev *dev,
307 				     char *buf, size_t bufsize)
308 {
309 	ssize_t count = 0;
310 	unsigned int addr;
311 	u32 val;
312 
313 	addr = dev->dfsentry->mmio32read_next;
314 	if (addr > B43_MAX_MMIO_ACCESS)
315 		return -EDESTADDRREQ;
316 
317 	val = b43_read32(dev, addr);
318 	fappend("0x%08X\n", val);
319 
320 	return count;
321 }
322 
mmio32read__write_file(struct b43_wldev * dev,const char * buf,size_t count)323 static int mmio32read__write_file(struct b43_wldev *dev,
324 				  const char *buf, size_t count)
325 {
326 	unsigned int addr;
327 	int res;
328 
329 	res = sscanf(buf, "0x%X", &addr);
330 	if (res != 1)
331 		return -EINVAL;
332 	if (addr > B43_MAX_MMIO_ACCESS)
333 		return -EADDRNOTAVAIL;
334 	if ((addr % 4) != 0)
335 		return -EINVAL;
336 
337 	dev->dfsentry->mmio32read_next = addr;
338 
339 	return 0;
340 }
341 
mmio32write__write_file(struct b43_wldev * dev,const char * buf,size_t count)342 static int mmio32write__write_file(struct b43_wldev *dev,
343 				   const char *buf, size_t count)
344 {
345 	unsigned int addr, mask, set;
346 	int res;
347 	u32 val;
348 
349 	res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
350 	if (res != 3)
351 		return -EINVAL;
352 	if (addr > B43_MAX_MMIO_ACCESS)
353 		return -EADDRNOTAVAIL;
354 	if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
355 		return -E2BIG;
356 	if ((addr % 4) != 0)
357 		return -EINVAL;
358 
359 	if (mask == 0)
360 		val = 0;
361 	else
362 		val = b43_read32(dev, addr);
363 	val &= mask;
364 	val |= set;
365 	b43_write32(dev, addr, val);
366 
367 	return 0;
368 }
369 
370 /* wl->irq_lock is locked */
tsf_read_file(struct b43_wldev * dev,char * buf,size_t bufsize)371 static ssize_t tsf_read_file(struct b43_wldev *dev,
372 			     char *buf, size_t bufsize)
373 {
374 	ssize_t count = 0;
375 	u64 tsf;
376 
377 	b43_tsf_read(dev, &tsf);
378 	fappend("0x%08x%08x\n",
379 		(unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
380 		(unsigned int)(tsf & 0xFFFFFFFFULL));
381 
382 	return count;
383 }
384 
385 /* wl->irq_lock is locked */
tsf_write_file(struct b43_wldev * dev,const char * buf,size_t count)386 static int tsf_write_file(struct b43_wldev *dev,
387 			  const char *buf, size_t count)
388 {
389 	u64 tsf;
390 
391 	if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1)
392 		return -EINVAL;
393 	b43_tsf_write(dev, tsf);
394 
395 	return 0;
396 }
397 
txstat_read_file(struct b43_wldev * dev,char * buf,size_t bufsize)398 static ssize_t txstat_read_file(struct b43_wldev *dev,
399 				char *buf, size_t bufsize)
400 {
401 	struct b43_txstatus_log *log = &dev->dfsentry->txstatlog;
402 	ssize_t count = 0;
403 	unsigned long flags;
404 	int i, idx;
405 	struct b43_txstatus *stat;
406 
407 	spin_lock_irqsave(&log->lock, flags);
408 	if (log->end < 0) {
409 		fappend("Nothing transmitted, yet\n");
410 		goto out_unlock;
411 	}
412 	fappend("b43 TX status reports:\n\n"
413 		"index | cookie | seq | phy_stat | frame_count | "
414 		"rts_count | supp_reason | pm_indicated | "
415 		"intermediate | for_ampdu | acked\n" "---\n");
416 	i = log->end + 1;
417 	idx = 0;
418 	while (1) {
419 		if (i == B43_NR_LOGGED_TXSTATUS)
420 			i = 0;
421 		stat = &(log->log[i]);
422 		if (stat->cookie) {
423 			fappend("%03d | "
424 				"0x%04X | 0x%04X | 0x%02X | "
425 				"0x%X | 0x%X | "
426 				"%u | %u | "
427 				"%u | %u | %u\n",
428 				idx,
429 				stat->cookie, stat->seq, stat->phy_stat,
430 				stat->frame_count, stat->rts_count,
431 				stat->supp_reason, stat->pm_indicated,
432 				stat->intermediate, stat->for_ampdu,
433 				stat->acked);
434 			idx++;
435 		}
436 		if (i == log->end)
437 			break;
438 		i++;
439 	}
440 out_unlock:
441 	spin_unlock_irqrestore(&log->lock, flags);
442 
443 	return count;
444 }
445 
446 /* wl->irq_lock is locked */
restart_write_file(struct b43_wldev * dev,const char * buf,size_t count)447 static int restart_write_file(struct b43_wldev *dev,
448 			      const char *buf, size_t count)
449 {
450 	int err = 0;
451 
452 	if (count > 0 && buf[0] == '1') {
453 		b43_controller_restart(dev, "manually restarted");
454 	} else
455 		err = -EINVAL;
456 
457 	return err;
458 }
459 
calc_expire_secs(unsigned long now,unsigned long time,unsigned long expire)460 static unsigned long calc_expire_secs(unsigned long now,
461 				      unsigned long time,
462 				      unsigned long expire)
463 {
464 	expire = time + expire;
465 
466 	if (time_after(now, expire))
467 		return 0; /* expired */
468 	if (expire < now) {
469 		/* jiffies wrapped */
470 		expire -= MAX_JIFFY_OFFSET;
471 		now -= MAX_JIFFY_OFFSET;
472 	}
473 	B43_WARN_ON(expire < now);
474 
475 	return (expire - now) / HZ;
476 }
477 
loctls_read_file(struct b43_wldev * dev,char * buf,size_t bufsize)478 static ssize_t loctls_read_file(struct b43_wldev *dev,
479 				char *buf, size_t bufsize)
480 {
481 	ssize_t count = 0;
482 	struct b43_txpower_lo_control *lo;
483 	int i, err = 0;
484 	struct b43_lo_calib *cal;
485 	unsigned long now = jiffies;
486 	struct b43_phy *phy = &dev->phy;
487 
488 	if (phy->type != B43_PHYTYPE_G) {
489 		fappend("Device is not a G-PHY\n");
490 		err = -ENODEV;
491 		goto out;
492 	}
493 	lo = phy->g->lo_control;
494 	fappend("-- Local Oscillator calibration data --\n\n");
495 	fappend("HW-power-control enabled: %d\n",
496 		dev->phy.hardware_power_control);
497 	fappend("TX Bias: 0x%02X,  TX Magn: 0x%02X  (expire in %lu sec)\n",
498 		lo->tx_bias, lo->tx_magn,
499 		calc_expire_secs(now, lo->txctl_measured_time,
500 				 B43_LO_TXCTL_EXPIRE));
501 	fappend("Power Vector: 0x%08X%08X  (expires in %lu sec)\n",
502 		(unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32),
503 		(unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL),
504 		calc_expire_secs(now, lo->pwr_vec_read_time,
505 				 B43_LO_PWRVEC_EXPIRE));
506 
507 	fappend("\nCalibrated settings:\n");
508 	list_for_each_entry(cal, &lo->calib_list, list) {
509 		bool active;
510 
511 		active = (b43_compare_bbatt(&cal->bbatt, &phy->g->bbatt) &&
512 			  b43_compare_rfatt(&cal->rfatt, &phy->g->rfatt));
513 		fappend("BB(%d), RF(%d,%d)  ->  I=%d, Q=%d  "
514 			"(expires in %lu sec)%s\n",
515 			cal->bbatt.att,
516 			cal->rfatt.att, cal->rfatt.with_padmix,
517 			cal->ctl.i, cal->ctl.q,
518 			calc_expire_secs(now, cal->calib_time,
519 					 B43_LO_CALIB_EXPIRE),
520 			active ? "  ACTIVE" : "");
521 	}
522 
523 	fappend("\nUsed RF attenuation values:  Value(WithPadmix flag)\n");
524 	for (i = 0; i < lo->rfatt_list.len; i++) {
525 		fappend("%u(%d), ",
526 			lo->rfatt_list.list[i].att,
527 			lo->rfatt_list.list[i].with_padmix);
528 	}
529 	fappend("\n");
530 	fappend("\nUsed Baseband attenuation values:\n");
531 	for (i = 0; i < lo->bbatt_list.len; i++) {
532 		fappend("%u, ",
533 			lo->bbatt_list.list[i].att);
534 	}
535 	fappend("\n");
536 
537 out:
538 	return err ? err : count;
539 }
540 
541 #undef fappend
542 
b43_debugfs_open(struct inode * inode,struct file * file)543 static int b43_debugfs_open(struct inode *inode, struct file *file)
544 {
545 	file->private_data = inode->i_private;
546 	return 0;
547 }
548 
b43_debugfs_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)549 static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
550 				size_t count, loff_t *ppos)
551 {
552 	struct b43_wldev *dev;
553 	struct b43_debugfs_fops *dfops;
554 	struct b43_dfs_file *dfile;
555 	ssize_t uninitialized_var(ret);
556 	char *buf;
557 	const size_t bufsize = 1024 * 16; /* 16 kiB buffer */
558 	const size_t buforder = get_order(bufsize);
559 	int err = 0;
560 
561 	if (!count)
562 		return 0;
563 	dev = file->private_data;
564 	if (!dev)
565 		return -ENODEV;
566 
567 	mutex_lock(&dev->wl->mutex);
568 	if (b43_status(dev) < B43_STAT_INITIALIZED) {
569 		err = -ENODEV;
570 		goto out_unlock;
571 	}
572 
573 	dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
574 	if (!dfops->read) {
575 		err = -ENOSYS;
576 		goto out_unlock;
577 	}
578 	dfile = fops_to_dfs_file(dev, dfops);
579 
580 	if (!dfile->buffer) {
581 		buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
582 		if (!buf) {
583 			err = -ENOMEM;
584 			goto out_unlock;
585 		}
586 		memset(buf, 0, bufsize);
587 		if (dfops->take_irqlock) {
588 			spin_lock_irq(&dev->wl->irq_lock);
589 			ret = dfops->read(dev, buf, bufsize);
590 			spin_unlock_irq(&dev->wl->irq_lock);
591 		} else
592 			ret = dfops->read(dev, buf, bufsize);
593 		if (ret <= 0) {
594 			free_pages((unsigned long)buf, buforder);
595 			err = ret;
596 			goto out_unlock;
597 		}
598 		dfile->data_len = ret;
599 		dfile->buffer = buf;
600 	}
601 
602 	ret = simple_read_from_buffer(userbuf, count, ppos,
603 				      dfile->buffer,
604 				      dfile->data_len);
605 	if (*ppos >= dfile->data_len) {
606 		free_pages((unsigned long)dfile->buffer, buforder);
607 		dfile->buffer = NULL;
608 		dfile->data_len = 0;
609 	}
610 out_unlock:
611 	mutex_unlock(&dev->wl->mutex);
612 
613 	return err ? err : ret;
614 }
615 
b43_debugfs_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)616 static ssize_t b43_debugfs_write(struct file *file,
617 				 const char __user *userbuf,
618 				 size_t count, loff_t *ppos)
619 {
620 	struct b43_wldev *dev;
621 	struct b43_debugfs_fops *dfops;
622 	char *buf;
623 	int err = 0;
624 
625 	if (!count)
626 		return 0;
627 	if (count > PAGE_SIZE)
628 		return -E2BIG;
629 	dev = file->private_data;
630 	if (!dev)
631 		return -ENODEV;
632 
633 	mutex_lock(&dev->wl->mutex);
634 	if (b43_status(dev) < B43_STAT_INITIALIZED) {
635 		err = -ENODEV;
636 		goto out_unlock;
637 	}
638 
639 	dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
640 	if (!dfops->write) {
641 		err = -ENOSYS;
642 		goto out_unlock;
643 	}
644 
645 	buf = (char *)get_zeroed_page(GFP_KERNEL);
646 	if (!buf) {
647 		err = -ENOMEM;
648 		goto out_unlock;
649 	}
650 	if (copy_from_user(buf, userbuf, count)) {
651 		err = -EFAULT;
652 		goto out_freepage;
653 	}
654 	if (dfops->take_irqlock) {
655 		spin_lock_irq(&dev->wl->irq_lock);
656 		err = dfops->write(dev, buf, count);
657 		spin_unlock_irq(&dev->wl->irq_lock);
658 	} else
659 		err = dfops->write(dev, buf, count);
660 	if (err)
661 		goto out_freepage;
662 
663 out_freepage:
664 	free_page((unsigned long)buf);
665 out_unlock:
666 	mutex_unlock(&dev->wl->mutex);
667 
668 	return err ? err : count;
669 }
670 
671 
672 #define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock)	\
673 	static struct b43_debugfs_fops fops_##name = {		\
674 		.read	= _read,				\
675 		.write	= _write,				\
676 		.fops	= {					\
677 			.open	= b43_debugfs_open,		\
678 			.read	= b43_debugfs_read,		\
679 			.write	= b43_debugfs_write,		\
680 		},						\
681 		.file_struct_offset = offsetof(struct b43_dfsentry, \
682 					       file_##name),	\
683 		.take_irqlock	= _take_irqlock,		\
684 	}
685 
686 B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file, 1);
687 B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file, 1);
688 B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file, 1);
689 B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file, 1);
690 B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file, 1);
691 B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file, 1);
692 B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1);
693 B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1);
694 B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
695 B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
696 B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
697 B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0);
698 
699 
b43_debug(struct b43_wldev * dev,enum b43_dyndbg feature)700 int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
701 {
702 	return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
703 }
704 
b43_remove_dynamic_debug(struct b43_wldev * dev)705 static void b43_remove_dynamic_debug(struct b43_wldev *dev)
706 {
707 	struct b43_dfsentry *e = dev->dfsentry;
708 	int i;
709 
710 	for (i = 0; i < __B43_NR_DYNDBG; i++)
711 		debugfs_remove(e->dyn_debug_dentries[i]);
712 }
713 
b43_add_dynamic_debug(struct b43_wldev * dev)714 static void b43_add_dynamic_debug(struct b43_wldev *dev)
715 {
716 	struct b43_dfsentry *e = dev->dfsentry;
717 	struct dentry *d;
718 
719 #define add_dyn_dbg(name, id, initstate) do {		\
720 	e->dyn_debug[id] = (initstate);			\
721 	d = debugfs_create_bool(name, 0600, e->subdir,	\
722 				&(e->dyn_debug[id]));	\
723 	if (!IS_ERR(d))					\
724 		e->dyn_debug_dentries[id] = d;		\
725 				} while (0)
726 
727 	add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, 0);
728 	add_dyn_dbg("debug_dmaoverflow", B43_DBG_DMAOVERFLOW, 0);
729 	add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0);
730 	add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0);
731 	add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
732 	add_dyn_dbg("debug_lo", B43_DBG_LO, 0);
733 	add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
734 	add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0);
735 
736 #undef add_dyn_dbg
737 }
738 
b43_debugfs_add_device(struct b43_wldev * dev)739 void b43_debugfs_add_device(struct b43_wldev *dev)
740 {
741 	struct b43_dfsentry *e;
742 	struct b43_txstatus_log *log;
743 	char devdir[16];
744 
745 	B43_WARN_ON(!dev);
746 	e = kzalloc(sizeof(*e), GFP_KERNEL);
747 	if (!e) {
748 		b43err(dev->wl, "debugfs: add device OOM\n");
749 		return;
750 	}
751 	e->dev = dev;
752 	log = &e->txstatlog;
753 	log->log = kcalloc(B43_NR_LOGGED_TXSTATUS,
754 			   sizeof(struct b43_txstatus), GFP_KERNEL);
755 	if (!log->log) {
756 		b43err(dev->wl, "debugfs: add device txstatus OOM\n");
757 		kfree(e);
758 		return;
759 	}
760 	log->end = -1;
761 	spin_lock_init(&log->lock);
762 
763 	dev->dfsentry = e;
764 
765 	snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
766 	e->subdir = debugfs_create_dir(devdir, rootdir);
767 	if (!e->subdir || IS_ERR(e->subdir)) {
768 		if (e->subdir == ERR_PTR(-ENODEV)) {
769 			b43dbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
770 			       "enabled in kernel config\n");
771 		} else {
772 			b43err(dev->wl, "debugfs: cannot create %s directory\n",
773 			       devdir);
774 		}
775 		dev->dfsentry = NULL;
776 		kfree(log->log);
777 		kfree(e);
778 		return;
779 	}
780 
781 	e->mmio16read_next = 0xFFFF; /* invalid address */
782 	e->mmio32read_next = 0xFFFF; /* invalid address */
783 	e->shm16read_routing_next = 0xFFFFFFFF; /* invalid routing */
784 	e->shm16read_addr_next = 0xFFFFFFFF; /* invalid address */
785 	e->shm32read_routing_next = 0xFFFFFFFF; /* invalid routing */
786 	e->shm32read_addr_next = 0xFFFFFFFF; /* invalid address */
787 
788 #define ADD_FILE(name, mode)	\
789 	do {							\
790 		struct dentry *d;				\
791 		d = debugfs_create_file(__stringify(name),	\
792 					mode, e->subdir, dev,	\
793 					&fops_##name.fops);	\
794 		e->file_##name.dentry = NULL;			\
795 		if (!IS_ERR(d))					\
796 			e->file_##name.dentry = d;		\
797 	} while (0)
798 
799 
800 	ADD_FILE(shm16read, 0600);
801 	ADD_FILE(shm16write, 0200);
802 	ADD_FILE(shm32read, 0600);
803 	ADD_FILE(shm32write, 0200);
804 	ADD_FILE(mmio16read, 0600);
805 	ADD_FILE(mmio16write, 0200);
806 	ADD_FILE(mmio32read, 0600);
807 	ADD_FILE(mmio32write, 0200);
808 	ADD_FILE(tsf, 0600);
809 	ADD_FILE(txstat, 0400);
810 	ADD_FILE(restart, 0200);
811 	ADD_FILE(loctls, 0400);
812 
813 #undef ADD_FILE
814 
815 	b43_add_dynamic_debug(dev);
816 }
817 
b43_debugfs_remove_device(struct b43_wldev * dev)818 void b43_debugfs_remove_device(struct b43_wldev *dev)
819 {
820 	struct b43_dfsentry *e;
821 
822 	if (!dev)
823 		return;
824 	e = dev->dfsentry;
825 	if (!e)
826 		return;
827 	b43_remove_dynamic_debug(dev);
828 
829 	debugfs_remove(e->file_shm16read.dentry);
830 	debugfs_remove(e->file_shm16write.dentry);
831 	debugfs_remove(e->file_shm32read.dentry);
832 	debugfs_remove(e->file_shm32write.dentry);
833 	debugfs_remove(e->file_mmio16read.dentry);
834 	debugfs_remove(e->file_mmio16write.dentry);
835 	debugfs_remove(e->file_mmio32read.dentry);
836 	debugfs_remove(e->file_mmio32write.dentry);
837 	debugfs_remove(e->file_tsf.dentry);
838 	debugfs_remove(e->file_txstat.dentry);
839 	debugfs_remove(e->file_restart.dentry);
840 	debugfs_remove(e->file_loctls.dentry);
841 
842 	debugfs_remove(e->subdir);
843 	kfree(e->txstatlog.log);
844 	kfree(e);
845 }
846 
847 /* Called with IRQs disabled. */
b43_debugfs_log_txstat(struct b43_wldev * dev,const struct b43_txstatus * status)848 void b43_debugfs_log_txstat(struct b43_wldev *dev,
849 			    const struct b43_txstatus *status)
850 {
851 	struct b43_dfsentry *e = dev->dfsentry;
852 	struct b43_txstatus_log *log;
853 	struct b43_txstatus *cur;
854 	int i;
855 
856 	if (!e)
857 		return;
858 	log = &e->txstatlog;
859 	spin_lock(&log->lock); /* IRQs are already disabled. */
860 	i = log->end + 1;
861 	if (i == B43_NR_LOGGED_TXSTATUS)
862 		i = 0;
863 	log->end = i;
864 	cur = &(log->log[i]);
865 	memcpy(cur, status, sizeof(*cur));
866 	spin_unlock(&log->lock);
867 }
868 
b43_debugfs_init(void)869 void b43_debugfs_init(void)
870 {
871 	rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
872 	if (IS_ERR(rootdir))
873 		rootdir = NULL;
874 }
875 
b43_debugfs_exit(void)876 void b43_debugfs_exit(void)
877 {
878 	debugfs_remove(rootdir);
879 }
880