279 lines
7.3 KiB
C
279 lines
7.3 KiB
C
/*
|
|
* Copyright (C) 2014-2019 Amlogic, Inc. All rights reserved.
|
|
*
|
|
* All information contained herein is Amlogic confidential.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
//#include <ion.h>
|
|
#include <gst/gst.h>
|
|
#include <gst/base/base.h>
|
|
#include <gst/allocators/gstdmabuf.h>
|
|
#include "gstamlionallocator.h"
|
|
|
|
#include "ion.h"
|
|
|
|
|
|
#define MAX_HEAP_NAME 32
|
|
/**
|
|
* struct ion_heap_data - data about a heap
|
|
* @name - first 32 characters of the heap name
|
|
* @type - heap type
|
|
* @heap_id - heap id for the heap
|
|
*/
|
|
struct ion_heap_data {
|
|
char name[MAX_HEAP_NAME];
|
|
guint type;
|
|
guint heap_id;
|
|
guint reserved0;
|
|
guint reserved1;
|
|
guint reserved2;
|
|
};
|
|
|
|
#define ION_FLAG_CACHED 1
|
|
#define ION_FLAG_CACHED_NEEDS_SYNC 2
|
|
|
|
GST_DEBUG_CATEGORY_STATIC(amlion_allocator_debug);
|
|
#define GST_CAT_DEFAULT amlion_allocator_debug
|
|
|
|
#define gst_amlion_allocator_parent_class parent_class
|
|
|
|
G_DEFINE_TYPE(GstAmlIONAllocator, gst_amlion_allocator, GST_TYPE_ALLOCATOR)
|
|
|
|
static void
|
|
gst_amlion_mem_init(void)
|
|
{
|
|
GstAllocator *allocator = g_object_new(gst_amlion_allocator_get_type(), NULL);
|
|
GstAmlIONAllocator *self = GST_AMLION_ALLOCATOR (allocator);
|
|
|
|
gint fd = ion_open ();
|
|
if (fd < 0) {
|
|
GST_ERROR ("Could not open ion driver");
|
|
g_object_unref (self);
|
|
return;
|
|
}
|
|
|
|
GST_DEBUG("Xiaobo add here for debugss %s,%d fd=[%d]",__FUNCTION__,__LINE__,fd);
|
|
self->fd = fd;
|
|
|
|
self->dma_allocator = gst_dmabuf_allocator_new();
|
|
|
|
gst_allocator_register(g_type_name(GST_TYPE_AMLION_ALLOCATOR), allocator);
|
|
}
|
|
|
|
GstAllocator*
|
|
gst_amlion_allocator_obtain(void)
|
|
{
|
|
static GOnce ion_allocator_once = G_ONCE_INIT;
|
|
GstAllocator *allocator;
|
|
|
|
g_once(&ion_allocator_once, (GThreadFunc)gst_amlion_mem_init, NULL);
|
|
|
|
allocator = gst_allocator_find(g_type_name(GST_TYPE_AMLION_ALLOCATOR));
|
|
|
|
if (allocator == NULL)
|
|
GST_WARNING("No allocator named %s found", g_type_name(GST_TYPE_AMLION_ALLOCATOR));
|
|
|
|
return allocator;
|
|
}
|
|
|
|
GQuark
|
|
gst_amlion_memory_quark (void)
|
|
{
|
|
static GQuark quark = 0;
|
|
|
|
if (quark == 0)
|
|
quark = g_quark_from_string ("GstAmlIONPrivate");
|
|
|
|
return quark;
|
|
}
|
|
|
|
#define ION_FLAG_EXTEND_MESON_HEAP_EXT (1 << 30)
|
|
|
|
|
|
static GstMemory *
|
|
gst_amlion_alloc_alloc (GstAllocator * allocator, gsize size,
|
|
GstAllocationParams * params)
|
|
{
|
|
GstAmlIONAllocator *self = GST_AMLION_ALLOCATOR (allocator);
|
|
gint ionSize = (size + params->prefix + params->padding);
|
|
gint ret = -1;
|
|
gint data_fd = -1;
|
|
gint num_heaps = 0;
|
|
guint heap_mask = 0;
|
|
gint legacy_ion = 0;
|
|
struct ion_heap_data *heaps = NULL;
|
|
guint heap_types[] = {ION_HEAP_TYPE_DMA, ION_HEAP_TYPE_CARVEOUT, ION_NUM_HEAPS};
|
|
gint heap_type_idx = -1;
|
|
// use GST_MEMORY_FLAG_PHYSICALLY_CONTIGUOUS to indicate cached/uncached dma buffer
|
|
gboolean is_uncached = (params->flags & GST_MEMORY_FLAG_PHYSICALLY_CONTIGUOUS);
|
|
|
|
if (self->fd < 0)
|
|
return NULL;
|
|
|
|
legacy_ion = ion_is_legacy(self->fd);
|
|
|
|
try_heap:
|
|
heap_type_idx ++;
|
|
if (heap_types[heap_type_idx] >= ION_NUM_HEAPS) {
|
|
GST_ERROR ("ion alloc failed, no heap usable");
|
|
goto fail_exit;
|
|
}
|
|
|
|
if (legacy_ion) {
|
|
heap_mask = 1 << heap_types[heap_type_idx];
|
|
} else {
|
|
if ((ret = ion_query_heap_cnt (self->fd, &num_heaps)) < 0) {
|
|
GST_ERROR ("ion query heap cnt failed, ret:%d", ret);
|
|
goto fail_exit;
|
|
}
|
|
|
|
if (num_heaps <= 0) {
|
|
GST_ERROR ("unexpected error: ion query heap cnt is 0");
|
|
goto fail_exit;
|
|
}
|
|
|
|
heaps = g_new0 (struct ion_heap_data, num_heaps);
|
|
|
|
if (heaps == NULL) {
|
|
GST_ERROR ("failed to allocate ion heap data");
|
|
goto fail_exit;
|
|
}
|
|
|
|
if ((ret = ion_query_get_heaps (self->fd, num_heaps, heaps)) < 0) {
|
|
GST_ERROR ("ion query get heaps failed, ret:%d", ret);
|
|
goto fail_exit;
|
|
}
|
|
|
|
for (int i = 0; i != num_heaps; ++i) {
|
|
GST_DEBUG("Heap_name = [%s],heap type = [%d],heap id = [%d] heap_types[heap_type_idx][%d]",heaps[i].name,heaps[i].type,heaps[i].heap_id,heap_types[heap_type_idx]);
|
|
if (heaps[i].type == heap_types[heap_type_idx]) {
|
|
heap_mask = 1 << heaps[i].heap_id;
|
|
break;
|
|
}
|
|
}
|
|
|
|
g_free (heaps);
|
|
heaps = NULL;
|
|
if (heap_mask == 0) {
|
|
GST_WARNING ("failed to match heapmask, heap type = %d", heap_types[heap_type_idx]);
|
|
goto try_heap;
|
|
}
|
|
}
|
|
guint flag = is_uncached ? 0 : ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC | ION_FLAG_EXTEND_MESON_HEAP_EXT;
|
|
|
|
if (legacy_ion) {
|
|
// force to uncached buffer if is legacy ion,
|
|
// to avoid the memory conherency issue
|
|
flag = 0;
|
|
}
|
|
|
|
ret = ion_alloc_fd (self->fd, ionSize, 0, heap_mask, flag, &data_fd);
|
|
if (ret < 0) {
|
|
GST_WARNING ("ion alloc failed on heap %d, ret: %d data_fd[%d]", heap_types[heap_type_idx], ret,data_fd);
|
|
goto try_heap;
|
|
}
|
|
|
|
GST_DEBUG("phyalloc ionSize:%d dmafd: %d on heap %d, type: %s", ionSize,
|
|
data_fd, heap_types[heap_type_idx],
|
|
is_uncached ? "uncached" : "cached");
|
|
|
|
GstAmlIONMemory *ion_mem = g_slice_new0 (GstAmlIONMemory);
|
|
gst_memory_init (GST_MEMORY_CAST(ion_mem), GST_MEMORY_FLAG_NO_SHARE, allocator,
|
|
0, size, 0, 0, size);
|
|
|
|
ion_mem->size = ionSize;
|
|
ion_mem->fd = data_fd;
|
|
|
|
GstMemory *mem =
|
|
gst_dmabuf_allocator_alloc (self->dma_allocator, data_fd, ionSize);
|
|
|
|
gst_mini_object_set_qdata (GST_MINI_OBJECT(mem), GST_AMLION_MEMORY_QUARK,
|
|
ion_mem, (GDestroyNotify) gst_memory_unref);
|
|
|
|
GST_LOG ("allocated memory %p by allocator %p with qdata %p\n", mem,
|
|
allocator, ion_mem);
|
|
|
|
return mem;
|
|
|
|
fail_exit:
|
|
if (heaps) {
|
|
g_free (heaps);
|
|
}
|
|
if (data_fd > 0) {
|
|
close (data_fd);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
gst_amlion_alloc_free (GstAllocator * allocator, GstMemory * memory)
|
|
{
|
|
GstAmlIONAllocator *self = GST_AMLION_ALLOCATOR (allocator);
|
|
GstAmlIONMemory *ion_mem = (GstAmlIONMemory *) memory;
|
|
|
|
if (!ion_mem || self->fd < 0)
|
|
return;
|
|
|
|
GST_DEBUG ("phyfree ionSize:%ld dmafd: %d",
|
|
ion_mem->size, ion_mem->fd);
|
|
g_slice_free (GstAmlIONMemory, ion_mem);
|
|
}
|
|
|
|
static void
|
|
gst_amlion_allocator_dispose (GObject * object)
|
|
{
|
|
GstAmlIONAllocator *self = GST_AMLION_ALLOCATOR (object);
|
|
|
|
if (self->fd) {
|
|
ion_close (self->fd);
|
|
self->fd = -1;
|
|
}
|
|
|
|
if (self->dma_allocator)
|
|
gst_object_unref(self->dma_allocator);
|
|
self->dma_allocator = NULL;
|
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
gst_amlion_allocator_class_init (GstAmlIONAllocatorClass * klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
GstAllocatorClass *allocator_class = GST_ALLOCATOR_CLASS (klass);
|
|
|
|
allocator_class->alloc = GST_DEBUG_FUNCPTR (gst_amlion_alloc_alloc);
|
|
allocator_class->free = GST_DEBUG_FUNCPTR (gst_amlion_alloc_free);
|
|
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_amlion_allocator_dispose);
|
|
|
|
GST_DEBUG_CATEGORY_INIT(amlion_allocator_debug, "amlionallocator", 0, "DMA FD memory allocator based on ion");
|
|
}
|
|
|
|
static void
|
|
gst_amlion_allocator_init (GstAmlIONAllocator * self)
|
|
{
|
|
GstAllocator *allocator = GST_ALLOCATOR (self);
|
|
|
|
allocator->mem_type = GST_ALLOCATOR_AMLION;
|
|
allocator->mem_map = NULL;
|
|
allocator->mem_unmap = NULL;
|
|
}
|
|
|
|
gboolean
|
|
gst_is_amlionbuf_memory (GstMemory * mem)
|
|
{
|
|
g_return_val_if_fail (mem != NULL, FALSE);
|
|
|
|
gpointer qdata = gst_mini_object_get_qdata (GST_MINI_OBJECT(mem), GST_AMLION_MEMORY_QUARK);
|
|
return qdata != NULL;
|
|
}
|
|
|