Loading drivers/staging/android/ion/Kconfig +6 −10 Original line number Diff line number Diff line Loading @@ -36,19 +36,15 @@ config ION_TEGRA config ION_HISI tristate "Ion for Hisilicon" depends on ARCH_HISI && ION select ION_OF help Choose this option if you wish to use ion on Hisilicon Platform. source "drivers/staging/android/ion/hisilicon/Kconfig" config ION_OF bool "Devicetree support for Ion" depends on ION && OF_ADDRESS config ION_POOL_CACHE_POLICY bool "Ion set page pool cache policy" depends on ION && X86 default y if X86 help Provides base support for defining Ion heaps in devicetree and setting them up. Also includes functions for platforms to parse the devicetree and expand for their own custom extensions If using Ion and devicetree, you should say Y here Choose this option if need to explicity set cache policy of the pages in the page pool. drivers/staging/android/ion/Makefile +1 −3 Original line number Diff line number Diff line obj-$(CONFIG_ION) += ion.o ion-ioctl.o ion_heap.o \ ion_page_pool.o ion_system_heap.o \ obj-$(CONFIG_ION) += ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \ ion_carveout_heap.o ion_chunk_heap.o ion_cma_heap.o obj-$(CONFIG_ION_TEST) += ion_test.o ifdef CONFIG_COMPAT Loading @@ -9,5 +8,4 @@ endif obj-$(CONFIG_ION_DUMMY) += ion_dummy_driver.o obj-$(CONFIG_ION_TEGRA) += tegra/ obj-$(CONFIG_ION_HISI) += hisilicon/ obj-$(CONFIG_ION_OF) += ion_of.o drivers/staging/android/ion/ion.c +325 −67 Original line number Diff line number Diff line Loading @@ -41,6 +41,82 @@ #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; /* Protects rb_tree */ 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; /* Protects 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) && Loading Loading @@ -131,16 +207,19 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, goto err2; } if (buffer->sg_table == NULL) { WARN_ONCE(1, "This heap needs to set the sgtable"); buffer->dev = dev; buffer->size = len; table = heap->ops->map_dma(heap, buffer); if (WARN_ONCE(!table, "heap->ops->map_dma should return ERR_PTR on error")) table = ERR_PTR(-EINVAL); if (IS_ERR(table)) { ret = -EINVAL; goto err1; } table = buffer->sg_table; buffer->dev = dev; buffer->size = len; buffer->sg_table = table; if (ion_buffer_fault_user_mappings(buffer)) { int num_pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; struct scatterlist *sg; Loading @@ -149,7 +228,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 err1; goto err; } for_each_sg(table->sgl, sg, table->nents, i) { Loading Loading @@ -183,6 +262,8 @@ 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: Loading @@ -194,6 +275,7 @@ 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); Loading Loading @@ -297,17 +379,26 @@ 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); } int ion_handle_put_nolock(struct ion_handle *handle) static int ion_handle_put_nolock(struct ion_handle *handle) { return kref_put(&handle->ref, ion_handle_destroy); int ret; ret = kref_put(&handle->ref, ion_handle_destroy); return ret; } int ion_handle_put(struct ion_handle *handle) static int ion_handle_put(struct ion_handle *handle) { struct ion_client *client = handle->client; int ret; Loading Loading @@ -337,7 +428,7 @@ static struct ion_handle *ion_handle_lookup(struct ion_client *client, return ERR_PTR(-EINVAL); } struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, static struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, int id) { struct ion_handle *handle; Loading @@ -349,7 +440,7 @@ struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, return handle ? handle : ERR_PTR(-EINVAL); } struct ion_handle *ion_handle_get_by_id(struct ion_client *client, static struct ion_handle *ion_handle_get_by_id(struct ion_client *client, int id) { struct ion_handle *handle; Loading Loading @@ -462,10 +553,16 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, } EXPORT_SYMBOL(ion_alloc); void ion_free_nolock(struct ion_client *client, static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle) { if (!ion_handle_validate(client, handle)) { bool valid_handle; WARN_ON(client != handle->client); valid_handle = ion_handle_validate(client, handle); if (!valid_handle) { WARN(1, "%s: invalid handle passed to free.\n", __func__); return; } Loading @@ -482,6 +579,32 @@ 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; Loading Loading @@ -797,6 +920,26 @@ 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); Loading Loading @@ -1135,7 +1278,7 @@ struct ion_handle *ion_import_dma_buf_fd(struct ion_client *client, int fd) } EXPORT_SYMBOL(ion_import_dma_buf_fd); int ion_sync_for_device(struct ion_client *client, int fd) static int ion_sync_for_device(struct ion_client *client, int fd) { struct dma_buf *dmabuf; struct ion_buffer *buffer; Loading @@ -1159,45 +1302,125 @@ int ion_sync_for_device(struct ion_client *client, int fd) return 0; } int ion_query_heaps(struct ion_client *client, struct ion_heap_query *query) /* 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) { struct ion_client *client = filp->private_data; struct ion_device *dev = client->dev; 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; struct ion_handle *cleanup_handle = NULL; int ret = 0; unsigned int dir; memset(&hdata, 0, sizeof(hdata)); union { struct ion_fd_data fd; struct ion_allocation_data allocation; struct ion_handle_data handle; struct ion_custom_data custom; } data; down_read(&dev->lock); if (!buffer) { query->cnt = dev->heap_cnt; ret = 0; goto out; } dir = ion_ioctl_dir(cmd); if (query->cnt <= 0) goto out; if (_IOC_SIZE(cmd) > sizeof(data)) return -EINVAL; max_cnt = query->cnt; if (dir & _IOC_WRITE) if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd))) return -EFAULT; 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; switch (cmd) { case ION_IOC_ALLOC: { struct ion_handle *handle; ret = copy_to_user(&buffer[cnt], &hdata, sizeof(hdata)); 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); cnt++; if (cnt >= max_cnt) data.allocation.handle = handle->id; cleanup_handle = handle; break; } case ION_IOC_FREE: { struct ion_handle *handle; query->cnt = cnt; out: up_read(&dev->lock); 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; } 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; } } return ret; } Loading Loading @@ -1369,7 +1592,8 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) { struct dentry *debug_file; if (!heap->ops->allocate || !heap->ops->free) if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma || !heap->ops->unmap_dma) pr_err("%s: can not add heap with invalid ops struct.\n", __func__); Loading Loading @@ -1418,7 +1642,6 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) } } dev->heap_cnt++; up_write(&dev->lock); } EXPORT_SYMBOL(ion_device_add_heap); Loading Loading @@ -1483,3 +1706,38 @@ 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); } } drivers/staging/android/ion/ion.h +41 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,17 @@ struct ion_platform_data { struct ion_platform_heap *heaps; }; /** * ion_reserve() - reserve memory for ion heaps if applicable * @data: platform data specifying starting physical address and * size * * Calls memblock reserve to set aside memory for heaps that are * located at specific memory addresses or of specific sizes not * managed by the kernel */ void ion_reserve(struct ion_platform_data *data); /** * ion_client_create() - allocate a client and returns it * @dev: the global ion device Loading Loading @@ -118,6 +129,36 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, */ void ion_free(struct ion_client *client, struct ion_handle *handle); /** * ion_phys - returns the physical address and len of a handle * @client: the client * @handle: the handle * @addr: a pointer to put the address in * @len: a pointer to put the length in * * This function queries the heap for a particular handle to get the * handle's physical address. It't output is only correct if * a heap returns physically contiguous memory -- in other cases * this api should not be implemented -- ion_sg_table should be used * instead. Returns -EINVAL if the handle is invalid. This has * no implications on the reference counting of the handle -- * the returned value may not be valid if the caller is not * holding a reference. */ int ion_phys(struct ion_client *client, struct ion_handle *handle, ion_phys_addr_t *addr, size_t *len); /** * ion_map_dma - return an sg_table describing a handle * @client: the client * @handle: the handle * * This function returns the sg_table describing * a particular ion handle. */ struct sg_table *ion_sg_table(struct ion_client *client, struct ion_handle *handle); /** * ion_map_kernel - create mapping for the given handle * @client: the client Loading drivers/staging/android/ion/ion_carveout_heap.c +34 −9 Original line number Diff line number Diff line Loading @@ -25,15 +25,13 @@ #include "ion.h" #include "ion_priv.h" #define ION_CARVEOUT_ALLOCATE_FAIL -1 struct ion_carveout_heap { struct ion_heap heap; struct gen_pool *pool; ion_phys_addr_t base; }; static ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap, ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap, unsigned long size, unsigned long align) { Loading @@ -47,7 +45,7 @@ static ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap, return offset; } static void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, unsigned long size) { struct ion_carveout_heap *carveout_heap = Loading @@ -58,6 +56,19 @@ static void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, gen_pool_free(carveout_heap->pool, addr, size); } static int ion_carveout_heap_phys(struct ion_heap *heap, struct ion_buffer *buffer, ion_phys_addr_t *addr, size_t *len) { struct sg_table *table = buffer->priv_virt; struct page *page = sg_page(table->sgl); ion_phys_addr_t paddr = PFN_PHYS(page_to_pfn(page)); *addr = paddr; *len = buffer->size; return 0; } static int ion_carveout_heap_allocate(struct ion_heap *heap, struct ion_buffer *buffer, unsigned long size, unsigned long align, Loading @@ -84,7 +95,7 @@ static int ion_carveout_heap_allocate(struct ion_heap *heap, } sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(paddr)), size, 0); buffer->sg_table = table; buffer->priv_virt = table; return 0; Loading @@ -98,7 +109,7 @@ static int ion_carveout_heap_allocate(struct ion_heap *heap, static void ion_carveout_heap_free(struct ion_buffer *buffer) { struct ion_heap *heap = buffer->heap; struct sg_table *table = buffer->sg_table; struct sg_table *table = buffer->priv_virt; struct page *page = sg_page(table->sgl); ion_phys_addr_t paddr = PFN_PHYS(page_to_pfn(page)); Loading @@ -113,9 +124,23 @@ static void ion_carveout_heap_free(struct ion_buffer *buffer) kfree(table); } static struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap, struct ion_buffer *buffer) { return buffer->priv_virt; } static void ion_carveout_heap_unmap_dma(struct ion_heap *heap, struct ion_buffer *buffer) { } static struct ion_heap_ops carveout_heap_ops = { .allocate = ion_carveout_heap_allocate, .free = ion_carveout_heap_free, .phys = ion_carveout_heap_phys, .map_dma = ion_carveout_heap_map_dma, .unmap_dma = ion_carveout_heap_unmap_dma, .map_user = ion_heap_map_user, .map_kernel = ion_heap_map_kernel, .unmap_kernel = ion_heap_unmap_kernel, Loading Loading
drivers/staging/android/ion/Kconfig +6 −10 Original line number Diff line number Diff line Loading @@ -36,19 +36,15 @@ config ION_TEGRA config ION_HISI tristate "Ion for Hisilicon" depends on ARCH_HISI && ION select ION_OF help Choose this option if you wish to use ion on Hisilicon Platform. source "drivers/staging/android/ion/hisilicon/Kconfig" config ION_OF bool "Devicetree support for Ion" depends on ION && OF_ADDRESS config ION_POOL_CACHE_POLICY bool "Ion set page pool cache policy" depends on ION && X86 default y if X86 help Provides base support for defining Ion heaps in devicetree and setting them up. Also includes functions for platforms to parse the devicetree and expand for their own custom extensions If using Ion and devicetree, you should say Y here Choose this option if need to explicity set cache policy of the pages in the page pool.
drivers/staging/android/ion/Makefile +1 −3 Original line number Diff line number Diff line obj-$(CONFIG_ION) += ion.o ion-ioctl.o ion_heap.o \ ion_page_pool.o ion_system_heap.o \ obj-$(CONFIG_ION) += ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \ ion_carveout_heap.o ion_chunk_heap.o ion_cma_heap.o obj-$(CONFIG_ION_TEST) += ion_test.o ifdef CONFIG_COMPAT Loading @@ -9,5 +8,4 @@ endif obj-$(CONFIG_ION_DUMMY) += ion_dummy_driver.o obj-$(CONFIG_ION_TEGRA) += tegra/ obj-$(CONFIG_ION_HISI) += hisilicon/ obj-$(CONFIG_ION_OF) += ion_of.o
drivers/staging/android/ion/ion.c +325 −67 Original line number Diff line number Diff line Loading @@ -41,6 +41,82 @@ #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; /* Protects rb_tree */ 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; /* Protects 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) && Loading Loading @@ -131,16 +207,19 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, goto err2; } if (buffer->sg_table == NULL) { WARN_ONCE(1, "This heap needs to set the sgtable"); buffer->dev = dev; buffer->size = len; table = heap->ops->map_dma(heap, buffer); if (WARN_ONCE(!table, "heap->ops->map_dma should return ERR_PTR on error")) table = ERR_PTR(-EINVAL); if (IS_ERR(table)) { ret = -EINVAL; goto err1; } table = buffer->sg_table; buffer->dev = dev; buffer->size = len; buffer->sg_table = table; if (ion_buffer_fault_user_mappings(buffer)) { int num_pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; struct scatterlist *sg; Loading @@ -149,7 +228,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 err1; goto err; } for_each_sg(table->sgl, sg, table->nents, i) { Loading Loading @@ -183,6 +262,8 @@ 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: Loading @@ -194,6 +275,7 @@ 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); Loading Loading @@ -297,17 +379,26 @@ 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); } int ion_handle_put_nolock(struct ion_handle *handle) static int ion_handle_put_nolock(struct ion_handle *handle) { return kref_put(&handle->ref, ion_handle_destroy); int ret; ret = kref_put(&handle->ref, ion_handle_destroy); return ret; } int ion_handle_put(struct ion_handle *handle) static int ion_handle_put(struct ion_handle *handle) { struct ion_client *client = handle->client; int ret; Loading Loading @@ -337,7 +428,7 @@ static struct ion_handle *ion_handle_lookup(struct ion_client *client, return ERR_PTR(-EINVAL); } struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, static struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, int id) { struct ion_handle *handle; Loading @@ -349,7 +440,7 @@ struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, return handle ? handle : ERR_PTR(-EINVAL); } struct ion_handle *ion_handle_get_by_id(struct ion_client *client, static struct ion_handle *ion_handle_get_by_id(struct ion_client *client, int id) { struct ion_handle *handle; Loading Loading @@ -462,10 +553,16 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, } EXPORT_SYMBOL(ion_alloc); void ion_free_nolock(struct ion_client *client, static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle) { if (!ion_handle_validate(client, handle)) { bool valid_handle; WARN_ON(client != handle->client); valid_handle = ion_handle_validate(client, handle); if (!valid_handle) { WARN(1, "%s: invalid handle passed to free.\n", __func__); return; } Loading @@ -482,6 +579,32 @@ 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; Loading Loading @@ -797,6 +920,26 @@ 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); Loading Loading @@ -1135,7 +1278,7 @@ struct ion_handle *ion_import_dma_buf_fd(struct ion_client *client, int fd) } EXPORT_SYMBOL(ion_import_dma_buf_fd); int ion_sync_for_device(struct ion_client *client, int fd) static int ion_sync_for_device(struct ion_client *client, int fd) { struct dma_buf *dmabuf; struct ion_buffer *buffer; Loading @@ -1159,45 +1302,125 @@ int ion_sync_for_device(struct ion_client *client, int fd) return 0; } int ion_query_heaps(struct ion_client *client, struct ion_heap_query *query) /* 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) { struct ion_client *client = filp->private_data; struct ion_device *dev = client->dev; 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; struct ion_handle *cleanup_handle = NULL; int ret = 0; unsigned int dir; memset(&hdata, 0, sizeof(hdata)); union { struct ion_fd_data fd; struct ion_allocation_data allocation; struct ion_handle_data handle; struct ion_custom_data custom; } data; down_read(&dev->lock); if (!buffer) { query->cnt = dev->heap_cnt; ret = 0; goto out; } dir = ion_ioctl_dir(cmd); if (query->cnt <= 0) goto out; if (_IOC_SIZE(cmd) > sizeof(data)) return -EINVAL; max_cnt = query->cnt; if (dir & _IOC_WRITE) if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd))) return -EFAULT; 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; switch (cmd) { case ION_IOC_ALLOC: { struct ion_handle *handle; ret = copy_to_user(&buffer[cnt], &hdata, sizeof(hdata)); 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); cnt++; if (cnt >= max_cnt) data.allocation.handle = handle->id; cleanup_handle = handle; break; } case ION_IOC_FREE: { struct ion_handle *handle; query->cnt = cnt; out: up_read(&dev->lock); 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; } 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; } } return ret; } Loading Loading @@ -1369,7 +1592,8 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) { struct dentry *debug_file; if (!heap->ops->allocate || !heap->ops->free) if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma || !heap->ops->unmap_dma) pr_err("%s: can not add heap with invalid ops struct.\n", __func__); Loading Loading @@ -1418,7 +1642,6 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) } } dev->heap_cnt++; up_write(&dev->lock); } EXPORT_SYMBOL(ion_device_add_heap); Loading Loading @@ -1483,3 +1706,38 @@ 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); } }
drivers/staging/android/ion/ion.h +41 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,17 @@ struct ion_platform_data { struct ion_platform_heap *heaps; }; /** * ion_reserve() - reserve memory for ion heaps if applicable * @data: platform data specifying starting physical address and * size * * Calls memblock reserve to set aside memory for heaps that are * located at specific memory addresses or of specific sizes not * managed by the kernel */ void ion_reserve(struct ion_platform_data *data); /** * ion_client_create() - allocate a client and returns it * @dev: the global ion device Loading Loading @@ -118,6 +129,36 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, */ void ion_free(struct ion_client *client, struct ion_handle *handle); /** * ion_phys - returns the physical address and len of a handle * @client: the client * @handle: the handle * @addr: a pointer to put the address in * @len: a pointer to put the length in * * This function queries the heap for a particular handle to get the * handle's physical address. It't output is only correct if * a heap returns physically contiguous memory -- in other cases * this api should not be implemented -- ion_sg_table should be used * instead. Returns -EINVAL if the handle is invalid. This has * no implications on the reference counting of the handle -- * the returned value may not be valid if the caller is not * holding a reference. */ int ion_phys(struct ion_client *client, struct ion_handle *handle, ion_phys_addr_t *addr, size_t *len); /** * ion_map_dma - return an sg_table describing a handle * @client: the client * @handle: the handle * * This function returns the sg_table describing * a particular ion handle. */ struct sg_table *ion_sg_table(struct ion_client *client, struct ion_handle *handle); /** * ion_map_kernel - create mapping for the given handle * @client: the client Loading
drivers/staging/android/ion/ion_carveout_heap.c +34 −9 Original line number Diff line number Diff line Loading @@ -25,15 +25,13 @@ #include "ion.h" #include "ion_priv.h" #define ION_CARVEOUT_ALLOCATE_FAIL -1 struct ion_carveout_heap { struct ion_heap heap; struct gen_pool *pool; ion_phys_addr_t base; }; static ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap, ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap, unsigned long size, unsigned long align) { Loading @@ -47,7 +45,7 @@ static ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap, return offset; } static void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, unsigned long size) { struct ion_carveout_heap *carveout_heap = Loading @@ -58,6 +56,19 @@ static void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, gen_pool_free(carveout_heap->pool, addr, size); } static int ion_carveout_heap_phys(struct ion_heap *heap, struct ion_buffer *buffer, ion_phys_addr_t *addr, size_t *len) { struct sg_table *table = buffer->priv_virt; struct page *page = sg_page(table->sgl); ion_phys_addr_t paddr = PFN_PHYS(page_to_pfn(page)); *addr = paddr; *len = buffer->size; return 0; } static int ion_carveout_heap_allocate(struct ion_heap *heap, struct ion_buffer *buffer, unsigned long size, unsigned long align, Loading @@ -84,7 +95,7 @@ static int ion_carveout_heap_allocate(struct ion_heap *heap, } sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(paddr)), size, 0); buffer->sg_table = table; buffer->priv_virt = table; return 0; Loading @@ -98,7 +109,7 @@ static int ion_carveout_heap_allocate(struct ion_heap *heap, static void ion_carveout_heap_free(struct ion_buffer *buffer) { struct ion_heap *heap = buffer->heap; struct sg_table *table = buffer->sg_table; struct sg_table *table = buffer->priv_virt; struct page *page = sg_page(table->sgl); ion_phys_addr_t paddr = PFN_PHYS(page_to_pfn(page)); Loading @@ -113,9 +124,23 @@ static void ion_carveout_heap_free(struct ion_buffer *buffer) kfree(table); } static struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap, struct ion_buffer *buffer) { return buffer->priv_virt; } static void ion_carveout_heap_unmap_dma(struct ion_heap *heap, struct ion_buffer *buffer) { } static struct ion_heap_ops carveout_heap_ops = { .allocate = ion_carveout_heap_allocate, .free = ion_carveout_heap_free, .phys = ion_carveout_heap_phys, .map_dma = ion_carveout_heap_map_dma, .unmap_dma = ion_carveout_heap_unmap_dma, .map_user = ion_heap_map_user, .map_kernel = ion_heap_map_kernel, .unmap_kernel = ion_heap_unmap_kernel, Loading