/* // Copyright (c) 2014 Intel Corporation // // 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 // // http://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. */ #include <malloc.h> #include <string.h> #include <wsbm_pool.h> #include <wsbm_driver.h> #include <wsbm_manager.h> #include <wsbm_util.h> #include <drm/ttm/ttm_placement.h> #include <linux/psb_drm.h> #include <xf86drm.h> #include <common/utils/HwcTrace.h> struct _WsbmBufferPool * mainPool = NULL; struct PsbWsbmValidateNode { struct _ValidateNode base; struct psb_validate_arg arg; }; static inline uint32_t align_to(uint32_t arg, uint32_t align) { return ((arg + (align - 1)) & (~(align - 1))); } static struct _ValidateNode * pvrAlloc(struct _WsbmVNodeFuncs * func, int typeId) { CTRACE(); if(typeId == 0) { struct PsbWsbmValidateNode * vNode = malloc(sizeof(*vNode)); if(!vNode) { ELOGTRACE("failed to allocate memory"); return NULL; } vNode->base.func = func; vNode->base.type_id = 0; return &vNode->base; } else { struct _ValidateNode * node = malloc(sizeof(*node)); if(!node) { ELOGTRACE("failed to allocate node"); return NULL; } node->func = func; node->type_id = 1; return node; } } static void pvrFree(struct _ValidateNode * node) { CTRACE(); if(node->type_id == 0) { free(containerOf(node, struct PsbWsbmValidateNode, base)); } else { free(node); } } static void pvrClear(struct _ValidateNode * node) { CTRACE(); if(node->type_id == 0) { struct PsbWsbmValidateNode * vNode = containerOf(node, struct PsbWsbmValidateNode, base); memset(&vNode->arg.d.req, 0, sizeof(vNode->arg.d.req)); } } static struct _WsbmVNodeFuncs vNodeFuncs = { .alloc = pvrAlloc, .free = pvrFree, .clear = pvrClear, }; void psbWsbmTakedown() { CTRACE(); if (mainPool) { wsbmPoolTakeDown(mainPool); mainPool = NULL; } if (wsbmIsInitialized()) { wsbmTakedown(); } } int psbWsbmInitialize(int drmFD) { union drm_psb_extension_arg arg; const char drmExt[] = "psb_ttm_placement_alphadrop"; int ret = 0; CTRACE(); if (drmFD <= 0) { ELOGTRACE("invalid drm fd %d", drmFD); return drmFD; } /*init wsbm*/ ret = wsbmInit(wsbmNullThreadFuncs(), &vNodeFuncs); if (ret) { ELOGTRACE("failed to initialize Wsbm, error code %d", ret); return ret; } VLOGTRACE("DRM_PSB_EXTENSION %d", DRM_PSB_EXTENSION); /*get devOffset via drm IOCTL*/ strncpy(arg.extension, drmExt, sizeof(drmExt)); ret = drmCommandWriteRead(drmFD, 6/*DRM_PSB_EXTENSION*/, &arg, sizeof(arg)); if(ret || !arg.rep.exists) { ELOGTRACE("failed to get device offset, error code %d", ret); goto out; } unsigned int ioctl_offset = arg.rep.driver_ioctl_offset; ILOGTRACE("ioctl offset %#x", ioctl_offset); mainPool = wsbmTTMPoolInit(drmFD, arg.rep.driver_ioctl_offset); if(!mainPool) { ELOGTRACE("failed to initialize TTM Pool"); ret = -EINVAL; goto out; } VLOGTRACE("Wsbm initialization succeeded. mainPool %p", mainPool); return 0; out: psbWsbmTakedown(); return ret; } int psbWsbmAllocateFromUB(uint32_t size, uint32_t align, void ** buf, void *user_pt) { struct _WsbmBufferObject * wsbmBuf = NULL; int ret = 0; ALOGTRACE("size %d", align_to(size, 4096)); if(!buf || !user_pt) { ELOGTRACE("invalid parameter"); return -EINVAL; } VLOGTRACE("mainPool %p", mainPool); ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, align, DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_CACHED | WSBM_PL_FLAG_NO_EVICT | WSBM_PL_FLAG_SHARED); if(ret) { ELOGTRACE("wsbmGenBuffers failed with error code %d", ret); return ret; } ret = wsbmBODataUB(wsbmBuf, align_to(size, 4096), NULL, NULL, 0, user_pt, -1); if(ret) { ELOGTRACE("wsbmBOData failed with error code %d", ret); /*FIXME: should I unreference this buffer here?*/ return ret; } *buf = wsbmBuf; VLOGTRACE("ttm UB buffer allocated. %p", *buf); return 0; } int psbWsbmAllocateTTMBuffer(uint32_t size, uint32_t align, void ** buf) { struct _WsbmBufferObject * wsbmBuf = NULL; int ret = 0; ALOGTRACE("size %d", align_to(size, 4096)); if(!buf) { ELOGTRACE("invalid parameter"); return -EINVAL; } VLOGTRACE("mainPool %p", mainPool); ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, align, (WSBM_PL_FLAG_VRAM | WSBM_PL_FLAG_TT | WSBM_PL_FLAG_SHARED | WSBM_PL_FLAG_NO_EVICT)); if(ret) { ELOGTRACE("wsbmGenBuffers failed with error code %d", ret); return ret; } ret = wsbmBOData(wsbmBuf, align_to(size, 4096), NULL, NULL, 0); if(ret) { ELOGTRACE("wsbmBOData failed with error code %d", ret); /*FIXME: should I unreference this buffer here?*/ return ret; } /* wsbmBOReference(wsbmBuf); */ /* no need to add reference */ *buf = wsbmBuf; VLOGTRACE("ttm buffer allocated. %p", *buf); return 0; } int psbWsbmWrapTTMBuffer(uint32_t handle, void **buf) { int ret = 0; struct _WsbmBufferObject *wsbmBuf; if (!buf) { ELOGTRACE("invalid parameter"); return -EINVAL; } ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, 0, (WSBM_PL_FLAG_VRAM | WSBM_PL_FLAG_TT | /*WSBM_PL_FLAG_NO_EVICT |*/ WSBM_PL_FLAG_SHARED)); if (ret) { ELOGTRACE("wsbmGenBuffers failed with error code %d", ret); return ret; } ret = wsbmBOSetReferenced(wsbmBuf, handle); if (ret) { ELOGTRACE("wsbmBOSetReferenced failed with error code %d", ret); return ret; } *buf = (void *)wsbmBuf; VLOGTRACE("wrap buffer %p for handle %#x", wsbmBuf, handle); return 0; } int psbWsbmWrapTTMBuffer2(uint32_t handle, void **buf) { int ret = 0; struct _WsbmBufferObject *wsbmBuf; if (!buf) { ELOGTRACE("invalid parameter"); return -EINVAL; } ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, 4096, (WSBM_PL_FLAG_SHARED | DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_UNCACHED)); if (ret) { ELOGTRACE("wsbmGenBuffers failed with error code %d", ret); return ret; } *buf = (void *)wsbmBuf; VLOGTRACE("wrap buffer %p for handle %#x", wsbmBuf, handle); return 0; } int psbWsbmCreateFromUB(void *buf, uint32_t size, void *vaddr) { int ret = 0; struct _WsbmBufferObject *wsbmBuf; if (!buf || !vaddr) { ELOGTRACE("invalid parameter"); return -EINVAL; } wsbmBuf = (struct _WsbmBufferObject *)buf; ret = wsbmBODataUB(wsbmBuf, size, NULL, NULL, 0, vaddr, -1); if (ret) { ELOGTRACE("wsbmBODataUB failed with error code %d", ret); return ret; } return 0; } int psbWsbmUnReference(void *buf) { struct _WsbmBufferObject *wsbmBuf; if (!buf) { ELOGTRACE("invalid parameter"); return -EINVAL; } wsbmBuf = (struct _WsbmBufferObject *)buf; wsbmBOUnreference(&wsbmBuf); return 0; } int psbWsbmDestroyTTMBuffer(void * buf) { CTRACE(); if(!buf) { ELOGTRACE("invalid ttm buffer"); return -EINVAL; } /*FIXME: should I unmap this buffer object first?*/ wsbmBOUnmap((struct _WsbmBufferObject *)buf); wsbmBOUnreference((struct _WsbmBufferObject **)&buf); XLOGTRACE(); return 0; } void * psbWsbmGetCPUAddress(void * buf) { if(!buf) { ELOGTRACE("invalid ttm buffer"); return NULL; } VLOGTRACE("buffer object %p", buf); void * address = wsbmBOMap((struct _WsbmBufferObject *)buf, WSBM_ACCESS_READ | WSBM_ACCESS_WRITE); if(!address) { ELOGTRACE("failed to map buffer object"); return NULL; } unsigned long buf_size = wsbmBOSize((struct _WsbmBufferObject *)buf); VLOGTRACE("mapped successfully. %p, size %ld", address, buf_size); return address; } uint32_t psbWsbmGetGttOffset(void * buf) { if(!buf) { ELOGTRACE("invalid ttm buffer"); return 0; } VLOGTRACE("buffer object %p", buf); uint32_t offset = wsbmBOOffsetHint((struct _WsbmBufferObject *)buf) - 0x10000000; uint32_t offset_tmp = offset >> 12; VLOGTRACE("offset %#x", offset_tmp); return offset >> 12; } uint32_t psbWsbmGetKBufHandle(void *buf) { if (!buf) { ELOGTRACE("invalid ttm buffer"); return 0; } return (wsbmKBufHandle(wsbmKBuf((struct _WsbmBufferObject *)buf))); } uint32_t psbWsbmWaitIdle(void *buf) { if (!buf) { ELOGTRACE("invalid ttm buffer"); return -EINVAL; } wsbmBOWaitIdle(buf, 0); return 0; }