3.10 dma-buf updates

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJRgQj+AAoJEAG+/NWsLn5b+ZgP/2To0IUb3hyvcfCEnGytzOu1
 zIkDMyqTYtPy3r+gdZ7LkZYJkJ0NrO9DwWUDcPEY/9mBL0kwOBIgWumUi2ABESQI
 /tuTYzG0MKo5UNRr/aSK5erLSZeSbRht4DE8oiK9mw1O6/mUq5c4J/V+z6AYWC8m
 4cad8+XGU6x1g0a13VIhO8p2OcfV/ZyGwOeHN4SMZhkoHt3Le8wVXYMUDDofmCKs
 lkkCetleQFcHLtwIMRC3SX15mIF57LhicK5JfmvEYvI4ghVu5eKi5B59aGdhG0R9
 p7cKZ10TgDbr2I8gvQNZ/jSKhMCxLeGHeA781YWqJRU/YdvoYltVVOeWH60YZJdF
 K/dwaPsVkE68xVpTO5xieCTY9nSk1q258gQLgPkgThQYuRuPgWwAN/GbaFYGJjew
 vGmpp2F7VZxrVjBO89Rqgp47KWZE9ibEpc4Gb6pg7thqRl/joi6sosP0zGUApnFT
 fJSKMvXgNGDk6r8b5F2EYKTeLAHDuQ+FqzZeZ1+B/IOEwmyUosqslUlhmEVXqawW
 CUMO0MkimIfv7stPcgx/v7e3lQDz/8EGI8NBjJIipkeF+Fo39bUt4MA56SVp/lBC
 YyPokFjZGcqtADKHxZzNYTpGx/9NTMCDR510qhqITWQXd+e6ygbmLUgwdOOiBlQM
 gQDdPh29sPULSad37tbr
 =VZTM
 -----END PGP SIGNATURE-----

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()
This commit is contained in:
Linus Torvalds 2013-05-01 07:44:37 -07:00
commit b0ca4d0123
3 changed files with 189 additions and 9 deletions

View file

@ -52,14 +52,23 @@ The dma_buf buffer sharing API usage contains the following steps:
associated with this buffer.
Interface:
struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
size_t size, int flags)
struct dma_buf *dma_buf_export_named(void *priv, struct dma_buf_ops *ops,
size_t size, int flags,
const char *exp_name)
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,
so it can be exported. On failure to allocate the dma_buf object, it returns
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
Userspace entity requests for a file-descriptor (fd) which is a handle to the

View file

@ -27,9 +27,18 @@
#include <linux/dma-buf.h>
#include <linux/anon_inodes.h>
#include <linux/export.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
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)
{
struct dma_buf *dmabuf;
@ -42,6 +51,11 @@ static int dma_buf_release(struct inode *inode, struct file *file)
BUG_ON(dmabuf->vmapping_counter);
dmabuf->ops->release(dmabuf);
mutex_lock(&db_list.lock);
list_del(&dmabuf->list_node);
mutex_unlock(&db_list.lock);
kfree(dmabuf);
return 0;
}
@ -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.
* 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
* @ops: [in] Attach allocator-defined dma buf ops to the new buffer.
* @size: [in] Size of the buffer
* @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
* supplied private data and operations for dma_buf_ops. On either missing
* 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,
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 *exp_name)
{
struct dma_buf *dmabuf;
struct file *file;
@ -114,6 +130,7 @@ struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
dmabuf->priv = priv;
dmabuf->ops = ops;
dmabuf->size = size;
dmabuf->exp_name = exp_name;
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,
mutex_init(&dmabuf->lock);
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;
}
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)
mutex_unlock(&dmabuf->lock);
}
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);

View file

@ -112,6 +112,8 @@ struct dma_buf_ops {
* @file: file pointer used for sharing buffers across, and for refcounting.
* @attachments: list of dma_buf_attachment that denotes all devices attached.
* @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.
*/
struct dma_buf {
@ -123,6 +125,8 @@ struct dma_buf {
struct mutex lock;
unsigned vmapping_counter;
void *vmap_ptr;
const char *exp_name;
struct list_head list_node;
void *priv;
};
@ -162,8 +166,13 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
struct device *dev);
void dma_buf_detach(struct dma_buf *dmabuf,
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);
struct dma_buf *dma_buf_get(int fd);
void dma_buf_put(struct dma_buf *dmabuf);
@ -185,5 +194,6 @@ int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *,
unsigned long);
void *dma_buf_vmap(struct dma_buf *);
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__ */