diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 10:44:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 10:44:37 -0400 |
commit | b0ca4d0123608cfec73fc689c74295da89fc934e (patch) | |
tree | 4d79f2b9c3277501637e0dcd6c541416091e4308 | |
parent | d70b1e06eb331afe1576ac23bb9523708026ba1f (diff) | |
parent | b89e35636bc75b72d15a1af6d49798802aff77d5 (diff) |
Merge tag 'tag-for-linus-3.10' of git://git.linaro.org/people/sumitsemwal/linux-dma-buf
Pull dma-buf updates from Sumit Semwal:
"Added debugfs support to dma-buf"
* tag 'tag-for-linus-3.10' of git://git.linaro.org/people/sumitsemwal/linux-dma-buf:
dma-buf: Add debugfs support
dma-buf: replace dma_buf_export() with dma_buf_export_named()
-rw-r--r-- | Documentation/dma-buf-sharing.txt | 13 | ||||
-rw-r--r-- | drivers/base/dma-buf.c | 169 | ||||
-rw-r--r-- | include/linux/dma-buf.h | 16 |
3 files changed, 189 insertions, 9 deletions
diff --git a/Documentation/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt index 4966b1be42ac..0b23261561d2 100644 --- a/Documentation/dma-buf-sharing.txt +++ b/Documentation/dma-buf-sharing.txt | |||
@@ -52,14 +52,23 @@ The dma_buf buffer sharing API usage contains the following steps: | |||
52 | associated with this buffer. | 52 | associated with this buffer. |
53 | 53 | ||
54 | Interface: | 54 | Interface: |
55 | struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops, | 55 | struct dma_buf *dma_buf_export_named(void *priv, struct dma_buf_ops *ops, |
56 | size_t size, int flags) | 56 | size_t size, int flags, |
57 | const char *exp_name) | ||
57 | 58 | ||
58 | If this succeeds, dma_buf_export allocates a dma_buf structure, and returns a | 59 | If this succeeds, dma_buf_export allocates a dma_buf structure, and returns a |
59 | pointer to the same. It also associates an anonymous file with this buffer, | 60 | pointer to the same. It also associates an anonymous file with this buffer, |
60 | so it can be exported. On failure to allocate the dma_buf object, it returns | 61 | so it can be exported. On failure to allocate the dma_buf object, it returns |
61 | NULL. | 62 | NULL. |
62 | 63 | ||
64 | 'exp_name' is the name of exporter - to facilitate information while | ||
65 | debugging. | ||
66 | |||
67 | Exporting modules which do not wish to provide any specific name may use the | ||
68 | helper define 'dma_buf_export()', with the same arguments as above, but | ||
69 | without the last argument; a __FILE__ pre-processor directive will be | ||
70 | inserted in place of 'exp_name' instead. | ||
71 | |||
63 | 2. Userspace gets a handle to pass around to potential buffer-users | 72 | 2. Userspace gets a handle to pass around to potential buffer-users |
64 | 73 | ||
65 | Userspace entity requests for a file-descriptor (fd) which is a handle to the | 74 | Userspace entity requests for a file-descriptor (fd) which is a handle to the |
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index 2a7cb0df176b..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 | } |
@@ -77,22 +91,24 @@ static inline int is_dma_buf_file(struct file *file) | |||
77 | } | 91 | } |
78 | 92 | ||
79 | /** | 93 | /** |
80 | * dma_buf_export - Creates a new dma_buf, and associates an anon file | 94 | * dma_buf_export_named - Creates a new dma_buf, and associates an anon file |
81 | * with this buffer, so it can be exported. | 95 | * with this buffer, so it can be exported. |
82 | * Also connect the allocator specific data and ops to the buffer. | 96 | * Also connect the allocator specific data and ops to the buffer. |
97 | * Additionally, provide a name string for exporter; useful in debugging. | ||
83 | * | 98 | * |
84 | * @priv: [in] Attach private data of allocator to this buffer | 99 | * @priv: [in] Attach private data of allocator to this buffer |
85 | * @ops: [in] Attach allocator-defined dma buf ops to the new buffer. | 100 | * @ops: [in] Attach allocator-defined dma buf ops to the new buffer. |
86 | * @size: [in] Size of the buffer | 101 | * @size: [in] Size of the buffer |
87 | * @flags: [in] mode flags for the file. | 102 | * @flags: [in] mode flags for the file. |
103 | * @exp_name: [in] name of the exporting module - useful for debugging. | ||
88 | * | 104 | * |
89 | * Returns, on success, a newly created dma_buf object, which wraps the | 105 | * Returns, on success, a newly created dma_buf object, which wraps the |
90 | * supplied private data and operations for dma_buf_ops. On either missing | 106 | * supplied private data and operations for dma_buf_ops. On either missing |
91 | * ops, or error in allocating struct dma_buf, will return negative error. | 107 | * ops, or error in allocating struct dma_buf, will return negative error. |
92 | * | 108 | * |
93 | */ | 109 | */ |
94 | struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops, | 110 | struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops, |
95 | size_t size, int flags) | 111 | size_t size, int flags, const char *exp_name) |
96 | { | 112 | { |
97 | struct dma_buf *dmabuf; | 113 | struct dma_buf *dmabuf; |
98 | struct file *file; | 114 | struct file *file; |
@@ -114,6 +130,7 @@ struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops, | |||
114 | dmabuf->priv = priv; | 130 | dmabuf->priv = priv; |
115 | dmabuf->ops = ops; | 131 | dmabuf->ops = ops; |
116 | dmabuf->size = size; | 132 | dmabuf->size = size; |
133 | dmabuf->exp_name = exp_name; | ||
117 | 134 | ||
118 | file = anon_inode_getfile("dmabuf", &dma_buf_fops, dmabuf, flags); | 135 | file = anon_inode_getfile("dmabuf", &dma_buf_fops, dmabuf, flags); |
119 | 136 | ||
@@ -122,9 +139,13 @@ struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops, | |||
122 | mutex_init(&dmabuf->lock); | 139 | mutex_init(&dmabuf->lock); |
123 | INIT_LIST_HEAD(&dmabuf->attachments); | 140 | INIT_LIST_HEAD(&dmabuf->attachments); |
124 | 141 | ||
142 | mutex_lock(&db_list.lock); | ||
143 | list_add(&dmabuf->list_node, &db_list.head); | ||
144 | mutex_unlock(&db_list.lock); | ||
145 | |||
125 | return dmabuf; | 146 | return dmabuf; |
126 | } | 147 | } |
127 | EXPORT_SYMBOL_GPL(dma_buf_export); | 148 | EXPORT_SYMBOL_GPL(dma_buf_export_named); |
128 | 149 | ||
129 | 150 | ||
130 | /** | 151 | /** |
@@ -548,3 +569,143 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) | |||
548 | mutex_unlock(&dmabuf->lock); | 569 | mutex_unlock(&dmabuf->lock); |
549 | } | 570 | } |
550 | 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); | ||
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 9978b614a1aa..dfac5ed31120 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h | |||
@@ -112,6 +112,8 @@ struct dma_buf_ops { | |||
112 | * @file: file pointer used for sharing buffers across, and for refcounting. | 112 | * @file: file pointer used for sharing buffers across, and for refcounting. |
113 | * @attachments: list of dma_buf_attachment that denotes all devices attached. | 113 | * @attachments: list of dma_buf_attachment that denotes all devices attached. |
114 | * @ops: dma_buf_ops associated with this buffer object. | 114 | * @ops: dma_buf_ops associated with this buffer object. |
115 | * @exp_name: name of the exporter; useful for debugging. | ||
116 | * @list_node: node for dma_buf accounting and debugging. | ||
115 | * @priv: exporter specific private data for this buffer object. | 117 | * @priv: exporter specific private data for this buffer object. |
116 | */ | 118 | */ |
117 | struct dma_buf { | 119 | struct dma_buf { |
@@ -123,6 +125,8 @@ struct dma_buf { | |||
123 | struct mutex lock; | 125 | struct mutex lock; |
124 | unsigned vmapping_counter; | 126 | unsigned vmapping_counter; |
125 | void *vmap_ptr; | 127 | void *vmap_ptr; |
128 | const char *exp_name; | ||
129 | struct list_head list_node; | ||
126 | void *priv; | 130 | void *priv; |
127 | }; | 131 | }; |
128 | 132 | ||
@@ -162,8 +166,13 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, | |||
162 | struct device *dev); | 166 | struct device *dev); |
163 | void dma_buf_detach(struct dma_buf *dmabuf, | 167 | void dma_buf_detach(struct dma_buf *dmabuf, |
164 | struct dma_buf_attachment *dmabuf_attach); | 168 | struct dma_buf_attachment *dmabuf_attach); |
165 | struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops, | 169 | |
166 | size_t size, int flags); | 170 | struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops, |
171 | size_t size, int flags, const char *); | ||
172 | |||
173 | #define dma_buf_export(priv, ops, size, flags) \ | ||
174 | dma_buf_export_named(priv, ops, size, flags, __FILE__) | ||
175 | |||
167 | int dma_buf_fd(struct dma_buf *dmabuf, int flags); | 176 | int dma_buf_fd(struct dma_buf *dmabuf, int flags); |
168 | struct dma_buf *dma_buf_get(int fd); | 177 | struct dma_buf *dma_buf_get(int fd); |
169 | void dma_buf_put(struct dma_buf *dmabuf); | 178 | void dma_buf_put(struct dma_buf *dmabuf); |
@@ -185,5 +194,6 @@ int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, | |||
185 | unsigned long); | 194 | unsigned long); |
186 | void *dma_buf_vmap(struct dma_buf *); | 195 | void *dma_buf_vmap(struct dma_buf *); |
187 | void dma_buf_vunmap(struct dma_buf *, void *vaddr); | 196 | void dma_buf_vunmap(struct dma_buf *, void *vaddr); |
188 | 197 | int dma_buf_debugfs_create_file(const char *name, | |
198 | int (*write)(struct seq_file *)); | ||
189 | #endif /* __DMA_BUF_H__ */ | 199 | #endif /* __DMA_BUF_H__ */ |