Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b0ca4d01 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
Loading
Loading
Loading
Loading
+11 −2
Original line number Original line Diff line number Diff line
@@ -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
+165 −4
Original line number Original line Diff line number Diff line
@@ -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)
	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)
}
}


/**
/**
 * 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,
	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,
	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)
	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);
+13 −3
Original line number Original line Diff line number Diff line
@@ -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 {
	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,
							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 *,
		 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__ */