From 30e7ecfc58ce7c9e7ea6f412460a0803bb904d91 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 11 Feb 2018 03:02:42 +0200 Subject: Add ION allocation support When using the USERPTR method attempt to use ION if available. The heap is hardcoded to DMA for now. Signed-off-by: Laurent Pinchart --- include/linux/ion.h | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++ yavta.c | 69 +++++++++++++++++- 2 files changed, 262 insertions(+), 3 deletions(-) create mode 100644 include/linux/ion.h diff --git a/include/linux/ion.h b/include/linux/ion.h new file mode 100644 index 0000000..f09e7c1 --- /dev/null +++ b/include/linux/ion.h @@ -0,0 +1,196 @@ +/* + * drivers/staging/android/uapi/ion.h + * + * 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. + * + */ + +#ifndef _UAPI_LINUX_ION_H +#define _UAPI_LINUX_ION_H + +#include +#include + +typedef int ion_user_handle_t; + +/** + * enum ion_heap_types - list of all possible types of heaps + * @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc + * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc + * @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved + * carveout heap, allocations are physically + * contiguous + * @ION_HEAP_TYPE_DMA: memory allocated via DMA API + * @ION_NUM_HEAPS: helper for iterating over heaps, a bit mask + * is used to identify the heaps, so only 32 + * total heap types are supported + */ +enum ion_heap_type { + ION_HEAP_TYPE_SYSTEM, + ION_HEAP_TYPE_SYSTEM_CONTIG, + ION_HEAP_TYPE_CARVEOUT, + ION_HEAP_TYPE_CHUNK, + ION_HEAP_TYPE_DMA, + ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always + are at the end of this enum */ + ION_NUM_HEAPS = 16, +}; + +#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM) +#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG) +#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT) +#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA) + +#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8 + +/** + * allocation flags - the lower 16 bits are used by core ion, the upper 16 + * bits are reserved for use by the heaps themselves. + */ +#define ION_FLAG_CACHED 1 /* mappings of this buffer should be + cached, ion will do cache + maintenance when the buffer is + mapped for dma */ +#define ION_FLAG_CACHED_NEEDS_SYNC 2 /* mappings of this buffer will created + at mmap time, if this is set + caches must be managed manually */ + +/** + * DOC: Ion Userspace API + * + * create a client by opening /dev/ion + * most operations handled via following ioctls + * + */ + +/** + * struct ion_allocation_data - metadata passed from userspace for allocations + * @len: size of the allocation + * @align: required alignment of the allocation + * @heap_id_mask: mask of heap ids to allocate from + * @flags: flags passed to heap + * @handle: pointer that will be populated with a cookie to use to + * refer to this allocation + * + * Provided by userspace as an argument to the ioctl + */ +struct ion_allocation_data { + size_t len; + size_t align; + unsigned int heap_id_mask; + unsigned int flags; + ion_user_handle_t handle; +}; + +/** + * struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair + * @handle: a handle + * @fd: a file descriptor representing that handle + * + * For ION_IOC_SHARE or ION_IOC_MAP userspace populates the handle field with + * the handle returned from ion alloc, and the kernel returns the file + * descriptor to share or map in the fd field. For ION_IOC_IMPORT, userspace + * provides the file descriptor and the kernel returns the handle. + */ +struct ion_fd_data { + ion_user_handle_t handle; + int fd; +}; + +/** + * struct ion_handle_data - a handle passed to/from the kernel + * @handle: a handle + */ +struct ion_handle_data { + ion_user_handle_t handle; +}; + +/** + * struct ion_custom_data - metadata passed to/from userspace for a custom ioctl + * @cmd: the custom ioctl function to call + * @arg: additional data to pass to the custom ioctl, typically a user + * pointer to a predefined structure + * + * This works just like the regular cmd and arg fields of an ioctl. + */ +struct ion_custom_data { + unsigned int cmd; + unsigned long arg; +}; + +#define ION_IOC_MAGIC 'I' + +/** + * DOC: ION_IOC_ALLOC - allocate memory + * + * Takes an ion_allocation_data struct and returns it with the handle field + * populated with the opaque handle for the allocation. + */ +#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ + struct ion_allocation_data) + +/** + * DOC: ION_IOC_FREE - free memory + * + * Takes an ion_handle_data struct and frees the handle. + */ +#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data) + +/** + * DOC: ION_IOC_MAP - get a file descriptor to mmap + * + * Takes an ion_fd_data struct with the handle field populated with a valid + * opaque handle. Returns the struct with the fd field set to a file + * descriptor open in the current address space. This file descriptor + * can then be used as an argument to mmap. + */ +#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data) + +/** + * DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation + * + * Takes an ion_fd_data struct with the handle field populated with a valid + * opaque handle. Returns the struct with the fd field set to a file + * descriptor open in the current address space. This file descriptor + * can then be passed to another process. The corresponding opaque handle can + * be retrieved via ION_IOC_IMPORT. + */ +#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data) + +/** + * DOC: ION_IOC_IMPORT - imports a shared file descriptor + * + * Takes an ion_fd_data struct with the fd field populated with a valid file + * descriptor obtained from ION_IOC_SHARE and returns the struct with the handle + * filed set to the corresponding opaque handle. + */ +#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data) + +/** + * DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory + * + * Deprecated in favor of using the dma_buf api's correctly (syncing + * will happend automatically when the buffer is mapped to a device). + * If necessary should be used after touching a cached buffer from the cpu, + * this will make the buffer in memory coherent. + */ +#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data) + +/** + * DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl + * + * Takes the argument of the architecture specific ioctl to call and + * passes appropriate userdata for that ioctl + */ +#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data) + +#endif /* _UAPI_LINUX_ION_H */ diff --git a/yavta.c b/yavta.c index afe9633..8318c8b 100644 --- a/yavta.c +++ b/yavta.c @@ -37,6 +37,7 @@ #include #include +#include #include #ifndef V4L2_BUF_FLAG_ERROR @@ -58,11 +59,13 @@ struct buffer unsigned int padding[VIDEO_MAX_PLANES]; unsigned int size[VIDEO_MAX_PLANES]; void *mem[VIDEO_MAX_PLANES]; + ion_user_handle_t handles[VIDEO_MAX_PLANES]; }; struct device { int fd; + int ion; int opened; enum v4l2_buf_type type; @@ -340,6 +343,7 @@ static void video_init(struct device *dev) { memset(dev, 0, sizeof *dev); dev->fd = -1; + dev->ion = -1; dev->memtype = V4L2_MEMORY_MMAP; dev->buffers = NULL; dev->type = (enum v4l2_buf_type)-1; @@ -817,6 +821,40 @@ static int video_buffer_munmap(struct device *dev, struct buffer *buffer) return 0; } +static int video_buffer_alloc_ion(struct device *dev, size_t len, void **mem, + ion_user_handle_t *handle) +{ + struct ion_allocation_data ion_alloc = { + .len = len, + .heap_id_mask = ION_HEAP_TYPE_DMA_MASK, + }; + struct ion_fd_data ion_map = { 0, }; + int ret; + + ret = ioctl(dev->ion, ION_IOC_ALLOC, &ion_alloc); + if (ret < 0) { + printf("ION allocation of %zu bytes failed: %s (%d)\n", len, + strerror(errno), errno); + return -errno; + } + + *handle = ion_alloc.handle; + ion_map.handle = ion_alloc.handle; + ret = ioctl(dev->ion, ION_IOC_MAP, &ion_map); + if (ret < 0) { + printf("ION map failed: %s (%d)\n", strerror(errno), errno); + return -errno; + } + + *mem = mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, ion_map.fd, 0); + if (*mem == MAP_FAILED) { + printf("ION mmap failed: %s (%d)\n", strerror(errno), errno); + return -errno; + } + + return 0; +} + static int video_buffer_alloc_userptr(struct device *dev, struct buffer *buffer, struct v4l2_buffer *v4l2buf, unsigned int offset, unsigned int padding) @@ -832,8 +870,14 @@ static int video_buffer_alloc_userptr(struct device *dev, struct buffer *buffer, else length = v4l2buf->length; - ret = posix_memalign(&buffer->mem[i], page_size, - length + offset + padding); + if (dev->ion != -1) + ret = video_buffer_alloc_ion(dev, length + offset + padding, + &buffer->mem[i], + &buffer->handles[i]); + else + ret = posix_memalign(&buffer->mem[i], page_size, + length + offset + padding); + if (ret < 0) { printf("Unable to allocate buffer %u/%u (%d)\n", buffer->idx, i, ret); @@ -856,7 +900,17 @@ static void video_buffer_free_userptr(struct device *dev, struct buffer *buffer) unsigned int i; for (i = 0; i < dev->num_planes; i++) { - free(buffer->mem[i]); + if (dev->ion != -1) { + struct ion_handle_data ion_free = { + .handle = buffer->handles[i], + }; + + munmap(buffer->mem[i], buffer->size[i]); + ioctl(dev->ion, ION_IOC_FREE, &ion_free); + } else { + free(buffer->mem[i]); + } + buffer->mem[i] = NULL; } } @@ -926,6 +980,15 @@ static int video_alloc_buffers(struct device *dev, int nbufs, printf("%u buffers requested.\n", rb.count); + if (dev->memtype == V4L2_MEMORY_USERPTR) { + dev->ion = open("/dev/ion", O_RDWR); + if (dev->ion < 0) { + printf("Unable to open ION device: %s (%d).\n", strerror(errno), + errno); + return dev->ion; + } + } + buffers = malloc(rb.count * sizeof buffers[0]); if (buffers == NULL) return -ENOMEM; -- cgit v1.2.3