aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorKalle Valo <kvalo@qca.qualcomm.com>2012-02-06 01:23:40 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2012-02-08 04:25:07 -0500
commitc807b30d2588dd3c74db1f690a0e9e724dd332da (patch)
tree285723e62f2e40814d164597c6a44340e0d8566f /drivers/net/wireless/ath
parent9b9a4f2acac2a04416ba15242b8666d4f8273e31 (diff)
ath6kl: add blocking debugfs file for retrieving firmware logs
When debugging firmware issues it's not always enough to get the latest firmware logs, sometimes we need to get logs from a longer period. To make this possible, add a debugfs file named fwlog_block. When reading from this file ath6kl will send firmware logs whenever available and otherwise it will block and wait for new logs. Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h3
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c104
2 files changed, 106 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 9a58214135b9..4ff06a326785 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -653,6 +653,9 @@ struct ath6kl {
653#ifdef CONFIG_ATH6KL_DEBUG 653#ifdef CONFIG_ATH6KL_DEBUG
654 struct { 654 struct {
655 struct sk_buff_head fwlog_queue; 655 struct sk_buff_head fwlog_queue;
656 struct completion fwlog_completion;
657 bool fwlog_open;
658
656 u32 fwlog_mask; 659 u32 fwlog_mask;
657 660
658 unsigned int dbgfs_diag_reg; 661 unsigned int dbgfs_diag_reg;
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index 98b5f15f622e..ec32ff692163 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -290,6 +290,7 @@ void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
290 spin_lock(&ar->debug.fwlog_queue.lock); 290 spin_lock(&ar->debug.fwlog_queue.lock);
291 291
292 __skb_queue_tail(&ar->debug.fwlog_queue, skb); 292 __skb_queue_tail(&ar->debug.fwlog_queue, skb);
293 complete(&ar->debug.fwlog_completion);
293 294
294 /* drop oldest entries */ 295 /* drop oldest entries */
295 while (skb_queue_len(&ar->debug.fwlog_queue) > 296 while (skb_queue_len(&ar->debug.fwlog_queue) >
@@ -303,6 +304,28 @@ void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
303 return; 304 return;
304} 305}
305 306
307static int ath6kl_fwlog_open(struct inode *inode, struct file *file)
308{
309 struct ath6kl *ar = inode->i_private;
310
311 if (ar->debug.fwlog_open)
312 return -EBUSY;
313
314 ar->debug.fwlog_open = true;
315
316 file->private_data = inode->i_private;
317 return 0;
318}
319
320static int ath6kl_fwlog_release(struct inode *inode, struct file *file)
321{
322 struct ath6kl *ar = inode->i_private;
323
324 ar->debug.fwlog_open = false;
325
326 return 0;
327}
328
306static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, 329static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
307 size_t count, loff_t *ppos) 330 size_t count, loff_t *ppos)
308{ 331{
@@ -347,12 +370,87 @@ static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
347} 370}
348 371
349static const struct file_operations fops_fwlog = { 372static const struct file_operations fops_fwlog = {
350 .open = ath6kl_debugfs_open, 373 .open = ath6kl_fwlog_open,
374 .release = ath6kl_fwlog_release,
351 .read = ath6kl_fwlog_read, 375 .read = ath6kl_fwlog_read,
352 .owner = THIS_MODULE, 376 .owner = THIS_MODULE,
353 .llseek = default_llseek, 377 .llseek = default_llseek,
354}; 378};
355 379
380static ssize_t ath6kl_fwlog_block_read(struct file *file,
381 char __user *user_buf,
382 size_t count,
383 loff_t *ppos)
384{
385 struct ath6kl *ar = file->private_data;
386 struct sk_buff *skb;
387 ssize_t ret_cnt;
388 size_t len = 0, not_copied;
389 char *buf;
390 int ret;
391
392 buf = vmalloc(count);
393 if (!buf)
394 return -ENOMEM;
395
396 spin_lock(&ar->debug.fwlog_queue.lock);
397
398 if (skb_queue_len(&ar->debug.fwlog_queue) == 0) {
399 /* we must init under queue lock */
400 init_completion(&ar->debug.fwlog_completion);
401
402 spin_unlock(&ar->debug.fwlog_queue.lock);
403
404 ret = wait_for_completion_interruptible(
405 &ar->debug.fwlog_completion);
406 if (ret == -ERESTARTSYS)
407 return ret;
408
409 spin_lock(&ar->debug.fwlog_queue.lock);
410 }
411
412 while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
413 if (skb->len > count - len) {
414 /* not enough space, put skb back and leave */
415 __skb_queue_head(&ar->debug.fwlog_queue, skb);
416 break;
417 }
418
419
420 memcpy(buf + len, skb->data, skb->len);
421 len += skb->len;
422
423 kfree_skb(skb);
424 }
425
426 spin_unlock(&ar->debug.fwlog_queue.lock);
427
428 /* FIXME: what to do if len == 0? */
429
430 not_copied = copy_to_user(user_buf, buf, len);
431 if (not_copied != 0) {
432 ret_cnt = -EFAULT;
433 goto out;
434 }
435
436 *ppos = *ppos + len;
437
438 ret_cnt = len;
439
440out:
441 vfree(buf);
442
443 return ret_cnt;
444}
445
446static const struct file_operations fops_fwlog_block = {
447 .open = ath6kl_fwlog_open,
448 .release = ath6kl_fwlog_release,
449 .read = ath6kl_fwlog_block_read,
450 .owner = THIS_MODULE,
451 .llseek = default_llseek,
452};
453
356static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf, 454static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf,
357 size_t count, loff_t *ppos) 455 size_t count, loff_t *ppos)
358{ 456{
@@ -1623,6 +1721,7 @@ static const struct file_operations fops_power_params = {
1623int ath6kl_debug_init(struct ath6kl *ar) 1721int ath6kl_debug_init(struct ath6kl *ar)
1624{ 1722{
1625 skb_queue_head_init(&ar->debug.fwlog_queue); 1723 skb_queue_head_init(&ar->debug.fwlog_queue);
1724 init_completion(&ar->debug.fwlog_completion);
1626 1725
1627 /* 1726 /*
1628 * Actually we are lying here but don't know how to read the mask 1727 * Actually we are lying here but don't know how to read the mask
@@ -1647,6 +1746,9 @@ int ath6kl_debug_init(struct ath6kl *ar)
1647 debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, 1746 debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar,
1648 &fops_fwlog); 1747 &fops_fwlog);
1649 1748
1749 debugfs_create_file("fwlog_block", S_IRUSR, ar->debugfs_phy, ar,
1750 &fops_fwlog_block);
1751
1650 debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, 1752 debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy,
1651 ar, &fops_fwlog_mask); 1753 ar, &fops_fwlog_mask);
1652 1754