You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
361 lines
9.1 KiB
361 lines
9.1 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd.. 2018-2019. All rights reserved.
|
|
* Description: Gralloc
|
|
* Author: Hisilicon
|
|
* Created: 2019.11.07
|
|
*/
|
|
|
|
#include "gralloc_ion.h"
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <linux/dma-buf.h>
|
|
|
|
#include <securec.h>
|
|
#include <ion/ion.h>
|
|
#ifdef GRALLOC_NEED_SMMU_MAP
|
|
#include "ion_ext.h"
|
|
#endif
|
|
|
|
static pthread_mutex_t g_ion_handle_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
static unsigned int gralloc_ion_get_heapid(unsigned long long usage)
|
|
{
|
|
GRALLOC_IGNORE(usage);
|
|
#ifdef GRALLOC_NEED_SMMU_MAP
|
|
return ION_HEAP_SYSTEM_MASK;
|
|
#else
|
|
if ((usage & GRALLOC_USAGE_PROTECTED) != 0) {
|
|
return ION_HEAP_SEC_SMMU_MASK;
|
|
}
|
|
|
|
return ION_HEAP_SMMU_MASK;
|
|
#endif
|
|
}
|
|
|
|
static unsigned int gralloc_ion_get_flags(unsigned long long usage)
|
|
{
|
|
if (((usage & GRALLOC_USAGE_SW_READ_MASK) == GRALLOC_USAGE_SW_READ_OFTEN) ||
|
|
((usage & GRALLOC_USAGE_SW_READ_MASK) == GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN)) {
|
|
#ifdef GRALLOC_NEED_SMMU_MAP
|
|
return ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
|
|
#else
|
|
return ION_FLAG_CACHED;
|
|
#endif
|
|
}
|
|
|
|
return GRALLOC_SUCCESS;
|
|
}
|
|
|
|
int gralloc_ion_device_open(private_module_t *m)
|
|
{
|
|
if (m == nullptr) {
|
|
GRALLOC_ERROR_INFO();
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
|
|
pthread_mutex_lock(&g_ion_handle_lock);
|
|
|
|
if (m->client < 0) {
|
|
m->client = ion_open();
|
|
|
|
if (m->client < 0) {
|
|
GRALLOC_ERROR_INFO();
|
|
pthread_mutex_unlock(&g_ion_handle_lock);
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_ion_handle_lock);
|
|
return GRALLOC_SUCCESS;
|
|
}
|
|
|
|
int gralloc_ion_device_close(struct hw_device_t *device)
|
|
{
|
|
int ret = 0;
|
|
gralloc1_device_t *dev = reinterpret_cast<gralloc1_device_t *>(device);
|
|
|
|
if (dev == nullptr) {
|
|
GRALLOC_ERROR_INFO();
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
|
|
private_module_t *m = reinterpret_cast<private_module_t *>(dev->common.module);
|
|
|
|
if (m == nullptr) {
|
|
GRALLOC_ERROR_INFO();
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
|
|
pthread_mutex_lock(&g_ion_handle_lock);
|
|
if (m->client > 0) {
|
|
ret = ion_close(m->client);
|
|
if (ret < 0) {
|
|
GRALLOC_ERROR_INFO();
|
|
pthread_mutex_unlock(&g_ion_handle_lock);
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
|
|
m->client = -1;
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_ion_handle_lock);
|
|
return GRALLOC_SUCCESS;
|
|
}
|
|
|
|
int gralloc_ion_allocate(const private_module_t *m, const buffer_descriptor_t *descriptors,
|
|
private_internal_handle_t *handle)
|
|
{
|
|
int ret;
|
|
unsigned int flags;
|
|
unsigned int heaps;
|
|
unsigned long long usage;
|
|
int fd = -1;
|
|
size_t size;
|
|
#ifdef GRALLOC_NEED_SMMU_MAP
|
|
ion_user_handle_t hnd = -1;
|
|
#endif
|
|
char errbuf[256] = {0}; /* 256 is enough for err string */
|
|
|
|
if (m == nullptr || handle == nullptr || descriptors == nullptr) {
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
|
|
usage = descriptors->producer_usage | descriptors->consumer_usage;
|
|
size = descriptors->size;
|
|
heaps = gralloc_ion_get_heapid(usage);
|
|
flags = gralloc_ion_get_flags(usage);
|
|
#ifdef GRALLOC_NEED_SMMU_MAP
|
|
ret = ion_alloc(m->client, size, 0, heaps, flags, &hnd);
|
|
#else
|
|
ret = ion_alloc_fd(m->client, size, 0, heaps, flags, &fd);
|
|
#endif
|
|
if (ret < 0) {
|
|
ALOGE("gralloc ion_alloc fail errno:%d %s", errno, strerror_r(errno, errbuf, sizeof(errbuf)));
|
|
GRALLOC_ERROR_INFO();
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
|
|
#ifdef GRALLOC_NEED_SMMU_MAP
|
|
ret = ion_share(m->client, hnd, &fd);
|
|
if (ret < 0) {
|
|
GRALLOC_ERROR_INFO();
|
|
ion_free(m->client, hnd);
|
|
|
|
if (fd != -1) {
|
|
close(fd);
|
|
}
|
|
handle->hnd = -1;
|
|
handle->fd = -1;
|
|
handle->size = 0;
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
handle->hnd = hnd;
|
|
#endif
|
|
|
|
handle->size = size;
|
|
handle->fd = fd;
|
|
|
|
return GRALLOC_SUCCESS;
|
|
}
|
|
|
|
void gralloc_ion_free(const private_module_t *m, private_internal_handle_t *handle)
|
|
{
|
|
if (m == nullptr || handle == nullptr) {
|
|
GRALLOC_ERROR_INFO();
|
|
return;
|
|
}
|
|
|
|
int fd = handle->fd;
|
|
#ifdef GRALLOC_NEED_SMMU_MAP
|
|
int ret = 0;
|
|
ion_user_handle_t hnd = handle->hnd;
|
|
|
|
if (hnd != -1) {
|
|
ret = ion_free(m->client, hnd);
|
|
if (ret < 0) {
|
|
GRALLOC_ERROR_INFO();
|
|
return;
|
|
}
|
|
handle->hnd = -1;
|
|
} else {
|
|
GRALLOC_ERROR_INFO();
|
|
return;
|
|
}
|
|
#else
|
|
GRALLOC_IGNORE(m);
|
|
#endif
|
|
|
|
if (fd != -1) {
|
|
close(fd);
|
|
}
|
|
handle->fd = -1;
|
|
handle->size = 0;
|
|
}
|
|
|
|
int gralloc_ion_map(const private_module_t *m, private_internal_handle_t *handle)
|
|
{
|
|
char errbuf[256] = {0}; /* 256 is enough for err string */
|
|
|
|
if (m == nullptr || handle == nullptr) {
|
|
GRALLOC_ERROR_INFO();
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
|
|
int fd = handle->fd;
|
|
void *base = nullptr;
|
|
#ifdef GRALLOC_NEED_SMMU_MAP
|
|
unsigned int addr = (unsigned int)-1;
|
|
ion_user_handle_t hnd = -1;
|
|
size_t size = 0;
|
|
#else
|
|
size_t size = handle->size;
|
|
GRALLOC_IGNORE(m);
|
|
#endif
|
|
unsigned long long usage = handle->consumer_usage | handle->producer_usage;
|
|
|
|
#ifdef GRALLOC_NEED_SMMU_MAP
|
|
int ret;
|
|
ret = ion_import(m->client, fd, &hnd);
|
|
if (ret != 0) {
|
|
GRALLOC_ERROR_INFO();
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
|
|
ret = ion_map_iommu(m->client, hnd, &addr, &size, (usage & GRALLOC_USAGE_PROTECTED) ? 1 : 0);
|
|
if (ret != 0) {
|
|
ALOGE("gralloc ion_alloc fail errno:%d %s", errno, strerror_r(errno, errbuf, sizeof(errbuf)));
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
|
|
handle->hnd = hnd;
|
|
handle->addr = addr;
|
|
handle->size = size;
|
|
#endif
|
|
|
|
if (size <= 0) {
|
|
GRALLOC_ERROR_INFO();
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
|
|
if ((handle->flags & private_internal_handle_t::PRIV_FLAGS_USES_ION) &&
|
|
!(usage & GRALLOC_USAGE_PROTECTED)) {
|
|
base = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
if (base == MAP_FAILED) {
|
|
ALOGE("gralloc ion_alloc fail errno:%d %s", errno, strerror_r(errno, errbuf, sizeof(errbuf)));
|
|
GRALLOC_ERROR_INFO();
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
handle->base = base;
|
|
}
|
|
|
|
return GRALLOC_SUCCESS;
|
|
}
|
|
|
|
int gralloc_ion_unmap(const private_module_t *m, private_internal_handle_t *handle)
|
|
{
|
|
if (m == nullptr || handle == nullptr) {
|
|
GRALLOC_ERROR_INFO();
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
|
|
#ifdef GRALLOC_NEED_SMMU_MAP
|
|
int ret;
|
|
ion_user_handle_t hnd = handle->hnd;
|
|
#else
|
|
GRALLOC_IGNORE(m);
|
|
#endif
|
|
|
|
unsigned long long usage = handle->consumer_usage | handle->producer_usage;
|
|
|
|
if ((handle->flags & private_internal_handle_t::PRIV_FLAGS_USES_ION) &&
|
|
!(usage & GRALLOC_USAGE_PROTECTED) && handle->base != nullptr) {
|
|
munmap(handle->base, handle->size);
|
|
handle->base = MAP_FAILED;
|
|
}
|
|
|
|
#ifdef GRALLOC_NEED_SMMU_MAP
|
|
if (handle->addr != (unsigned int)-1) {
|
|
ret = ion_unmap_iommu(m->client, hnd, (usage & GRALLOC_USAGE_PROTECTED) ? 1 : 0);
|
|
if (ret < 0) {
|
|
GRALLOC_ERROR_INFO();
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
|
|
ret = ion_free(m->client, hnd);
|
|
if (ret < 0) {
|
|
GRALLOC_ERROR_INFO();
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
}
|
|
|
|
handle->hnd = -1;
|
|
handle->addr = (unsigned int)-1;
|
|
handle->size = 0;
|
|
#endif
|
|
return GRALLOC_SUCCESS;
|
|
}
|
|
|
|
int gralloc_ion_sync(const private_module_t *m, const private_internal_handle_t *handle)
|
|
{
|
|
if (m != nullptr && handle != nullptr) {
|
|
if ((handle->flags & private_internal_handle_t::PRIV_FLAGS_USES_ION) &&
|
|
!(handle->flags & private_internal_handle_t::PRIV_FLAGS_USES_ION_DMA_HEAP)) {
|
|
#ifdef GRALLOC_NEED_SMMU_MAP
|
|
ion_sync_fd(m->client, handle->fd);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return GRALLOC_SUCCESS;
|
|
}
|
|
|
|
int gralloc_dmabuf_sync(const private_internal_handle_t *handle, bool start)
|
|
{
|
|
struct dma_buf_sync sync;
|
|
int ret, retry;
|
|
|
|
/* flush master memory */
|
|
if (handle == nullptr) {
|
|
GRALLOC_ERROR_INFO();
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
if ((handle->flags & private_internal_handle_t::PRIV_FLAGS_USES_ION) &&
|
|
!(handle->flags & private_internal_handle_t::PRIV_FLAGS_USES_ION_DMA_HEAP)) {
|
|
unsigned long long usage = handle->producer_usage | handle->consumer_usage;
|
|
|
|
bool cpu_read = ((usage & GRALLOC_USAGE_SW_READ_MASK) != 0) ? true : false;
|
|
bool cpu_write = ((usage & GRALLOC_USAGE_SW_WRITE_MASK) != 0) ? true : false;
|
|
|
|
memset_s(&sync, sizeof(struct dma_buf_sync), 0, sizeof(struct dma_buf_sync));
|
|
|
|
/* START + READ: it would invalidate cache; END + WRITE: it would flush cache. */
|
|
if (start) {
|
|
sync.flags |= DMA_BUF_SYNC_START;
|
|
} else {
|
|
sync.flags |= DMA_BUF_SYNC_END;
|
|
}
|
|
|
|
if (cpu_read) {
|
|
sync.flags |= DMA_BUF_SYNC_READ;
|
|
}
|
|
|
|
if (cpu_write) {
|
|
sync.flags |= DMA_BUF_SYNC_WRITE;
|
|
}
|
|
|
|
retry = 5; /* try 5 times */
|
|
do {
|
|
ret = ioctl(handle->fd, DMA_BUF_IOCTL_SYNC, &sync);
|
|
retry--;
|
|
} while ((ret == -EAGAIN || ret == -EINTR) && retry);
|
|
|
|
if (ret < 0) {
|
|
GRALLOC_ERROR_INFO();
|
|
return GRALLOC_FAILURE;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|