/drivers/gpu/ion/ion.c
C | 1186 lines | 941 code | 151 blank | 94 comment | 129 complexity | f334c5f289f4de1c8a149e66a032bc2d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
- /*
- * drivers/gpu/ion/ion.c
- *
- * Copyright (C) 2011 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
- #include <linux/device.h>
- #include <linux/file.h>
- #include <linux/fs.h>
- #include <linux/anon_inodes.h>
- #include <linux/ion.h>
- #include <linux/list.h>
- #include <linux/miscdevice.h>
- #include <linux/mm.h>
- #include <linux/mm_types.h>
- #include <linux/rbtree.h>
- #include <linux/sched.h>
- #include <linux/slab.h>
- #include <linux/seq_file.h>
- #include <linux/uaccess.h>
- #include <linux/debugfs.h>
- #include "ion_priv.h"
- #define DEBUG
- /**
- * struct ion_device - the metadata of the ion device node
- * @dev: the actual misc device
- * @buffers: an rb tree of all the existing buffers
- * @lock: lock protecting the buffers & heaps trees
- * @heaps: list of all the heaps in the system
- * @user_clients: list of all the clients created from userspace
- */
- struct ion_device {
- struct miscdevice dev;
- struct rb_root buffers;
- struct mutex lock;
- struct rb_root heaps;
- long (*custom_ioctl) (struct ion_client *client, unsigned int cmd,
- unsigned long arg);
- struct rb_root user_clients;
- struct rb_root kernel_clients;
- struct dentry *debug_root;
- };
- /**
- * struct ion_client - a process/hw block local address space
- * @ref: for reference counting the client
- * @node: node in the tree of all clients
- * @dev: backpointer to ion device
- * @handles: an rb tree of all the handles in this client
- * @lock: lock protecting the tree of handles
- * @heap_mask: mask of all supported heaps
- * @name: used for debugging
- * @task: used for debugging
- *
- * A client represents a list of buffers this client may access.
- * The mutex stored here is used to protect both handles tree
- * as well as the handles themselves, and should be held while modifying either.
- */
- struct ion_client {
- struct kref ref;
- struct rb_node node;
- struct ion_device *dev;
- struct rb_root handles;
- struct mutex lock;
- unsigned int heap_mask;
- const char *name;
- struct task_struct *task;
- pid_t pid;
- struct dentry *debug_root;
- };
- /**
- * ion_handle - a client local reference to a buffer
- * @ref: reference count
- * @client: back pointer to the client the buffer resides in
- * @buffer: pointer to the buffer
- * @node: node in the client's handle rbtree
- * @kmap_cnt: count of times this client has mapped to kernel
- * @dmap_cnt: count of times this client has mapped for dma
- * @usermap_cnt: count of times this client has mapped for userspace
- *
- * Modifications to node, map_cnt or mapping should be protected by the
- * lock in the client. Other fields are never changed after initialization.
- */
- struct ion_handle {
- struct kref ref;
- struct ion_client *client;
- struct ion_buffer *buffer;
- struct rb_node node;
- unsigned int kmap_cnt;
- unsigned int dmap_cnt;
- unsigned int usermap_cnt;
- };
- /* this function should only be called while dev->lock is held */
- static void ion_buffer_add(struct ion_device *dev,
- struct ion_buffer *buffer)
- {
- struct rb_node **p = &dev->buffers.rb_node;
- struct rb_node *parent = NULL;
- struct ion_buffer *entry;
- while (*p) {
- parent = *p;
- entry = rb_entry(parent, struct ion_buffer, node);
- if (buffer < entry) {
- p = &(*p)->rb_left;
- } else if (buffer > entry) {
- p = &(*p)->rb_right;
- } else {
- pr_err("%s: buffer already found.", __func__);
- BUG();
- }
- }
- rb_link_node(&buffer->node, parent, p);
- rb_insert_color(&buffer->node, &dev->buffers);
- }
- /* this function should only be called while dev->lock is held */
- static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
- struct ion_device *dev,
- unsigned long len,
- unsigned long align,
- unsigned long flags)
- {
- struct ion_buffer *buffer;
- int ret;
- buffer = kzalloc(sizeof(struct ion_buffer), GFP_KERNEL);
- if (!buffer)
- return ERR_PTR(-ENOMEM);
- buffer->heap = heap;
- kref_init(&buffer->ref);
- ret = heap->ops->allocate(heap, buffer, len, align, flags);
- if (ret) {
- kfree(buffer);
- return ERR_PTR(ret);
- }
- buffer->dev = dev;
- buffer->size = len;
- mutex_init(&buffer->lock);
- ion_buffer_add(dev, buffer);
- return buffer;
- }
- static void ion_buffer_destroy(struct kref *kref)
- {
- struct ion_buffer *buffer = container_of(kref, struct ion_buffer, ref);
- struct ion_device *dev = buffer->dev;
- buffer->heap->ops->free(buffer);
- mutex_lock(&dev->lock);
- rb_erase(&buffer->node, &dev->buffers);
- mutex_unlock(&dev->lock);
- kfree(buffer);
- }
- static void ion_buffer_get(struct ion_buffer *buffer)
- {
- kref_get(&buffer->ref);
- }
- static int ion_buffer_put(struct ion_buffer *buffer)
- {
- return kref_put(&buffer->ref, ion_buffer_destroy);
- }
- static struct ion_handle *ion_handle_create(struct ion_client *client,
- struct ion_buffer *buffer)
- {
- struct ion_handle *handle;
- handle = kzalloc(sizeof(struct ion_handle), GFP_KERNEL);
- if (!handle)
- return ERR_PTR(-ENOMEM);
- kref_init(&handle->ref);
- rb_init_node(&handle->node);
- handle->client = client;
- ion_buffer_get(buffer);
- handle->buffer = buffer;
- return handle;
- }
- static void ion_handle_destroy(struct kref *kref)
- {
- struct ion_handle *handle = container_of(kref, struct ion_handle, ref);
- /* XXX Can a handle be destroyed while it's map count is non-zero?:
- if (handle->map_cnt) unmap
- */
- ion_buffer_put(handle->buffer);
- mutex_lock(&handle->client->lock);
- if (!RB_EMPTY_NODE(&handle->node))
- rb_erase(&handle->node, &handle->client->handles);
- mutex_unlock(&handle->client->lock);
- kfree(handle);
- }
- struct ion_buffer *ion_handle_buffer(struct ion_handle *handle)
- {
- return handle->buffer;
- }
- static void ion_handle_get(struct ion_handle *handle)
- {
- kref_get(&handle->ref);
- }
- static int ion_handle_put(struct ion_handle *handle)
- {
- return kref_put(&handle->ref, ion_handle_destroy);
- }
- static struct ion_handle *ion_handle_lookup(struct ion_client *client,
- struct ion_buffer *buffer)
- {
- struct rb_node *n;
- for (n = rb_first(&client->handles); n; n = rb_next(n)) {
- struct ion_handle *handle = rb_entry(n, struct ion_handle,
- node);
- if (handle->buffer == buffer)
- return handle;
- }
- return NULL;
- }
- static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
- {
- struct rb_node *n = client->handles.rb_node;
-