diff options
author | Sumit Semwal <sumit.semwal@linaro.org> | 2013-04-04 02:14:37 -0400 |
---|---|---|
committer | Sumit Semwal <sumit.semwal@linaro.org> | 2013-05-01 07:06:22 -0400 |
commit | b89e35636bc75b72d15a1af6d49798802aff77d5 (patch) | |
tree | 68b8531d44591f4448d09145407e490c2b5d2faf /drivers/base | |
parent | 78df969550e7187f4dcd70b737217dcbc8e9a06a (diff) |
dma-buf: Add debugfs support
Add debugfs support to make it easier to print debug information
about the dma-buf buffers.
Cc: Dave Airlie <airlied@redhat.com>
[minor fixes on init and warning fix]
Cc: Dan Carpenter <dan.carpenter@oracle.com>
[remove double unlock in fail case]
Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/dma-buf.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index d89102a29f65..08fe897c0b4c 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c | |||
@@ -27,9 +27,18 @@ | |||
27 | #include <linux/dma-buf.h> | 27 | #include <linux/dma-buf.h> |
28 | #include <linux/anon_inodes.h> | 28 | #include <linux/anon_inodes.h> |
29 | #include <linux/export.h> | 29 | #include <linux/export.h> |
30 | #include <linux/debugfs.h> | ||
31 | #include <linux/seq_file.h> | ||
30 | 32 | ||
31 | static inline int is_dma_buf_file(struct file *); | 33 | static inline int is_dma_buf_file(struct file *); |
32 | 34 | ||
35 | struct dma_buf_list { | ||
36 | struct list_head head; | ||
37 | struct mutex lock; | ||
38 | }; | ||
39 | |||
40 | static struct dma_buf_list db_list; | ||
41 | |||
33 | static int dma_buf_release(struct inode *inode, struct file *file) | 42 | static int dma_buf_release(struct inode *inode, struct file *file) |
34 | { | 43 | { |
35 | struct dma_buf *dmabuf; | 44 | struct dma_buf *dmabuf; |
@@ -42,6 +51,11 @@ static int dma_buf_release(struct inode *inode, struct file *file) | |||
42 | BUG_ON(dmabuf->vmapping_counter); | 51 | BUG_ON(dmabuf->vmapping_counter); |
43 | 52 | ||
44 | dmabuf->ops->release(dmabuf); | 53 | dmabuf->ops->release(dmabuf); |
54 | |||
55 | mutex_lock(&db_list.lock); | ||
56 | list_del(&dmabuf->list_node); | ||
57 | mutex_unlock(&db_list.lock); | ||
58 | |||
45 | kfree(dmabuf); | 59 | kfree(dmabuf); |
46 | return 0; | 60 | return 0; |
47 | } | 61 | } |
@@ -125,6 +139,10 @@ struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops, | |||
125 | mutex_init(&dmabuf->lock); | 139 | mutex_init(&dmabuf->lock); |
126 | INIT_LIST_HEAD(&dmabuf->attachments); | 140 | INIT_LIST_HEAD(&dmabuf->attachments); |
127 | 141 | ||
142 | mutex_lock(&db_list.lock); | ||
143 | list_add(&dmabuf->list_node, &db_list.head); | ||
144 | mutex_unlock(&db_list.lock); | ||
145 | |||
128 | return dmabuf; | 146 | return dmabuf; |
129 | } | 147 | } |
130 | EXPORT_SYMBOL_GPL(dma_buf_export_named); | 148 | EXPORT_SYMBOL_GPL(dma_buf_export_named); |
@@ -551,3 +569,143 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) | |||
551 | mutex_unlock(&dmabuf->lock); | 569 | mutex_unlock(&dmabuf->lock); |
552 | } | 570 | } |
553 | EXPORT_SYMBOL_GPL(dma_buf_vunmap); | 571 | EXPORT_SYMBOL_GPL(dma_buf_vunmap); |
572 | |||
573 | #ifdef CONFIG_DEBUG_FS | ||
574 | static int dma_buf_describe(struct seq_file *s) | ||
575 | { | ||
576 | int ret; | ||
577 | struct dma_buf *buf_obj; | ||
578 | struct dma_buf_attachment *attach_obj; | ||
579 | int count = 0, attach_count; | ||
580 | size_t size = 0; | ||
581 | |||
582 | ret = mutex_lock_interruptible(&db_list.lock); | ||
583 | |||
584 | if (ret) | ||
585 | return ret; | ||
586 | |||
587 | seq_printf(s, "\nDma-buf Objects:\n"); | ||
588 | seq_printf(s, "\texp_name\tsize\tflags\tmode\tcount\n"); | ||
589 | |||
590 | list_for_each_entry(buf_obj, &db_list.head, list_node) { | ||
591 | ret = mutex_lock_interruptible(&buf_obj->lock); | ||
592 | |||
593 | if (ret) { | ||
594 | seq_printf(s, | ||
595 | "\tERROR locking buffer object: skipping\n"); | ||
596 | continue; | ||
597 | } | ||
598 | |||
599 | seq_printf(s, "\t"); | ||
600 | |||
601 | seq_printf(s, "\t%s\t%08zu\t%08x\t%08x\t%08ld\n", | ||
602 | buf_obj->exp_name, buf_obj->size, | ||
603 | buf_obj->file->f_flags, buf_obj->file->f_mode, | ||
604 | (long)(buf_obj->file->f_count.counter)); | ||
605 | |||
606 | seq_printf(s, "\t\tAttached Devices:\n"); | ||
607 | attach_count = 0; | ||
608 | |||
609 | list_for_each_entry(attach_obj, &buf_obj->attachments, node) { | ||
610 | seq_printf(s, "\t\t"); | ||
611 | |||
612 | seq_printf(s, "%s\n", attach_obj->dev->init_name); | ||
613 | attach_count++; | ||
614 | } | ||
615 | |||
616 | seq_printf(s, "\n\t\tTotal %d devices attached\n", | ||
617 | attach_count); | ||
618 | |||
619 | count++; | ||
620 | size += buf_obj->size; | ||
621 | mutex_unlock(&buf_obj->lock); | ||
622 | } | ||
623 | |||
624 | seq_printf(s, "\nTotal %d objects, %zu bytes\n", count, size); | ||
625 | |||
626 | mutex_unlock(&db_list.lock); | ||
627 | return 0; | ||
628 | } | ||
629 | |||
630 | static int dma_buf_show(struct seq_file *s, void *unused) | ||
631 | { | ||
632 | void (*func)(struct seq_file *) = s->private; | ||
633 | func(s); | ||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | static int dma_buf_debug_open(struct inode *inode, struct file *file) | ||
638 | { | ||
639 | return single_open(file, dma_buf_show, inode->i_private); | ||
640 | } | ||
641 | |||
642 | static const struct file_operations dma_buf_debug_fops = { | ||
643 | .open = dma_buf_debug_open, | ||
644 | .read = seq_read, | ||
645 | .llseek = seq_lseek, | ||
646 | .release = single_release, | ||
647 | }; | ||
648 | |||
649 | static struct dentry *dma_buf_debugfs_dir; | ||
650 | |||
651 | static int dma_buf_init_debugfs(void) | ||
652 | { | ||
653 | int err = 0; | ||
654 | dma_buf_debugfs_dir = debugfs_create_dir("dma_buf", NULL); | ||
655 | if (IS_ERR(dma_buf_debugfs_dir)) { | ||
656 | err = PTR_ERR(dma_buf_debugfs_dir); | ||
657 | dma_buf_debugfs_dir = NULL; | ||
658 | return err; | ||
659 | } | ||
660 | |||
661 | err = dma_buf_debugfs_create_file("bufinfo", dma_buf_describe); | ||
662 | |||
663 | if (err) | ||
664 | pr_debug("dma_buf: debugfs: failed to create node bufinfo\n"); | ||
665 | |||
666 | return err; | ||
667 | } | ||
668 | |||
669 | static void dma_buf_uninit_debugfs(void) | ||
670 | { | ||
671 | if (dma_buf_debugfs_dir) | ||
672 | debugfs_remove_recursive(dma_buf_debugfs_dir); | ||
673 | } | ||
674 | |||
675 | int dma_buf_debugfs_create_file(const char *name, | ||
676 | int (*write)(struct seq_file *)) | ||
677 | { | ||
678 | struct dentry *d; | ||
679 | |||
680 | d = debugfs_create_file(name, S_IRUGO, dma_buf_debugfs_dir, | ||
681 | write, &dma_buf_debug_fops); | ||
682 | |||
683 | if (IS_ERR(d)) | ||
684 | return PTR_ERR(d); | ||
685 | |||
686 | return 0; | ||
687 | } | ||
688 | #else | ||
689 | static inline int dma_buf_init_debugfs(void) | ||
690 | { | ||
691 | return 0; | ||
692 | } | ||
693 | static inline void dma_buf_uninit_debugfs(void) | ||
694 | { | ||
695 | } | ||
696 | #endif | ||
697 | |||
698 | static int __init dma_buf_init(void) | ||
699 | { | ||
700 | mutex_init(&db_list.lock); | ||
701 | INIT_LIST_HEAD(&db_list.head); | ||
702 | dma_buf_init_debugfs(); | ||
703 | return 0; | ||
704 | } | ||
705 | subsys_initcall(dma_buf_init); | ||
706 | |||
707 | static void __exit dma_buf_deinit(void) | ||
708 | { | ||
709 | dma_buf_uninit_debugfs(); | ||
710 | } | ||
711 | __exitcall(dma_buf_deinit); | ||