| /* |
| * # Copyright 2020 Google LLC |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * https://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <stdint.h> |
| #include <sys/ioctl.h> |
| |
| #include "gstionallocator.h" |
| #include "ion_coral.h" |
| |
| GST_DEBUG_CATEGORY_STATIC (ion_debug); |
| #define GST_CAT_DEFAULT ion_debug |
| #define gst_allocator_ion_parent_class parent_class |
| G_DEFINE_TYPE (GstAllocatorIon, gst_allocator_ion, GST_TYPE_DMABUF_ALLOCATOR); |
| |
| static void gst_allocator_ion_finalize (GObject * object); |
| static GstMemory * gst_allocator_ion_alloc (GstAllocator * allocator, |
| gsize size,GstAllocationParams * params); |
| |
| static void |
| gst_allocator_ion_class_init (GstAllocatorIonClass * klass) |
| { |
| GST_ALLOCATOR_CLASS (klass)->alloc = gst_allocator_ion_alloc; |
| G_OBJECT_CLASS (klass)->finalize = gst_allocator_ion_finalize; |
| |
| GST_DEBUG_CATEGORY_INIT (ion_debug, "ion", 0, |
| "Linux dma-buf allocator based on ION"); |
| } |
| |
| static void |
| gst_allocator_ion_init (GstAllocatorIon * ion) |
| { |
| GstAllocator *allocator = GST_ALLOCATOR (ion); |
| |
| allocator->mem_type = GST_ALLOCATOR_ION_NAME; |
| |
| ion->fd = -1; |
| ion->heap_mask = -1; |
| g_mutex_init (&ion->mutex); |
| } |
| |
| static void |
| gst_allocator_ion_finalize (GObject * object) |
| { |
| GstAllocatorIon *ion = GST_ALLOCATOR_ION (object); |
| |
| if (ion->fd > -1) { |
| close (ion->fd); |
| ion->fd = -1; |
| } |
| g_mutex_clear (&ion->mutex); |
| |
| G_OBJECT_CLASS (parent_class)->finalize (object); |
| } |
| |
| gboolean |
| gst_allocator_ion_init_check (GstAllocatorIon * ion) |
| { |
| int fd, buf_fd, heap_mask, i; |
| gboolean success; |
| struct ion_heap_query query; |
| struct ion_allocation_data alloc_data; |
| struct ion_heap_data *heap_data = NULL; |
| |
| g_mutex_lock (&ion->mutex); |
| |
| fd = 1; |
| buf_fd = -1; |
| heap_mask = 0; |
| success = FALSE; |
| |
| if (ion->fd > -1) { |
| GST_DEBUG_OBJECT (ion, "Already initialized"); |
| goto beach; |
| } |
| |
| GST_DEBUG_OBJECT (ion, "Opening /dev/ion"); |
| fd = open ("/dev/ion", O_RDWR); |
| if (fd == -1) { |
| GST_INFO_OBJECT (ion, "ION allocator not supported"); |
| g_mutex_unlock (&ion->mutex); |
| return FALSE; |
| } |
| GST_DEBUG_OBJECT (ion, "/dev/ion opened with fd=%d", fd); |
| |
| memset (&query, 0, sizeof(query)); |
| if (ioctl (fd, ION_IOC_HEAP_QUERY, &query) < 0) { |
| GST_ERROR_OBJECT (ion, "ION_IOC_HEAP_QUERY failed: %d", errno); |
| goto beach; |
| } |
| |
| GST_DEBUG_OBJECT (ion, "ION_IOC_HEAP_QUERY returned %u heaps", query.cnt); |
| heap_data = g_malloc0_n (query.cnt, sizeof(*heap_data)); |
| query.heaps = (uintptr_t) heap_data; |
| if (ioctl (fd, ION_IOC_HEAP_QUERY, &query) < 0) { |
| GST_ERROR_OBJECT (ion, "ION_IOC_HEAP_QUERY failed: %d", errno); |
| goto beach; |
| } |
| |
| for (i = 0; i < query.cnt; ++i) { |
| if (heap_data[i].type == ION_HEAP_TYPE_DMA) { |
| heap_mask |= 1 << heap_data[i].heap_id; |
| } |
| } |
| |
| memset (&alloc_data, 0, sizeof(alloc_data)); |
| alloc_data.len = 42; |
| alloc_data.heap_id_mask = heap_mask; |
| alloc_data.flags = ION_FLAG_CACHED; |
| |
| if (ioctl (fd, ION_IOC_ALLOC, &alloc_data) < 0) { |
| GST_ERROR_OBJECT (ion, "ION_IOC_ALLOC failed: %d", errno); |
| goto beach; |
| } |
| buf_fd = alloc_data.fd; |
| |
| beach: |
| success = buf_fd != -1; |
| if (success) { |
| close (buf_fd); |
| ion->fd = fd; |
| ion->heap_mask = heap_mask; |
| GST_INFO_OBJECT (ion, "ION allocator initialized"); |
| } else { |
| GST_ERROR_OBJECT (ion, "ION allocator initialization failed"); |
| } |
| |
| g_mutex_unlock (&ion->mutex); |
| |
| return success; |
| } |
| |
| |
| |
| static GstMemory * |
| gst_allocator_ion_alloc (GstAllocator * allocator, gsize size, |
| GstAllocationParams * params) |
| { |
| GstAllocatorIon *ion = GST_ALLOCATOR_ION (allocator); |
| struct ion_allocation_data alloc_data = { 0 }; |
| |
| alloc_data.len = size; |
| alloc_data.heap_id_mask = ion->heap_mask; |
| alloc_data.flags = ION_FLAG_CACHED; |
| |
| if (ioctl (ion->fd, ION_IOC_ALLOC, &alloc_data) < 0) { |
| GST_ERROR_OBJECT (ion, "ION_IOC_ALLOC failed: %d", errno); |
| return NULL; |
| } |
| |
| GST_DEBUG_OBJECT (ion, "allocated size %" G_GSIZE_FORMAT " b, fd %d", |
| size, alloc_data.fd); |
| return gst_dmabuf_allocator_alloc (allocator, alloc_data.fd, size); |
| } |
| |
| |
| gboolean gst_allocator_ion_init_check (GstAllocatorIon * ion); |