summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2018-02-11 03:02:42 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2018-04-09 21:52:47 +0300
commit30e7ecfc58ce7c9e7ea6f412460a0803bb904d91 (patch)
treeabee9de3d874fdc6285cd5427cee585540755abc
parenta624564ebdbd700202b685d19f3204d55d0dfe58 (diff)
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 <laurent.pinchart@ideasonboard.com>
-rw-r--r--include/linux/ion.h196
-rw-r--r--yavta.c69
2 files changed, 262 insertions, 3 deletions
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 <linux/ioctl.h>
+#include <linux/types.h>
+
+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 <sys/stat.h>
#include <sys/time.h>
+#include <linux/ion.h>
#include <linux/videodev2.h>
#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;