#include #include #include #include #include #include #include #include #include #include #include #include #include "visionbuf.h" // just hard-code these for convenience // size_t device_page_size = 0; // clGetDeviceInfo(device_id, CL_DEVICE_PAGE_SIZE_QCOM, // sizeof(device_page_size), &device_page_size, // NULL); // size_t padding_cl = 0; // clGetDeviceInfo(device_id, CL_DEVICE_EXT_MEM_PADDING_IN_BYTES_QCOM, // sizeof(padding_cl), &padding_cl, // NULL); #define DEVICE_PAGE_SIZE_CL 4096 #define PADDING_CL 0 static int ion_fd = -1; static void ion_init() { if (ion_fd == -1) { ion_fd = open("/dev/ion", O_RDWR | O_NONBLOCK); } } VisionBuf visionbuf_allocate(size_t len) { int err; ion_init(); struct ion_allocation_data ion_alloc = {0}; ion_alloc.len = len + PADDING_CL; ion_alloc.align = 4096; ion_alloc.heap_id_mask = 1 << ION_IOMMU_HEAP_ID; ion_alloc.flags = ION_FLAG_CACHED; err = ioctl(ion_fd, ION_IOC_ALLOC, &ion_alloc); assert(err == 0); struct ion_fd_data ion_fd_data = {0}; ion_fd_data.handle = ion_alloc.handle; err = ioctl(ion_fd, ION_IOC_SHARE, &ion_fd_data); assert(err == 0); void *addr = mmap(NULL, ion_alloc.len, PROT_READ | PROT_WRITE, MAP_SHARED, ion_fd_data.fd, 0); assert(addr != MAP_FAILED); memset(addr, 0, ion_alloc.len); return (VisionBuf){ .len = len, .addr = addr, .handle = ion_alloc.handle, .fd = ion_fd_data.fd, }; } VisionBuf visionbuf_allocate_cl(size_t len, cl_device_id device_id, cl_context ctx, cl_mem *out_mem) { VisionBuf r = visionbuf_allocate(len); *out_mem = visionbuf_to_cl(&r, device_id, ctx); return r; } cl_mem visionbuf_to_cl(const VisionBuf* buf, cl_device_id device_id, cl_context ctx) { int err = 0; assert(((uintptr_t)buf->addr % DEVICE_PAGE_SIZE_CL) == 0); cl_mem_ion_host_ptr ion_cl = {0}; ion_cl.ext_host_ptr.allocation_type = CL_MEM_ION_HOST_PTR_QCOM; ion_cl.ext_host_ptr.host_cache_policy = CL_MEM_HOST_UNCACHED_QCOM; ion_cl.ion_filedesc = buf->fd; ion_cl.ion_hostptr = buf->addr; cl_mem mem = clCreateBuffer(ctx, CL_MEM_USE_HOST_PTR | CL_MEM_EXT_HOST_PTR_QCOM, buf->len, &ion_cl, &err); assert(err == 0); return mem; } void visionbuf_sync(const VisionBuf* buf, int dir) { int err; struct ion_fd_data fd_data = {0}; fd_data.fd = buf->fd; err = ioctl(ion_fd, ION_IOC_IMPORT, &fd_data); assert(err == 0); struct ion_flush_data flush_data = {0}; flush_data.handle = fd_data.handle; flush_data.vaddr = buf->addr; flush_data.offset = 0; flush_data.length = buf->len; // ION_IOC_INV_CACHES ~= DMA_FROM_DEVICE // ION_IOC_CLEAN_CACHES ~= DMA_TO_DEVICE // ION_IOC_CLEAN_INV_CACHES ~= DMA_BIDIRECTIONAL struct ion_custom_data custom_data = {0}; switch (dir) { case VISIONBUF_SYNC_FROM_DEVICE: custom_data.cmd = ION_IOC_INV_CACHES; break; case VISIONBUF_SYNC_TO_DEVICE: custom_data.cmd = ION_IOC_CLEAN_CACHES; break; default: assert(0); } custom_data.arg = (unsigned long)&flush_data; err = ioctl(ion_fd, ION_IOC_CUSTOM, &custom_data); assert(err == 0); struct ion_handle_data handle_data = {0}; handle_data.handle = fd_data.handle; err = ioctl(ion_fd, ION_IOC_FREE, &handle_data); assert(err == 0); } void visionbuf_free(const VisionBuf* buf) { struct ion_handle_data handle_data = { .handle = buf->handle, }; int ret = ioctl(ion_fd, ION_IOC_FREE, &handle_data); assert(ret == 0); }