Commit b0ca4d01 authored by Linus Torvalds's avatar Linus Torvalds

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()
parents d70b1e06 b89e3563
...@@ -52,14 +52,23 @@ The dma_buf buffer sharing API usage contains the following steps: ...@@ -52,14 +52,23 @@ The dma_buf buffer sharing API usage contains the following steps:
associated with this buffer. associated with this buffer.
Interface: Interface:
struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops, struct dma_buf *dma_buf_export_named(void *priv, struct dma_buf_ops *ops,
size_t size, int flags) size_t size, int flags,
const char *exp_name)
If this succeeds, dma_buf_export allocates a dma_buf structure, and returns a If this succeeds, dma_buf_export allocates a dma_buf structure, and returns a
pointer to the same. It also associates an anonymous file with this buffer, pointer to the same. It also associates an anonymous file with this buffer,
so it can be exported. On failure to allocate the dma_buf object, it returns so it can be exported. On failure to allocate the dma_buf object, it returns
NULL. NULL.
'exp_name' is the name of exporter - to facilitate information while
debugging.
Exporting modules which do not wish to provide any specific name may use the
helper define 'dma_buf_export()', with the same arguments as above, but
without the last argument; a __FILE__ pre-processor directive will be
inserted in place of 'exp_name' instead.
2. Userspace gets a handle to pass around to potential buffer-users 2. Userspace gets a handle to pass around to potential buffer-users
Userspace entity requests for a file-descriptor (fd) which is a handle to the Userspace entity requests for a file-descriptor (fd) which is a handle to the
......
...@@ -27,9 +27,18 @@ ...@@ -27,9 +27,18 @@
#include <linux/dma-buf.h> #include <linux/dma-buf.h>
#include <linux/anon_inodes.h> #include <linux/anon_inodes.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
static inline int is_dma_buf_file(struct file *); static inline int is_dma_buf_file(struct file *);
struct dma_buf_list {
struct list_head head;
struct mutex lock;
};
static struct dma_buf_list db_list;
static int dma_buf_release(struct inode *inode, struct file *file) static int dma_buf_release(struct inode *inode, struct file *file)
{ {
struct dma_buf *dmabuf; struct dma_buf *dmabuf;
...@@ -42,6 +51,11 @@ static int dma_buf_release(struct inode *inode, struct file *file) ...@@ -42,6 +51,11 @@ static int dma_buf_release(struct inode *inode, struct file *file)
BUG_ON(dmabuf->vmapping_counter); BUG_ON(dmabuf->vmapping_counter);
dmabuf->ops->release(dmabuf); dmabuf->ops->release(dmabuf);
mutex_lock(&db_list.lock);
list_del(&dmabuf->list_node);
mutex_unlock(&db_list.lock);
kfree(dmabuf); kfree(dmabuf);
return 0; return 0;
} }
...@@ -77,22 +91,24 @@ static inline int is_dma_buf_file(struct file *file) ...@@ -77,22 +91,24 @@ static inline int is_dma_buf_file(struct file *file)
} }
/** /**
* dma_buf_export - Creates a new dma_buf, and associates an anon file * dma_buf_export_named - Creates a new dma_buf, and associates an anon file
* with this buffer, so it can be exported. * with this buffer, so it can be exported.
* Also connect the allocator specific data and ops to the buffer. * Also connect the allocator specific data and ops to the buffer.
* Additionally, provide a name string for exporter; useful in debugging.
* *
* @priv: [in] Attach private data of allocator to this buffer * @priv: [in] Attach private data of allocator to this buffer
* @ops: [in] Attach allocator-defined dma buf ops to the new buffer. * @ops: [in] Attach allocator-defined dma buf ops to the new buffer.
* @size: [in] Size of the buffer * @size: [in] Size of the buffer
* @flags: [in] mode flags for the file. * @flags: [in] mode flags for the file.
* @exp_name: [in] name of the exporting module - useful for debugging.
* *
* Returns, on success, a newly created dma_buf object, which wraps the * Returns, on success, a newly created dma_buf object, which wraps the
* supplied private data and operations for dma_buf_ops. On either missing * supplied private data and operations for dma_buf_ops. On either missing
* ops, or error in allocating struct dma_buf, will return negative error. * ops, or error in allocating struct dma_buf, will return negative error.
* *
*/ */
struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops, struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops,
size_t size, int flags) size_t size, int flags, const char *exp_name)
{ {
struct dma_buf *dmabuf; struct dma_buf *dmabuf;
struct file *file; struct file *file;
...@@ -114,6 +130,7 @@ struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops, ...@@ -114,6 +130,7 @@ struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
dmabuf->priv = priv; dmabuf->priv = priv;
dmabuf->ops = ops; dmabuf->ops = ops;
dmabuf->size = size; dmabuf->size = size;
dmabuf->exp_name = exp_name;
file = anon_inode_getfile("dmabuf", &dma_buf_fops, dmabuf, flags); file = anon_inode_getfile("dmabuf", &dma_buf_fops, dmabuf, flags);
...@@ -122,9 +139,13 @@ struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops, ...@@ -122,9 +139,13 @@ struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
mutex_init(&dmabuf->lock); mutex_init(&dmabuf->lock);
INIT_LIST_HEAD(&dmabuf->attachments); INIT_LIST_HEAD(&dmabuf->attachments);
mutex_lock(&db_list.lock);
list_add(&dmabuf->list_node, &db_list.head);
mutex_unlock(&db_list.lock);
return dmabuf; return dmabuf;
} }
EXPORT_SYMBOL_GPL(dma_buf_export); EXPORT_SYMBOL_GPL(dma_buf_export_named);
/** /**
...@@ -548,3 +569,143 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) ...@@ -548,3 +569,143 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
mutex_unlock(&dmabuf->lock); mutex_unlock(&dmabuf->lock);
} }
EXPORT_SYMBOL_GPL(dma_buf_vunmap); EXPORT_SYMBOL_GPL(dma_buf_vunmap);
#ifdef CONFIG_DEBUG_FS
static int dma_buf_describe(struct seq_file *s)
{
int ret;
struct dma_buf *buf_obj;
struct dma_buf_attachment *attach_obj;
int count = 0, attach_count;
size_t size = 0;
ret = mutex_lock_interruptible(&db_list.lock);
if (ret)
return ret;
seq_printf(s, "\nDma-buf Objects:\n");
seq_printf(s, "\texp_name\tsize\tflags\tmode\tcount\n");
list_for_each_entry(buf_obj, &db_list.head, list_node) {
ret = mutex_lock_interruptible(&buf_obj->lock);
if (ret) {
seq_printf(s,
"\tERROR locking buffer object: skipping\n");
continue;
}
seq_printf(s, "\t");
seq_printf(s, "\t%s\t%08zu\t%08x\t%08x\t%08ld\n",
buf_obj->exp_name, buf_obj->size,
buf_obj->file->f_flags, buf_obj->file->f_mode,
(long)(buf_obj->file->f_count.counter));
seq_printf(s, "\t\tAttached Devices:\n");
attach_count = 0;
list_for_each_entry(attach_obj, &buf_obj->attachments, node) {
seq_printf(s, "\t\t");
seq_printf(s, "%s\n", attach_obj->dev->init_name);
attach_count++;
}
seq_printf(s, "\n\t\tTotal %d devices attached\n",
attach_count);
count++;
size += buf_obj->size;
mutex_unlock(&buf_obj->lock);
}
seq_printf(s, "\nTotal %d objects, %zu bytes\n", count, size);
mutex_unlock(&db_list.lock);
return 0;
}
static int dma_buf_show(struct seq_file *s, void *unused)
{
void (*func)(struct seq_file *) = s->private;
func(s);
return 0;
}
static int dma_buf_debug_open(struct inode *inode, struct file *file)
{
return single_open(file, dma_buf_show, inode->i_private);
}
static const struct file_operations dma_buf_debug_fops = {
.open = dma_buf_debug_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static struct dentry *dma_buf_debugfs_dir;
static int dma_buf_init_debugfs(void)
{
int err = 0;
dma_buf_debugfs_dir = debugfs_create_dir("dma_buf", NULL);
if (IS_ERR(dma_buf_debugfs_dir)) {
err = PTR_ERR(dma_buf_debugfs_dir);
dma_buf_debugfs_dir = NULL;
return err;
}
err = dma_buf_debugfs_create_file("bufinfo", dma_buf_describe);
if (err)
pr_debug("dma_buf: debugfs: failed to create node bufinfo\n");
return err;
}
static void dma_buf_uninit_debugfs(void)
{
if (dma_buf_debugfs_dir)
debugfs_remove_recursive(dma_buf_debugfs_dir);
}
int dma_buf_debugfs_create_file(const char *name,
int (*write)(struct seq_file *))
{
struct dentry *d;
d = debugfs_create_file(name, S_IRUGO, dma_buf_debugfs_dir,
write, &dma_buf_debug_fops);
if (IS_ERR(d))
return PTR_ERR(d);
return 0;
}
#else
static inline int dma_buf_init_debugfs(void)
{
return 0;
}
static inline void dma_buf_uninit_debugfs(void)
{
}
#endif
static int __init dma_buf_init(void)
{
mutex_init(&db_list.lock);
INIT_LIST_HEAD(&db_list.head);
dma_buf_init_debugfs();
return 0;
}
subsys_initcall(dma_buf_init);
static void __exit dma_buf_deinit(void)
{
dma_buf_uninit_debugfs();
}
__exitcall(dma_buf_deinit);
...@@ -112,6 +112,8 @@ struct dma_buf_ops { ...@@ -112,6 +112,8 @@ struct dma_buf_ops {
* @file: file pointer used for sharing buffers across, and for refcounting. * @file: file pointer used for sharing buffers across, and for refcounting.
* @attachments: list of dma_buf_attachment that denotes all devices attached. * @attachments: list of dma_buf_attachment that denotes all devices attached.
* @ops: dma_buf_ops associated with this buffer object. * @ops: dma_buf_ops associated with this buffer object.
* @exp_name: name of the exporter; useful for debugging.
* @list_node: node for dma_buf accounting and debugging.
* @priv: exporter specific private data for this buffer object. * @priv: exporter specific private data for this buffer object.
*/ */
struct dma_buf { struct dma_buf {
...@@ -123,6 +125,8 @@ struct dma_buf { ...@@ -123,6 +125,8 @@ struct dma_buf {
struct mutex lock; struct mutex lock;
unsigned vmapping_counter; unsigned vmapping_counter;
void *vmap_ptr; void *vmap_ptr;
const char *exp_name;
struct list_head list_node;
void *priv; void *priv;
}; };
...@@ -162,8 +166,13 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, ...@@ -162,8 +166,13 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
struct device *dev); struct device *dev);
void dma_buf_detach(struct dma_buf *dmabuf, void dma_buf_detach(struct dma_buf *dmabuf,
struct dma_buf_attachment *dmabuf_attach); struct dma_buf_attachment *dmabuf_attach);
struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
size_t size, int flags); struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops,
size_t size, int flags, const char *);
#define dma_buf_export(priv, ops, size, flags) \
dma_buf_export_named(priv, ops, size, flags, __FILE__)
int dma_buf_fd(struct dma_buf *dmabuf, int flags); int dma_buf_fd(struct dma_buf *dmabuf, int flags);
struct dma_buf *dma_buf_get(int fd); struct dma_buf *dma_buf_get(int fd);
void dma_buf_put(struct dma_buf *dmabuf); void dma_buf_put(struct dma_buf *dmabuf);
...@@ -185,5 +194,6 @@ int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, ...@@ -185,5 +194,6 @@ int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *,
unsigned long); unsigned long);
void *dma_buf_vmap(struct dma_buf *); void *dma_buf_vmap(struct dma_buf *);
void dma_buf_vunmap(struct dma_buf *, void *vaddr); void dma_buf_vunmap(struct dma_buf *, void *vaddr);
int dma_buf_debugfs_create_file(const char *name,
int (*write)(struct seq_file *));
#endif /* __DMA_BUF_H__ */ #endif /* __DMA_BUF_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment