diff options
Diffstat (limited to 'drivers/staging/android/ion/ion.c')
-rw-r--r-- | drivers/staging/android/ion/ion.c | 388 |
1 files changed, 67 insertions, 321 deletions
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index a2cf93b59016..396ded52ab70 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -41,80 +41,6 @@ #include "ion_priv.h" #include "compat_ion.h" -/** - * struct ion_device - the metadata of the ion device node - * @dev: the actual misc device - * @buffers: an rb tree of all the existing buffers - * @buffer_lock: lock protecting the tree of buffers - * @lock: rwsem protecting the tree of heaps and clients - * @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 buffer_lock; - struct rw_semaphore lock; - struct plist_head heaps; - long (*custom_ioctl)(struct ion_client *client, unsigned int cmd, - unsigned long arg); - struct rb_root clients; - struct dentry *debug_root; - struct dentry *heaps_debug_root; - struct dentry *clients_debug_root; -}; - -/** - * struct ion_client - a process/hw block local address space - * @node: node in the tree of all clients - * @dev: backpointer to ion device - * @handles: an rb tree of all the handles in this client - * @idr: an idr space for allocating handle ids - * @lock: lock protecting the tree of handles - * @name: used for debugging - * @display_name: used for debugging (unique version of @name) - * @display_serial: used for debugging (to make display_name unique) - * @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 rb_node node; - struct ion_device *dev; - struct rb_root handles; - struct idr idr; - struct mutex lock; - const char *name; - char *display_name; - int display_serial; - 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 - * @id: client-unique id allocated by client->idr - * - * 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; - int id; -}; - bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer) { return (buffer->flags & ION_FLAG_CACHED) && @@ -174,10 +100,10 @@ static void ion_buffer_add(struct ion_device *dev, /* 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_device *dev, + unsigned long len, + unsigned long align, + unsigned long flags) { struct ion_buffer *buffer; struct sg_table *table; @@ -205,19 +131,16 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, goto err2; } - buffer->dev = dev; - buffer->size = len; - - table = heap->ops->map_dma(heap, buffer); - if (WARN_ONCE(table == NULL, - "heap->ops->map_dma should return ERR_PTR on error")) - table = ERR_PTR(-EINVAL); - if (IS_ERR(table)) { + if (buffer->sg_table == NULL) { + WARN_ONCE(1, "This heap needs to set the sgtable"); ret = -EINVAL; goto err1; } - buffer->sg_table = table; + table = buffer->sg_table; + buffer->dev = dev; + buffer->size = len; + if (ion_buffer_fault_user_mappings(buffer)) { int num_pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; struct scatterlist *sg; @@ -226,7 +149,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, buffer->pages = vmalloc(sizeof(struct page *) * num_pages); if (!buffer->pages) { ret = -ENOMEM; - goto err; + goto err1; } for_each_sg(table->sgl, sg, table->nents, i) { @@ -260,8 +183,6 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, mutex_unlock(&dev->buffer_lock); return buffer; -err: - heap->ops->unmap_dma(heap, buffer); err1: heap->ops->free(buffer); err2: @@ -273,7 +194,6 @@ void ion_buffer_destroy(struct ion_buffer *buffer) { if (WARN_ON(buffer->kmap_cnt > 0)) buffer->heap->ops->unmap_kernel(buffer->heap, buffer); - buffer->heap->ops->unmap_dma(buffer->heap, buffer); buffer->heap->ops->free(buffer); vfree(buffer->pages); kfree(buffer); @@ -337,7 +257,7 @@ static void ion_buffer_remove_from_handle(struct ion_buffer *buffer) } static struct ion_handle *ion_handle_create(struct ion_client *client, - struct ion_buffer *buffer) + struct ion_buffer *buffer) { struct ion_handle *handle; @@ -377,26 +297,17 @@ static void ion_handle_destroy(struct kref *kref) 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_nolock(struct ion_handle *handle) +int ion_handle_put_nolock(struct ion_handle *handle) { - int ret; - - ret = kref_put(&handle->ref, ion_handle_destroy); - - return ret; + return kref_put(&handle->ref, ion_handle_destroy); } -static int ion_handle_put(struct ion_handle *handle) +int ion_handle_put(struct ion_handle *handle) { struct ion_client *client = handle->client; int ret; @@ -426,8 +337,8 @@ static struct ion_handle *ion_handle_lookup(struct ion_client *client, return ERR_PTR(-EINVAL); } -static struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, - int id) +struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, + int id) { struct ion_handle *handle; @@ -438,7 +349,7 @@ static struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, return handle ? handle : ERR_PTR(-EINVAL); } -static struct ion_handle *ion_handle_get_by_id(struct ion_client *client, +struct ion_handle *ion_handle_get_by_id(struct ion_client *client, int id) { struct ion_handle *handle; @@ -551,15 +462,10 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, } EXPORT_SYMBOL(ion_alloc); -static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle) +void ion_free_nolock(struct ion_client *client, + struct ion_handle *handle) { - bool valid_handle; - - BUG_ON(client != handle->client); - - valid_handle = ion_handle_validate(client, handle); - - if (!valid_handle) { + if (!ion_handle_validate(client, handle)) { WARN(1, "%s: invalid handle passed to free.\n", __func__); return; } @@ -576,32 +482,6 @@ void ion_free(struct ion_client *client, struct ion_handle *handle) } EXPORT_SYMBOL(ion_free); -int ion_phys(struct ion_client *client, struct ion_handle *handle, - ion_phys_addr_t *addr, size_t *len) -{ - struct ion_buffer *buffer; - int ret; - - mutex_lock(&client->lock); - if (!ion_handle_validate(client, handle)) { - mutex_unlock(&client->lock); - return -EINVAL; - } - - buffer = handle->buffer; - - if (!buffer->heap->ops->phys) { - pr_err("%s: ion_phys is not implemented by this heap (name=%s, type=%d).\n", - __func__, buffer->heap->name, buffer->heap->type); - mutex_unlock(&client->lock); - return -ENODEV; - } - mutex_unlock(&client->lock); - ret = buffer->heap->ops->phys(buffer->heap, buffer, addr, len); - return ret; -} -EXPORT_SYMBOL(ion_phys); - static void *ion_buffer_kmap_get(struct ion_buffer *buffer) { void *vaddr; @@ -612,7 +492,7 @@ static void *ion_buffer_kmap_get(struct ion_buffer *buffer) } vaddr = buffer->heap->ops->map_kernel(buffer->heap, buffer); if (WARN_ONCE(vaddr == NULL, - "heap->ops->map_kernel should return ERR_PTR on error")) + "heap->ops->map_kernel should return ERR_PTR on error")) return ERR_PTR(-EINVAL); if (IS_ERR(vaddr)) return vaddr; @@ -781,14 +661,14 @@ static const struct file_operations debug_client_fops = { }; static int ion_get_client_serial(const struct rb_root *root, - const unsigned char *name) + const unsigned char *name) { int serial = -1; struct rb_node *node; for (node = rb_first(root); node; node = rb_next(node)) { struct ion_client *client = rb_entry(node, struct ion_client, - node); + node); if (strcmp(client->name, name)) continue; @@ -863,14 +743,14 @@ struct ion_client *ion_client_create(struct ion_device *dev, rb_insert_color(&client->node, &dev->clients); client->debug_root = debugfs_create_file(client->display_name, 0664, - dev->clients_debug_root, - client, &debug_client_fops); + dev->clients_debug_root, + client, &debug_client_fops); if (!client->debug_root) { char buf[256], *path; path = dentry_path(dev->clients_debug_root, buf, 256); pr_err("Failed to create client debugfs at %s/%s\n", - path, client->display_name); + path, client->display_name); } up_write(&dev->lock); @@ -917,26 +797,6 @@ void ion_client_destroy(struct ion_client *client) } EXPORT_SYMBOL(ion_client_destroy); -struct sg_table *ion_sg_table(struct ion_client *client, - struct ion_handle *handle) -{ - struct ion_buffer *buffer; - struct sg_table *table; - - mutex_lock(&client->lock); - if (!ion_handle_validate(client, handle)) { - pr_err("%s: invalid handle passed to map_dma.\n", - __func__); - mutex_unlock(&client->lock); - return ERR_PTR(-EINVAL); - } - buffer = handle->buffer; - table = buffer->sg_table; - mutex_unlock(&client->lock); - return table; -} -EXPORT_SYMBOL(ion_sg_table); - static void ion_buffer_sync_for_device(struct ion_buffer *buffer, struct device *dev, enum dma_data_direction direction); @@ -958,7 +818,7 @@ static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment, } void ion_pages_sync_for_device(struct device *dev, struct page *page, - size_t size, enum dma_data_direction dir) + size_t size, enum dma_data_direction dir) { struct scatterlist sg; @@ -998,7 +858,7 @@ static void ion_buffer_sync_for_device(struct ion_buffer *buffer, if (ion_buffer_page_is_dirty(page)) ion_pages_sync_for_device(dev, ion_buffer_page(page), - PAGE_SIZE, dir); + PAGE_SIZE, dir); ion_buffer_page_clean(buffer->pages + i); } @@ -1076,7 +936,7 @@ static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) if (!buffer->heap->ops->map_user) { pr_err("%s: this heap does not define a method for mapping to userspace\n", - __func__); + __func__); return -EINVAL; } @@ -1167,7 +1027,7 @@ static struct dma_buf_ops dma_buf_ops = { }; struct dma_buf *ion_share_dma_buf(struct ion_client *client, - struct ion_handle *handle) + struct ion_handle *handle) { DEFINE_DMA_BUF_EXPORT_INFO(exp_info); struct ion_buffer *buffer; @@ -1275,7 +1135,7 @@ struct ion_handle *ion_import_dma_buf_fd(struct ion_client *client, int fd) } EXPORT_SYMBOL(ion_import_dma_buf_fd); -static int ion_sync_for_device(struct ion_client *client, int fd) +int ion_sync_for_device(struct ion_client *client, int fd) { struct dma_buf *dmabuf; struct ion_buffer *buffer; @@ -1299,124 +1159,45 @@ static int ion_sync_for_device(struct ion_client *client, int fd) return 0; } -/* fix up the cases where the ioctl direction bits are incorrect */ -static unsigned int ion_ioctl_dir(unsigned int cmd) -{ - switch (cmd) { - case ION_IOC_SYNC: - case ION_IOC_FREE: - case ION_IOC_CUSTOM: - return _IOC_WRITE; - default: - return _IOC_DIR(cmd); - } -} - -static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +int ion_query_heaps(struct ion_client *client, struct ion_heap_query *query) { - struct ion_client *client = filp->private_data; struct ion_device *dev = client->dev; - struct ion_handle *cleanup_handle = NULL; - int ret = 0; - unsigned int dir; - - union { - struct ion_fd_data fd; - struct ion_allocation_data allocation; - struct ion_handle_data handle; - struct ion_custom_data custom; - } data; + struct ion_heap_data __user *buffer = u64_to_user_ptr(query->heaps); + int ret = -EINVAL, cnt = 0, max_cnt; + struct ion_heap *heap; + struct ion_heap_data hdata; - dir = ion_ioctl_dir(cmd); + memset(&hdata, 0, sizeof(hdata)); - if (_IOC_SIZE(cmd) > sizeof(data)) - return -EINVAL; + down_read(&dev->lock); + if (!buffer) { + query->cnt = dev->heap_cnt; + ret = 0; + goto out; + } - if (dir & _IOC_WRITE) - if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd))) - return -EFAULT; + if (query->cnt <= 0) + goto out; - switch (cmd) { - case ION_IOC_ALLOC: - { - struct ion_handle *handle; + max_cnt = query->cnt; - handle = ion_alloc(client, data.allocation.len, - data.allocation.align, - data.allocation.heap_id_mask, - data.allocation.flags); - if (IS_ERR(handle)) - return PTR_ERR(handle); + plist_for_each_entry(heap, &dev->heaps, node) { + strncpy(hdata.name, heap->name, MAX_HEAP_NAME); + hdata.name[sizeof(hdata.name) - 1] = '\0'; + hdata.type = heap->type; + hdata.heap_id = heap->id; - data.allocation.handle = handle->id; + ret = copy_to_user(&buffer[cnt], + &hdata, sizeof(hdata)); - cleanup_handle = handle; - break; - } - case ION_IOC_FREE: - { - struct ion_handle *handle; - - mutex_lock(&client->lock); - handle = ion_handle_get_by_id_nolock(client, data.handle.handle); - if (IS_ERR(handle)) { - mutex_unlock(&client->lock); - return PTR_ERR(handle); - } - ion_free_nolock(client, handle); - ion_handle_put_nolock(handle); - mutex_unlock(&client->lock); - break; - } - case ION_IOC_SHARE: - case ION_IOC_MAP: - { - struct ion_handle *handle; - - handle = ion_handle_get_by_id(client, data.handle.handle); - if (IS_ERR(handle)) - return PTR_ERR(handle); - data.fd.fd = ion_share_dma_buf_fd(client, handle); - ion_handle_put(handle); - if (data.fd.fd < 0) - ret = data.fd.fd; - break; - } - case ION_IOC_IMPORT: - { - struct ion_handle *handle; - - handle = ion_import_dma_buf_fd(client, data.fd.fd); - if (IS_ERR(handle)) - ret = PTR_ERR(handle); - else - data.handle.handle = handle->id; - break; - } - case ION_IOC_SYNC: - { - ret = ion_sync_for_device(client, data.fd.fd); - break; - } - case ION_IOC_CUSTOM: - { - if (!dev->custom_ioctl) - return -ENOTTY; - ret = dev->custom_ioctl(client, data.custom.cmd, - data.custom.arg); - break; - } - default: - return -ENOTTY; + cnt++; + if (cnt >= max_cnt) + break; } - if (dir & _IOC_READ) { - if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) { - if (cleanup_handle) - ion_free(client, cleanup_handle); - return -EFAULT; - } - } + query->cnt = cnt; +out: + up_read(&dev->lock); return ret; } @@ -1528,7 +1309,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) seq_printf(s, "%16s %16zu\n", "total ", total_size); if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) seq_printf(s, "%16s %16zu\n", "deferred free", - heap->free_list_size); + heap->free_list_size); seq_puts(s, "----------------------------------------------------\n"); if (heap->debug_show) @@ -1588,8 +1369,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) { struct dentry *debug_file; - if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma || - !heap->ops->unmap_dma) + if (!heap->ops->allocate || !heap->ops->free) pr_err("%s: can not add heap with invalid ops struct.\n", __func__); @@ -1611,15 +1391,15 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) plist_node_init(&heap->node, -heap->id); plist_add(&heap->node, &dev->heaps); debug_file = debugfs_create_file(heap->name, 0664, - dev->heaps_debug_root, heap, - &debug_heap_fops); + dev->heaps_debug_root, heap, + &debug_heap_fops); if (!debug_file) { char buf[256], *path; path = dentry_path(dev->heaps_debug_root, buf, 256); pr_err("Failed to create heap debugfs at %s/%s\n", - path, heap->name); + path, heap->name); } if (heap->shrinker.count_objects && heap->shrinker.scan_objects) { @@ -1634,10 +1414,11 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) path = dentry_path(dev->heaps_debug_root, buf, 256); pr_err("Failed to create heap shrinker debugfs at %s/%s\n", - path, debug_name); + path, debug_name); } } + dev->heap_cnt++; up_write(&dev->lock); } EXPORT_SYMBOL(ion_device_add_heap); @@ -1702,38 +1483,3 @@ void ion_device_destroy(struct ion_device *dev) kfree(dev); } EXPORT_SYMBOL(ion_device_destroy); - -void __init ion_reserve(struct ion_platform_data *data) -{ - int i; - - for (i = 0; i < data->nr; i++) { - if (data->heaps[i].size == 0) - continue; - - if (data->heaps[i].base == 0) { - phys_addr_t paddr; - - paddr = memblock_alloc_base(data->heaps[i].size, - data->heaps[i].align, - MEMBLOCK_ALLOC_ANYWHERE); - if (!paddr) { - pr_err("%s: error allocating memblock for heap %d\n", - __func__, i); - continue; - } - data->heaps[i].base = paddr; - } else { - int ret = memblock_reserve(data->heaps[i].base, - data->heaps[i].size); - if (ret) - pr_err("memblock reserve of %zx@%lx failed\n", - data->heaps[i].size, - data->heaps[i].base); - } - pr_info("%s: %s reserved base %lx size %zu\n", __func__, - data->heaps[i].name, - data->heaps[i].base, - data->heaps[i].size); - } -} |