/**************************************************************************** * * The MIT License (MIT) * * Copyright (c) 2014 - 2018 Vivante Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * ***************************************************************************** * * The GPL License (GPL) * * Copyright (C) 2014 - 2018 Vivante Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************** * * Note: This software is released under dual MIT and GPL licenses. A * recipient may use this file under the terms of either the MIT license or * GPL License. If you wish to use only one license not the other, you can * indicate your decision by deleting one of the above license notices in your * version of this file. * *****************************************************************************/ #if gcdENABLE_DRM #include #include #include #include "gc_hal_kernel_linux.h" #include "gc_hal_drm.h" #define _GC_OBJ_ZONE gcvZONE_KERNEL /******************************************************************************\ ******************************* gckKERNEL DRM Code ****************************** \******************************************************************************/ struct viv_gem_object { struct drm_gem_object base; uint32_t node_handle; gckVIDMEM_NODE node_object; gctBOOL cacheable; }; struct dma_buf *viv_gem_prime_export(struct drm_device *drm, struct drm_gem_object *gem_obj, int flags) { struct viv_gem_object *viv_obj = container_of(gem_obj, struct viv_gem_object, base); struct dma_buf *dmabuf = gcvNULL; gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private; if (gal_dev) { gckKERNEL kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0]; gcmkVERIFY_OK(gckVIDMEM_NODE_Export(kernel, viv_obj->node_handle, flags, (gctPOINTER*)&dmabuf, gcvNULL)); } return dmabuf; } struct drm_gem_object *viv_gem_prime_import(struct drm_device *drm, struct dma_buf *dmabuf) { struct drm_gem_object *gem_obj = gcvNULL; struct viv_gem_object *viv_obj; gcsHAL_INTERFACE iface; gckGALDEVICE gal_dev; gckKERNEL kernel; gctUINT32 processID; gckVIDMEM_NODE nodeObject; gceSTATUS status = gcvSTATUS_OK; gal_dev = (gckGALDEVICE)drm->dev_private; if (!gal_dev) { gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } gckOS_ZeroMemory(&iface, sizeof(iface)); iface.command = gcvHAL_WRAP_USER_MEMORY; iface.hardwareType = gal_dev->device->defaultHwType; iface.u.WrapUserMemory.desc.flag = gcvALLOC_FLAG_DMABUF; iface.u.WrapUserMemory.desc.handle = -1; iface.u.WrapUserMemory.desc.dmabuf = gcmPTR_TO_UINT64(dmabuf); gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface)); kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0]; gcmkONERROR(gckOS_GetProcessID(&processID)); gcmkONERROR(gckVIDMEM_HANDLE_Lookup(kernel, processID, iface.u.WrapUserMemory.node, &nodeObject)); /* ioctl output */ gem_obj = kzalloc(sizeof(struct viv_gem_object), GFP_KERNEL); drm_gem_private_object_init(drm, gem_obj, dmabuf->size); viv_obj = container_of(gem_obj, struct viv_gem_object, base); viv_obj->node_handle = iface.u.WrapUserMemory.node; viv_obj->node_object = nodeObject; OnError: return gem_obj; } void viv_gem_free_object(struct drm_gem_object *gem_obj) { struct viv_gem_object *viv_obj = container_of(gem_obj, struct viv_gem_object, base); struct drm_device *drm = gem_obj->dev; gcsHAL_INTERFACE iface; gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private; gckOS_ZeroMemory(&iface, sizeof(iface)); iface.command = gcvHAL_RELEASE_VIDEO_MEMORY; iface.hardwareType = gal_dev->device->defaultHwType; iface.u.ReleaseVideoMemory.node = viv_obj->node_handle; gcmkVERIFY_OK(gckDEVICE_Dispatch(gal_dev->device, &iface)); drm_gem_object_release(gem_obj); kfree(gem_obj); } static int viv_ioctl_gem_create(struct drm_device *drm, void *data, struct drm_file *file) { int ret = 0; struct drm_viv_gem_create *args = (struct drm_viv_gem_create*)data; struct drm_gem_object *gem_obj = gcvNULL; struct viv_gem_object *viv_obj = gcvNULL; gcsHAL_INTERFACE iface; gckGALDEVICE gal_dev; gckKERNEL kernel; gctUINT32 processID; gckVIDMEM_NODE nodeObject; gctUINT32 flags = gcvALLOC_FLAG_DMABUF_EXPORTABLE; gceSTATUS status = gcvSTATUS_OK; gal_dev = (gckGALDEVICE)drm->dev_private; if (!gal_dev) { gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } if (args->flags & DRM_VIV_GEM_CONTIGUOUS) { flags |= gcvALLOC_FLAG_CONTIGUOUS; } if (args->flags & DRM_VIV_GEM_CACHED) { flags |= gcvALLOC_FLAG_CACHEABLE; } if (args->flags & DRM_VIV_GEM_SECURE) { flags |= gcvALLOC_FLAG_SECURITY; } if (args->flags & DRM_VIV_GEM_CMA_LIMIT) { flags |= gcvALLOC_FLAG_CMA_LIMIT; } gckOS_ZeroMemory(&iface, sizeof(iface)); iface.command = gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY; iface.hardwareType = gal_dev->device->defaultHwType; iface.u.AllocateLinearVideoMemory.bytes = PAGE_ALIGN(args->size); iface.u.AllocateLinearVideoMemory.alignment = 256; iface.u.AllocateLinearVideoMemory.type = gcvSURF_RENDER_TARGET; /* should be general */ iface.u.AllocateLinearVideoMemory.flag = flags; iface.u.AllocateLinearVideoMemory.pool = gcvPOOL_DEFAULT; gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface)); kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0]; gcmkONERROR(gckOS_GetProcessID(&processID)); gcmkONERROR(gckVIDMEM_HANDLE_Lookup(kernel, processID, iface.u.AllocateLinearVideoMemory.node, &nodeObject)); /* ioctl output */ gem_obj = kzalloc(sizeof(struct viv_gem_object), GFP_KERNEL); drm_gem_private_object_init(drm, gem_obj, iface.u.AllocateLinearVideoMemory.bytes); ret = drm_gem_handle_create(file, gem_obj, &args->handle); viv_obj = container_of(gem_obj, struct viv_gem_object, base); viv_obj->node_handle = iface.u.AllocateLinearVideoMemory.node; viv_obj->node_object = nodeObject; viv_obj->cacheable = flags & gcvALLOC_FLAG_CACHEABLE; /* drop reference from allocate - handle holds it now */ drm_gem_object_unreference_unlocked(gem_obj); OnError: return gcmIS_ERROR(status) ? -ENOTTY : 0; } static int viv_ioctl_gem_lock(struct drm_device *drm, void *data, struct drm_file *file) { struct drm_viv_gem_lock *args = (struct drm_viv_gem_lock*)data; struct drm_gem_object *gem_obj = gcvNULL; struct viv_gem_object *viv_obj = gcvNULL; gcsHAL_INTERFACE iface; gceSTATUS status = gcvSTATUS_OK; gckGALDEVICE gal_dev = gcvNULL; gal_dev = (gckGALDEVICE)drm->dev_private; if (!gal_dev) { gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } gem_obj = drm_gem_object_lookup(file, args->handle); if (!gem_obj) { gcmkONERROR(gcvSTATUS_NOT_FOUND); } viv_obj = container_of(gem_obj, struct viv_gem_object, base); gckOS_ZeroMemory(&iface, sizeof(iface)); iface.command = gcvHAL_LOCK_VIDEO_MEMORY; iface.hardwareType = gal_dev->device->defaultHwType; iface.u.LockVideoMemory.node = viv_obj->node_handle; iface.u.LockVideoMemory.cacheable = args->cacheable; gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface)); args->logical = iface.u.LockVideoMemory.memory; OnError: if (gem_obj) { drm_gem_object_unreference_unlocked(gem_obj); } return gcmIS_ERROR(status) ? -ENOTTY : 0; } static int viv_ioctl_gem_unlock(struct drm_device *drm, void *data, struct drm_file *file) { struct drm_viv_gem_unlock *args = (struct drm_viv_gem_unlock*)data; struct drm_gem_object *gem_obj = gcvNULL; struct viv_gem_object *viv_obj = gcvNULL; gcsHAL_INTERFACE iface; gceSTATUS status = gcvSTATUS_OK; gckGALDEVICE gal_dev = gcvNULL; gal_dev = (gckGALDEVICE)drm->dev_private; if (!gal_dev) { gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } gem_obj = drm_gem_object_lookup(file, args->handle); if (!gem_obj) { gcmkONERROR(gcvSTATUS_NOT_FOUND); } viv_obj = container_of(gem_obj, struct viv_gem_object, base); memset(&iface, 0, sizeof(iface)); iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY; iface.hardwareType = gal_dev->device->defaultHwType; iface.u.UnlockVideoMemory.node = (gctUINT64)viv_obj->node_handle; iface.u.UnlockVideoMemory.type = gcvSURF_TYPE_UNKNOWN; gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface)); memset(&iface, 0, sizeof(iface)); iface.command = gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY; iface.hardwareType = gal_dev->device->defaultHwType; iface.u.BottomHalfUnlockVideoMemory.node = (gctUINT64)viv_obj->node_handle; iface.u.BottomHalfUnlockVideoMemory.type = gcvSURF_TYPE_UNKNOWN; gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface)); OnError: if (gem_obj) { drm_gem_object_unreference_unlocked(gem_obj); } return gcmIS_ERROR(status) ? -ENOTTY : 0; } static int viv_ioctl_gem_cache(struct drm_device *drm, void *data, struct drm_file *file) { struct drm_viv_gem_cache *args = (struct drm_viv_gem_cache*)data; struct drm_gem_object *gem_obj = gcvNULL; struct viv_gem_object *viv_obj = gcvNULL; gcsHAL_INTERFACE iface; gceSTATUS status = gcvSTATUS_OK; gckGALDEVICE gal_dev = gcvNULL; gceCACHEOPERATION cache_op = 0; gal_dev = (gckGALDEVICE)drm->dev_private; if (!gal_dev) { gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } gem_obj = drm_gem_object_lookup(file, args->handle); if (!gem_obj) { gcmkONERROR(gcvSTATUS_NOT_FOUND); } viv_obj = container_of(gem_obj, struct viv_gem_object, base); switch (args->op) { case DRM_VIV_GEM_CLEAN_CACHE: cache_op = gcvCACHE_CLEAN; break; case DRM_VIV_GEM_INVALIDATE_CACHE: cache_op = gcvCACHE_INVALIDATE; break; case DRM_VIV_GEM_FLUSH_CACHE: cache_op = gcvCACHE_FLUSH; break; case DRM_VIV_GEM_MEMORY_BARRIER: cache_op = gcvCACHE_MEMORY_BARRIER; break; default: break; } gckOS_ZeroMemory(&iface, sizeof(iface)); iface.command = gcvHAL_CACHE; iface.hardwareType = gal_dev->device->defaultHwType; iface.u.Cache.node = viv_obj->node_handle; iface.u.Cache.operation = cache_op; iface.u.Cache.logical = args->logical; iface.u.Cache.bytes = args->bytes; gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface)); OnError: if (gem_obj) { drm_gem_object_unreference_unlocked(gem_obj); } return gcmIS_ERROR(status) ? -ENOTTY : 0; } static int viv_ioctl_gem_query(struct drm_device *drm, void *data, struct drm_file *file) { struct drm_viv_gem_query *args = (struct drm_viv_gem_query*)data; struct drm_gem_object *gem_obj = gcvNULL; struct viv_gem_object *viv_obj = gcvNULL; gceSTATUS status = gcvSTATUS_OK; gckGALDEVICE gal_dev = gcvNULL; gal_dev = (gckGALDEVICE)drm->dev_private; if (!gal_dev) { gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } gem_obj = drm_gem_object_lookup(file, args->handle); if (!gem_obj) { gcmkONERROR(gcvSTATUS_NOT_FOUND); } viv_obj = container_of(gem_obj, struct viv_gem_object, base); switch (args->param) { case DRM_VIV_GEM_PARAM_POOL: args->value = (__u64)viv_obj->node_object->pool; break; case DRM_VIV_GEM_PARAM_SIZE: args->value = (__u64)gem_obj->size; break; default: gcmkONERROR(gcvSTATUS_NOT_SUPPORTED); } OnError: if (gem_obj) { drm_gem_object_unreference_unlocked(gem_obj); } return gcmIS_ERROR(status) ? -ENOTTY : 0; } static int viv_ioctl_gem_timestamp(struct drm_device *drm, void *data, struct drm_file *file) { struct drm_viv_gem_timestamp *args = (struct drm_viv_gem_timestamp *)data; struct drm_gem_object *gem_obj = gcvNULL; struct viv_gem_object *viv_obj = gcvNULL; gceSTATUS status = gcvSTATUS_OK; gckGALDEVICE gal_dev = gcvNULL; gal_dev = (gckGALDEVICE)drm->dev_private; if (!gal_dev) { gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } gem_obj = drm_gem_object_lookup(file, args->handle); if (!gem_obj) { gcmkONERROR(gcvSTATUS_NOT_FOUND); } viv_obj = container_of(gem_obj, struct viv_gem_object, base); viv_obj->node_object->timeStamp += args->inc; args->timestamp = viv_obj->node_object->timeStamp; OnError: if (gem_obj) { drm_gem_object_unreference_unlocked(gem_obj); } return gcmIS_ERROR(status) ? -ENOTTY : 0; } static int viv_ioctl_gem_set_tiling(struct drm_device *drm, void *data, struct drm_file *file) { struct drm_viv_gem_set_tiling *args = (struct drm_viv_gem_set_tiling*)data; struct drm_gem_object *gem_obj = gcvNULL; struct viv_gem_object *viv_obj = gcvNULL; gceSTATUS status = gcvSTATUS_OK; gckGALDEVICE gal_dev = gcvNULL; gal_dev = (gckGALDEVICE)drm->dev_private; if (!gal_dev) { gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } gem_obj = drm_gem_object_lookup(file, args->handle); if (!gem_obj) { gcmkONERROR(gcvSTATUS_NOT_FOUND); } viv_obj = container_of(gem_obj, struct viv_gem_object, base); viv_obj->node_object->tilingMode = args->tiling_mode; viv_obj->node_object->tsMode = args->ts_mode; viv_obj->node_object->clearValue = args->clear_value; OnError: if (gem_obj) { drm_gem_object_unreference_unlocked(gem_obj); } return gcmIS_ERROR(status) ? -ENOTTY : 0; } static int viv_ioctl_gem_get_tiling(struct drm_device *drm, void *data, struct drm_file *file) { struct drm_viv_gem_get_tiling *args = (struct drm_viv_gem_get_tiling*)data; struct drm_gem_object *gem_obj = gcvNULL; struct viv_gem_object *viv_obj = gcvNULL; gceSTATUS status = gcvSTATUS_OK; gckGALDEVICE gal_dev = gcvNULL; gal_dev = (gckGALDEVICE)drm->dev_private; if (!gal_dev) { gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } gem_obj = drm_gem_object_lookup(file, args->handle); if (!gem_obj) { gcmkONERROR(gcvSTATUS_NOT_FOUND); } viv_obj = container_of(gem_obj, struct viv_gem_object, base); args->tiling_mode = viv_obj->node_object->tilingMode; args->ts_mode = viv_obj->node_object->tsMode; args->clear_value = viv_obj->node_object->clearValue; OnError: if (gem_obj) { drm_gem_object_unreference_unlocked(gem_obj); } return gcmIS_ERROR(status) ? -ENOTTY : 0; } static int viv_ioctl_gem_attach_aux(struct drm_device *drm, void *data, struct drm_file *file) { struct drm_viv_gem_attach_aux *args = (struct drm_viv_gem_attach_aux*)data; struct drm_gem_object *gem_obj = gcvNULL; struct viv_gem_object *viv_obj = gcvNULL; struct drm_gem_object *gem_ts_obj = gcvNULL; gceSTATUS status = gcvSTATUS_OK; gckGALDEVICE gal_dev = gcvNULL; gckVIDMEM_NODE nodeObj = gcvNULL; gal_dev = (gckGALDEVICE)drm->dev_private; if (!gal_dev) { gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } gem_obj = drm_gem_object_lookup(file, args->handle); if (!gem_obj) { gcmkONERROR(gcvSTATUS_NOT_FOUND); } viv_obj = container_of(gem_obj, struct viv_gem_object, base); nodeObj = viv_obj->node_object; /* do not support re-attach */ if (nodeObj->tsNode) { gcmkONERROR(gcvSTATUS_NOT_SUPPORTED); } if (args->ts_handle) { struct viv_gem_object *viv_ts_obj; gckKERNEL kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0]; gcsHAL_INTERFACE iface; gctBOOL is128BTILE = gckHARDWARE_IsFeatureAvailable(kernel->hardware , gcvFEATURE_128BTILE); gctBOOL is2BitPerTile = is128BTILE ? gcvFALSE : gckHARDWARE_IsFeatureAvailable(kernel->hardware , gcvFEATURE_TILE_STATUS_2BITS); gctBOOL isCompressionDEC400 = gckHARDWARE_IsFeatureAvailable(kernel->hardware , gcvFEATURE_COMPRESSION_DEC400); gctPOINTER entry = gcvNULL; gctUINT32 tileStatusFiller = (isCompressionDEC400 || ((kernel->hardware->identity.chipModel == gcv500) && (kernel->hardware->identity.chipRevision > 2))) ? 0xFFFFFFFF : is2BitPerTile ? 0x55555555 : 0x11111111; gem_ts_obj = drm_gem_object_lookup(file, args->ts_handle); if (!gem_ts_obj) { gcmkONERROR(gcvSTATUS_NOT_FOUND); } viv_ts_obj = container_of(gem_ts_obj, struct viv_gem_object, base); gcmkONERROR(gckVIDMEM_NODE_Reference(kernel, viv_ts_obj->node_object)); nodeObj->tsNode = viv_ts_obj->node_object; /* Fill tile status node with tileStatusFiller value first time to avoid GPU hang. */ /* Lock tile status node. */ gckOS_ZeroMemory(&iface, sizeof(iface)); iface.command = gcvHAL_LOCK_VIDEO_MEMORY; iface.hardwareType = gal_dev->device->defaultHwType; iface.u.LockVideoMemory.node = viv_ts_obj->node_handle; iface.u.LockVideoMemory.cacheable = viv_ts_obj->cacheable; gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface)); /* Fill tile status node with tileStatusFiller. */ gcmkONERROR(gckVIDMEM_NODE_LockCPU(kernel, viv_ts_obj->node_handle, &entry)); memset(entry , tileStatusFiller , (__u64)gem_ts_obj->size); gcmkONERROR(gckVIDMEM_NODE_UnlockCPU(kernel, viv_ts_obj->node_handle, entry)); /* UnLock tile status node. */ memset(&iface, 0, sizeof(iface)); iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY; iface.hardwareType = gal_dev->device->defaultHwType; iface.u.UnlockVideoMemory.node = (gctUINT64)viv_ts_obj->node_handle; iface.u.UnlockVideoMemory.type = gcvSURF_TYPE_UNKNOWN; gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface)); memset(&iface, 0, sizeof(iface)); iface.command = gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY; iface.hardwareType = gal_dev->device->defaultHwType; iface.u.BottomHalfUnlockVideoMemory.node = (gctUINT64)viv_ts_obj->node_handle; iface.u.BottomHalfUnlockVideoMemory.type = gcvSURF_TYPE_UNKNOWN; gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface)); } OnError: if (gem_obj) { drm_gem_object_unreference_unlocked(gem_obj); if (gem_ts_obj) { drm_gem_object_unreference_unlocked(gem_ts_obj); } } return gcmIS_ERROR(status) ? -ENOTTY : 0; } static int viv_ioctl_gem_ref_node(struct drm_device *drm, void *data, struct drm_file *file) { struct drm_viv_gem_ref_node *args = (struct drm_viv_gem_ref_node*)data; struct drm_gem_object *gem_obj = gcvNULL; struct viv_gem_object *viv_obj = gcvNULL; gceSTATUS status = gcvSTATUS_OK; gckGALDEVICE gal_dev = gcvNULL; gckKERNEL kernel = gcvNULL; gctUINT32 processID; gckVIDMEM_NODE nodeObj; gctUINT32 nodeHandle = 0, tsNodeHandle = 0; gctBOOL refered = gcvFALSE; int ret = 0; gal_dev = (gckGALDEVICE)drm->dev_private; if (!gal_dev) { gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); } kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0]; gem_obj = drm_gem_object_lookup(file, args->handle); if (!gem_obj) { gcmkONERROR(gcvSTATUS_NOT_FOUND); } viv_obj = container_of(gem_obj, struct viv_gem_object, base); nodeObj = viv_obj->node_object; gcmkONERROR(gckOS_GetProcessID(&processID)); gcmkONERROR(gckVIDMEM_HANDLE_Allocate(kernel, nodeObj, &nodeHandle)); gcmkONERROR( gckKERNEL_AddProcessDB(kernel, processID, gcvDB_VIDEO_MEMORY, gcmINT2PTR(nodeHandle), gcvNULL, 0)); gcmkONERROR(gckVIDMEM_NODE_Reference(kernel, nodeObj)); refered = gcvTRUE; if (nodeObj->tsNode) { gcmkONERROR(gckVIDMEM_HANDLE_Allocate(kernel, nodeObj->tsNode, &tsNodeHandle)); gcmkONERROR( gckKERNEL_AddProcessDB(kernel, processID, gcvDB_VIDEO_MEMORY, gcmINT2PTR(tsNodeHandle), gcvNULL, 0)); gcmkONERROR(gckVIDMEM_NODE_Reference(kernel, nodeObj->tsNode)); } args->node = nodeHandle; args->ts_node = tsNodeHandle; OnError: if (gcmIS_ERROR(status) && kernel) { gctUINT32 processID; gcmkVERIFY_OK(gckOS_GetProcessID(&processID)); if (tsNodeHandle) { gckVIDMEM_HANDLE_Dereference(kernel, processID, tsNodeHandle); } if (nodeHandle) { gckVIDMEM_HANDLE_Dereference(kernel, processID, nodeHandle); } if (refered) { gcmkONERROR(gckVIDMEM_NODE_Dereference(kernel, nodeObj)); } args->node = 0; args->ts_node = 0; ret = -ENOTTY; } if (gem_obj) { drm_gem_object_unreference_unlocked(gem_obj); } return ret; } static const struct drm_ioctl_desc viv_ioctls[] = { DRM_IOCTL_DEF_DRV(VIV_GEM_CREATE, viv_ioctl_gem_create, DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIV_GEM_LOCK, viv_ioctl_gem_lock, DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIV_GEM_UNLOCK, viv_ioctl_gem_unlock, DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIV_GEM_CACHE, viv_ioctl_gem_cache, DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIV_GEM_QUERY, viv_ioctl_gem_query, DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIV_GEM_TIMESTAMP, viv_ioctl_gem_timestamp, DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIV_GEM_SET_TILING, viv_ioctl_gem_set_tiling, DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIV_GEM_GET_TILING, viv_ioctl_gem_get_tiling, DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIV_GEM_ATTACH_AUX, viv_ioctl_gem_attach_aux, DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VIV_GEM_REF_NODE, viv_ioctl_gem_ref_node, DRM_AUTH | DRM_RENDER_ALLOW), }; int viv_drm_open(struct drm_device *drm, struct drm_file *file) { gctINT i; gctUINT32 pid = _GetProcessID(); gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private; gceSTATUS status = gcvSTATUS_OK; for (i = 0; i < gcdMAX_GPU_COUNT; ++i) { if (gal_dev->kernels[i]) { gcmkONERROR(gckKERNEL_AttachProcessEx(gal_dev->kernels[i], gcvTRUE, pid)); } } file->driver_priv = gcmINT2PTR(pid); OnError: return gcmIS_ERROR(status) ? -ENODEV : 0; } void viv_drm_postclose(struct drm_device *drm, struct drm_file *file) { gctINT i; gctUINT32 pid = gcmPTR2SIZE(file->driver_priv); gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private; for (i = 0; i < gcdMAX_GPU_COUNT; ++i) { if (gal_dev->kernels[i]) { gcmkVERIFY_OK(gckKERNEL_AttachProcessEx(gal_dev->kernels[i], gcvFALSE, pid)); } } } static const struct file_operations viv_drm_fops = { .owner = THIS_MODULE, .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, #endif .poll = drm_poll, .read = drm_read, .llseek = no_llseek, }; static struct drm_driver viv_drm_driver = { .driver_features = DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER, .open = viv_drm_open, .postclose = viv_drm_postclose, #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) .gem_free_object_unlocked = viv_gem_free_object, #else .gem_free_object = viv_gem_free_object, #endif .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_export = viv_gem_prime_export, .gem_prime_import = viv_gem_prime_import, .ioctls = viv_ioctls, .num_ioctls = DRM_VIV_NUM_IOCTLS, .fops = &viv_drm_fops, .name = "vivante", .desc = "vivante DRM", .date = "20170808", .major = 1, .minor = 0, }; int viv_drm_probe(struct device *dev) { int ret = 0; gceSTATUS status = gcvSTATUS_OK; gckGALDEVICE gal_dev = gcvNULL; struct drm_device *drm = gcvNULL; gal_dev = (gckGALDEVICE)dev_get_drvdata(dev); if (!gal_dev) { ret = -ENODEV; gcmkONERROR(gcvSTATUS_INVALID_OBJECT); } drm = drm_dev_alloc(&viv_drm_driver, dev); if (IS_ERR(drm)) { ret = PTR_ERR(drm); gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); } drm->dev_private = (void*)gal_dev; ret = drm_dev_register(drm, 0); if (ret) { gcmkONERROR(gcvSTATUS_GENERIC_IO); } gal_dev->drm = (void*)drm; OnError: if (gcmIS_ERROR(status)) { if (drm) { drm_dev_unref(drm); } printk(KERN_ERR "galcore: Failed to setup drm device.\n"); } return ret; } int viv_drm_remove(struct device *dev) { gckGALDEVICE gal_dev = (gckGALDEVICE)dev_get_drvdata(dev); if (gal_dev) { struct drm_device *drm = (struct drm_device*)gal_dev->drm; drm_dev_unregister(drm); drm_dev_unref(drm); } return 0; } #endif