blob: 03b28eb108c71896fbc417f62506857b755054ce [file] [log] [blame]
/**********************************************************************
*
* Copyright (C) Imagination Technologies Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful but, except
* as otherwise stated in writing, 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* Imagination Technologies Ltd. <gpl-support@imgtec.com>
* Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
*
******************************************************************************/
#include <stddef.h>
#include "services_headers.h"
#include "buffer_manager.h"
#include "pdump_km.h"
#include "pvr_bridge_km.h"
#include "osfunc.h"
static PVRSRV_ERROR AllocDeviceMem(IMG_HANDLE hDevCookie,
IMG_HANDLE hDevMemHeap,
IMG_UINT32 ui32Flags,
IMG_SIZE_T ui32Size,
IMG_SIZE_T ui32Alignment,
IMG_PVOID pvPrivData,
IMG_UINT32 ui32PrivDataLength,
PVRSRV_KERNEL_MEM_INFO **ppsMemInfo);
typedef struct _RESMAN_MAP_DEVICE_MEM_DATA_
{
PVRSRV_KERNEL_MEM_INFO *psMemInfo;
PVRSRV_KERNEL_MEM_INFO *psSrcMemInfo;
} RESMAN_MAP_DEVICE_MEM_DATA;
typedef struct _PVRSRV_DC_MAPINFO_
{
PVRSRV_KERNEL_MEM_INFO *psMemInfo;
PVRSRV_DEVICE_NODE *psDeviceNode;
IMG_UINT32 ui32RangeIndex;
IMG_UINT32 ui32TilingStride;
PVRSRV_DEVICECLASS_BUFFER *psDeviceClassBuffer;
} PVRSRV_DC_MAPINFO;
static IMG_UINT32 g_ui32SyncUID = 0;
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVGetDeviceMemHeapsKM(IMG_HANDLE hDevCookie,
#if defined (SUPPORT_SID_INTERFACE)
PVRSRV_HEAP_INFO_KM *psHeapInfo)
#else
PVRSRV_HEAP_INFO *psHeapInfo)
#endif
{
PVRSRV_DEVICE_NODE *psDeviceNode;
IMG_UINT32 ui32HeapCount;
DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
IMG_UINT32 i;
if (hDevCookie == IMG_NULL)
{
PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetDeviceMemHeapsKM: hDevCookie invalid"));
PVR_DBG_BREAK;
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDeviceNode = (PVRSRV_DEVICE_NODE *)hDevCookie;
ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount;
psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;
PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS);
for(i=0; i<ui32HeapCount; i++)
{
psHeapInfo[i].ui32HeapID = psDeviceMemoryHeap[i].ui32HeapID;
psHeapInfo[i].hDevMemHeap = psDeviceMemoryHeap[i].hDevMemHeap;
psHeapInfo[i].sDevVAddrBase = psDeviceMemoryHeap[i].sDevVAddrBase;
psHeapInfo[i].ui32HeapByteSize = psDeviceMemoryHeap[i].ui32HeapSize;
psHeapInfo[i].ui32Attribs = psDeviceMemoryHeap[i].ui32Attribs;
psHeapInfo[i].ui32XTileStride = psDeviceMemoryHeap[i].ui32XTileStride;
}
for(; i < PVRSRV_MAX_CLIENT_HEAPS; i++)
{
OSMemSet(psHeapInfo + i, 0, sizeof(*psHeapInfo));
psHeapInfo[i].ui32HeapID = (IMG_UINT32)PVRSRV_UNDEFINED_HEAP_ID;
}
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateDeviceMemContextKM(IMG_HANDLE hDevCookie,
PVRSRV_PER_PROCESS_DATA *psPerProc,
IMG_HANDLE *phDevMemContext,
IMG_UINT32 *pui32ClientHeapCount,
#if defined (SUPPORT_SID_INTERFACE)
PVRSRV_HEAP_INFO_KM *psHeapInfo,
#else
PVRSRV_HEAP_INFO *psHeapInfo,
#endif
IMG_BOOL *pbCreated,
IMG_BOOL *pbShared)
{
PVRSRV_DEVICE_NODE *psDeviceNode;
IMG_UINT32 ui32HeapCount, ui32ClientHeapCount=0;
DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
IMG_HANDLE hDevMemContext;
IMG_HANDLE hDevMemHeap;
IMG_DEV_PHYADDR sPDDevPAddr;
IMG_UINT32 i;
#if !defined(PVR_SECURE_HANDLES) && !defined (SUPPORT_SID_INTERFACE)
PVR_UNREFERENCED_PARAMETER(pbShared);
#endif
if (hDevCookie == IMG_NULL)
{
PVR_DPF((PVR_DBG_ERROR, "PVRSRVCreateDeviceMemContextKM: hDevCookie invalid"));
PVR_DBG_BREAK;
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDeviceNode = (PVRSRV_DEVICE_NODE *)hDevCookie;
ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount;
psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;
PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS);
hDevMemContext = BM_CreateContext(psDeviceNode,
&sPDDevPAddr,
psPerProc,
pbCreated);
if (hDevMemContext == IMG_NULL)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateDeviceMemContextKM: Failed BM_CreateContext"));
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
for(i=0; i<ui32HeapCount; i++)
{
switch(psDeviceMemoryHeap[i].DevMemHeapType)
{
case DEVICE_MEMORY_HEAP_SHARED_EXPORTED:
{
psHeapInfo[ui32ClientHeapCount].ui32HeapID = psDeviceMemoryHeap[i].ui32HeapID;
psHeapInfo[ui32ClientHeapCount].hDevMemHeap = psDeviceMemoryHeap[i].hDevMemHeap;
psHeapInfo[ui32ClientHeapCount].sDevVAddrBase = psDeviceMemoryHeap[i].sDevVAddrBase;
psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize = psDeviceMemoryHeap[i].ui32HeapSize;
psHeapInfo[ui32ClientHeapCount].ui32Attribs = psDeviceMemoryHeap[i].ui32Attribs;
#if defined(SUPPORT_MEMORY_TILING)
psHeapInfo[ui32ClientHeapCount].ui32XTileStride = psDeviceMemoryHeap[i].ui32XTileStride;
#else
psHeapInfo[ui32ClientHeapCount].ui32XTileStride = 0;
#endif
#if defined(PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE)
pbShared[ui32ClientHeapCount] = IMG_TRUE;
#endif
ui32ClientHeapCount++;
break;
}
case DEVICE_MEMORY_HEAP_PERCONTEXT:
{
if (psDeviceMemoryHeap[i].ui32HeapSize > 0)
{
hDevMemHeap = BM_CreateHeap(hDevMemContext,
&psDeviceMemoryHeap[i]);
if (hDevMemHeap == IMG_NULL)
{
BM_DestroyContext(hDevMemContext, IMG_NULL);
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
}
else
{
hDevMemHeap = IMG_NULL;
}
psHeapInfo[ui32ClientHeapCount].ui32HeapID = psDeviceMemoryHeap[i].ui32HeapID;
psHeapInfo[ui32ClientHeapCount].hDevMemHeap = hDevMemHeap;
psHeapInfo[ui32ClientHeapCount].sDevVAddrBase = psDeviceMemoryHeap[i].sDevVAddrBase;
psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize = psDeviceMemoryHeap[i].ui32HeapSize;
psHeapInfo[ui32ClientHeapCount].ui32Attribs = psDeviceMemoryHeap[i].ui32Attribs;
#if defined(SUPPORT_MEMORY_TILING)
psHeapInfo[ui32ClientHeapCount].ui32XTileStride = psDeviceMemoryHeap[i].ui32XTileStride;
#else
psHeapInfo[ui32ClientHeapCount].ui32XTileStride = 0;
#endif
#if defined(PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE)
pbShared[ui32ClientHeapCount] = IMG_FALSE;
#endif
ui32ClientHeapCount++;
break;
}
}
}
*pui32ClientHeapCount = ui32ClientHeapCount;
*phDevMemContext = hDevMemContext;
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroyDeviceMemContextKM(IMG_HANDLE hDevCookie,
IMG_HANDLE hDevMemContext,
IMG_BOOL *pbDestroyed)
{
PVR_UNREFERENCED_PARAMETER(hDevCookie);
return BM_DestroyContext(hDevMemContext, pbDestroyed);
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVGetDeviceMemHeapInfoKM(IMG_HANDLE hDevCookie,
IMG_HANDLE hDevMemContext,
IMG_UINT32 *pui32ClientHeapCount,
#if defined (SUPPORT_SID_INTERFACE)
PVRSRV_HEAP_INFO_KM *psHeapInfo,
#else
PVRSRV_HEAP_INFO *psHeapInfo,
#endif
IMG_BOOL *pbShared)
{
PVRSRV_DEVICE_NODE *psDeviceNode;
IMG_UINT32 ui32HeapCount, ui32ClientHeapCount=0;
DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
IMG_HANDLE hDevMemHeap;
IMG_UINT32 i;
#if !defined(PVR_SECURE_HANDLES) && !defined (SUPPORT_SID_INTERFACE)
PVR_UNREFERENCED_PARAMETER(pbShared);
#endif
if (hDevCookie == IMG_NULL)
{
PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetDeviceMemHeapInfoKM: hDevCookie invalid"));
PVR_DBG_BREAK;
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDeviceNode = (PVRSRV_DEVICE_NODE *)hDevCookie;
ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount;
psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;
PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS);
for(i=0; i<ui32HeapCount; i++)
{
switch(psDeviceMemoryHeap[i].DevMemHeapType)
{
case DEVICE_MEMORY_HEAP_SHARED_EXPORTED:
{
psHeapInfo[ui32ClientHeapCount].ui32HeapID = psDeviceMemoryHeap[i].ui32HeapID;
psHeapInfo[ui32ClientHeapCount].hDevMemHeap = psDeviceMemoryHeap[i].hDevMemHeap;
psHeapInfo[ui32ClientHeapCount].sDevVAddrBase = psDeviceMemoryHeap[i].sDevVAddrBase;
psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize = psDeviceMemoryHeap[i].ui32HeapSize;
psHeapInfo[ui32ClientHeapCount].ui32Attribs = psDeviceMemoryHeap[i].ui32Attribs;
psHeapInfo[ui32ClientHeapCount].ui32XTileStride = psDeviceMemoryHeap[i].ui32XTileStride;
#if defined(PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE)
pbShared[ui32ClientHeapCount] = IMG_TRUE;
#endif
ui32ClientHeapCount++;
break;
}
case DEVICE_MEMORY_HEAP_PERCONTEXT:
{
if (psDeviceMemoryHeap[i].ui32HeapSize > 0)
{
hDevMemHeap = BM_CreateHeap(hDevMemContext,
&psDeviceMemoryHeap[i]);
if (hDevMemHeap == IMG_NULL)
{
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
}
else
{
hDevMemHeap = IMG_NULL;
}
psHeapInfo[ui32ClientHeapCount].ui32HeapID = psDeviceMemoryHeap[i].ui32HeapID;
psHeapInfo[ui32ClientHeapCount].hDevMemHeap = hDevMemHeap;
psHeapInfo[ui32ClientHeapCount].sDevVAddrBase = psDeviceMemoryHeap[i].sDevVAddrBase;
psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize = psDeviceMemoryHeap[i].ui32HeapSize;
psHeapInfo[ui32ClientHeapCount].ui32Attribs = psDeviceMemoryHeap[i].ui32Attribs;
psHeapInfo[ui32ClientHeapCount].ui32XTileStride = psDeviceMemoryHeap[i].ui32XTileStride;
#if defined(PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE)
pbShared[ui32ClientHeapCount] = IMG_FALSE;
#endif
ui32ClientHeapCount++;
break;
}
}
}
*pui32ClientHeapCount = ui32ClientHeapCount;
return PVRSRV_OK;
}
static PVRSRV_ERROR AllocDeviceMem(IMG_HANDLE hDevCookie,
IMG_HANDLE hDevMemHeap,
IMG_UINT32 ui32Flags,
IMG_SIZE_T ui32Size,
IMG_SIZE_T ui32Alignment,
IMG_PVOID pvPrivData,
IMG_UINT32 ui32PrivDataLength,
PVRSRV_KERNEL_MEM_INFO **ppsMemInfo)
{
PVRSRV_KERNEL_MEM_INFO *psMemInfo;
BM_HANDLE hBuffer;
PVRSRV_MEMBLK *psMemBlock;
IMG_BOOL bBMError;
PVR_UNREFERENCED_PARAMETER(hDevCookie);
*ppsMemInfo = IMG_NULL;
if(OSAllocMem(PVRSRV_PAGEABLE_SELECT,
sizeof(PVRSRV_KERNEL_MEM_INFO),
(IMG_VOID **)&psMemInfo, IMG_NULL,
"Kernel Memory Info") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"AllocDeviceMem: Failed to alloc memory for block"));
return (PVRSRV_ERROR_OUT_OF_MEMORY);
}
OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
psMemBlock = &(psMemInfo->sMemBlk);
psMemInfo->ui32Flags = ui32Flags | PVRSRV_MEM_RAM_BACKED_ALLOCATION;
bBMError = BM_Alloc (hDevMemHeap,
IMG_NULL,
ui32Size,
&psMemInfo->ui32Flags,
IMG_CAST_TO_DEVVADDR_UINT(ui32Alignment),
pvPrivData,
ui32PrivDataLength,
&hBuffer);
if (!bBMError)
{
PVR_DPF((PVR_DBG_ERROR,"AllocDeviceMem: BM_Alloc Failed"));
OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_KERNEL_MEM_INFO), psMemInfo, IMG_NULL);
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
psMemBlock->hBuffer = (IMG_HANDLE)hBuffer;
psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer);
psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
psMemInfo->uAllocSize = ui32Size;
psMemInfo->pvSysBackupBuffer = IMG_NULL;
*ppsMemInfo = psMemInfo;
return (PVRSRV_OK);
}
static PVRSRV_ERROR FreeDeviceMem2(PVRSRV_KERNEL_MEM_INFO *psMemInfo, PVRSRV_FREE_CALLBACK_ORIGIN eCallbackOrigin)
{
BM_HANDLE hBuffer;
if (!psMemInfo)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
hBuffer = psMemInfo->sMemBlk.hBuffer;
switch(eCallbackOrigin)
{
case PVRSRV_FREE_CALLBACK_ORIGIN_ALLOCATOR:
BM_Free(hBuffer, psMemInfo->ui32Flags);
break;
case PVRSRV_FREE_CALLBACK_ORIGIN_IMPORTER:
BM_FreeExport(hBuffer, psMemInfo->ui32Flags);
break;
default:
break;
}
if (psMemInfo->pvSysBackupBuffer &&
eCallbackOrigin == PVRSRV_FREE_CALLBACK_ORIGIN_ALLOCATOR)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, psMemInfo->uAllocSize, psMemInfo->pvSysBackupBuffer, IMG_NULL);
psMemInfo->pvSysBackupBuffer = IMG_NULL;
}
if (psMemInfo->ui32RefCount == 0)
OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_KERNEL_MEM_INFO), psMemInfo, IMG_NULL);
return(PVRSRV_OK);
}
static PVRSRV_ERROR FreeDeviceMem(PVRSRV_KERNEL_MEM_INFO *psMemInfo)
{
BM_HANDLE hBuffer;
if (!psMemInfo)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
hBuffer = psMemInfo->sMemBlk.hBuffer;
BM_Free(hBuffer, psMemInfo->ui32Flags);
if(psMemInfo->pvSysBackupBuffer)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, psMemInfo->uAllocSize, psMemInfo->pvSysBackupBuffer, IMG_NULL);
psMemInfo->pvSysBackupBuffer = IMG_NULL;
}
OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_KERNEL_MEM_INFO), psMemInfo, IMG_NULL);
return(PVRSRV_OK);
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVAllocSyncInfoKM(IMG_HANDLE hDevCookie,
IMG_HANDLE hDevMemContext,
PVRSRV_KERNEL_SYNC_INFO **ppsKernelSyncInfo)
{
IMG_HANDLE hSyncDevMemHeap;
DEVICE_MEMORY_INFO *psDevMemoryInfo;
BM_CONTEXT *pBMContext;
PVRSRV_ERROR eError;
PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo;
PVRSRV_SYNC_DATA *psSyncData;
eError = OSAllocMem(PVRSRV_PAGEABLE_SELECT,
sizeof(PVRSRV_KERNEL_SYNC_INFO),
(IMG_VOID **)&psKernelSyncInfo, IMG_NULL,
"Kernel Synchronization Info");
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVAllocSyncInfoKM: Failed to alloc memory"));
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
psKernelSyncInfo->ui32RefCount = 0;
pBMContext = (BM_CONTEXT*)hDevMemContext;
psDevMemoryInfo = &pBMContext->psDeviceNode->sDevMemoryInfo;
hSyncDevMemHeap = psDevMemoryInfo->psDeviceMemoryHeap[psDevMemoryInfo->ui32SyncHeapID].hDevMemHeap;
eError = AllocDeviceMem(hDevCookie,
hSyncDevMemHeap,
PVRSRV_MEM_CACHE_CONSISTENT,
sizeof(PVRSRV_SYNC_DATA),
sizeof(IMG_UINT32),
IMG_NULL,
0,
&psKernelSyncInfo->psSyncDataMemInfoKM);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVAllocSyncInfoKM: Failed to alloc memory"));
OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_KERNEL_SYNC_INFO), psKernelSyncInfo, IMG_NULL);
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
psKernelSyncInfo->psSyncData = psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM;
psSyncData = psKernelSyncInfo->psSyncData;
psSyncData->ui32WriteOpsPending = 0;
psSyncData->ui32WriteOpsComplete = 0;
psSyncData->ui32ReadOpsPending = 0;
psSyncData->ui32ReadOpsComplete = 0;
psSyncData->ui32ReadOps2Pending = 0;
psSyncData->ui32ReadOps2Complete = 0;
psSyncData->ui32LastOpDumpVal = 0;
psSyncData->ui32LastReadOpDumpVal = 0;
#if defined(PDUMP)
PDUMPCOMMENT("Allocating kernel sync object");
PDUMPMEM(psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM,
psKernelSyncInfo->psSyncDataMemInfoKM,
0,
(IMG_UINT32)psKernelSyncInfo->psSyncDataMemInfoKM->uAllocSize,
PDUMP_FLAGS_CONTINUOUS,
MAKEUNIQUETAG(psKernelSyncInfo->psSyncDataMemInfoKM));
#endif
psKernelSyncInfo->sWriteOpsCompleteDevVAddr.uiAddr = psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr + offsetof(PVRSRV_SYNC_DATA, ui32WriteOpsComplete);
psKernelSyncInfo->sReadOpsCompleteDevVAddr.uiAddr = psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr + offsetof(PVRSRV_SYNC_DATA, ui32ReadOpsComplete);
psKernelSyncInfo->sReadOps2CompleteDevVAddr.uiAddr = psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr + offsetof(PVRSRV_SYNC_DATA, ui32ReadOps2Complete);
psKernelSyncInfo->ui32UID = g_ui32SyncUID++;
psKernelSyncInfo->psSyncDataMemInfoKM->psKernelSyncInfo = IMG_NULL;
*ppsKernelSyncInfo = psKernelSyncInfo;
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVFreeSyncInfoKM(PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo)
{
PVRSRV_ERROR eError;
if (psKernelSyncInfo->ui32RefCount != 0)
{
PVR_DPF((PVR_DBG_ERROR, "oops: sync info ref count not zero at destruction"));
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
eError = FreeDeviceMem(psKernelSyncInfo->psSyncDataMemInfoKM);
(IMG_VOID)OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_KERNEL_SYNC_INFO), psKernelSyncInfo, IMG_NULL);
return eError;
}
static IMG_VOID freeWrapped(PVRSRV_KERNEL_MEM_INFO *psMemInfo)
{
IMG_HANDLE hOSWrapMem = psMemInfo->sMemBlk.hOSWrapMem;
if(psMemInfo->sMemBlk.psIntSysPAddr)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(IMG_SYS_PHYADDR), psMemInfo->sMemBlk.psIntSysPAddr, IMG_NULL);
psMemInfo->sMemBlk.psIntSysPAddr = IMG_NULL;
}
if(hOSWrapMem)
{
OSReleasePhysPageAddr(hOSWrapMem);
}
}
#if defined (PVRSRV_FLUSH_KERNEL_OPS_LAST_ONLY)
static
PVRSRV_ERROR _PollUntilAtLeast(volatile IMG_UINT32* pui32WatchedValue,
IMG_UINT32 ui32MinimumValue,
IMG_UINT32 ui32Waitus,
IMG_UINT32 ui32Tries)
{
PVRSRV_ERROR eError;
IMG_INT32 iDiff;
for(;;)
{
SYS_DATA *psSysData = SysAcquireDataNoCheck();
iDiff = *pui32WatchedValue - ui32MinimumValue;
if (iDiff >= 0)
{
eError = PVRSRV_OK;
break;
}
if(!ui32Tries)
{
eError = PVRSRV_ERROR_TIMEOUT_POLLING_FOR_VALUE;
break;
}
ui32Tries--;
if (psSysData->psGlobalEventObject)
{
IMG_HANDLE hOSEventKM;
if(psSysData->psGlobalEventObject)
{
eError = OSEventObjectOpenKM(psSysData->psGlobalEventObject, &hOSEventKM);
if (eError |= PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,
"_PollUntilAtLeast: OSEventObjectOpen failed"));
goto Exit;
}
eError = OSEventObjectWaitKM(hOSEventKM);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,
"_PollUntilAtLeast: PVRSRVEventObjectWait failed"));
goto Exit;
}
eError = OSEventObjectCloseKM(psSysData->psGlobalEventObject, hOSEventKM);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,
"_PollUntilAtLeast: OSEventObjectClose failed"));
}
}
}
}
Exit:
return eError;
}
static PVRSRV_ERROR FlushKernelOps(PVRSRV_SYNC_DATA *psSyncData)
{
PVRSRV_ERROR eError;
if(!psSyncData)
{
PVR_DPF((PVR_DBG_ERROR, "FlushKernelOps: invalid psSyncData"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
eError = _PollUntilAtLeast(&psSyncData->ui32ReadOpsComplete,
psSyncData->ui32ReadOpsPending,
MAX_HW_TIME_US/WAIT_TRY_COUNT,
WAIT_TRY_COUNT);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "FlushClientOps: Read ops pending timeout"));
PVR_DBG_BREAK;
return eError;
}
eError = _PollUntilAtLeast(&psSyncData->ui32WriteOpsComplete,
psSyncData->ui32WriteOpsPending,
MAX_HW_TIME_US/WAIT_TRY_COUNT,
WAIT_TRY_COUNT);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "FlushClientOps: Write ops pending timeout"));
PVR_DBG_BREAK;
}
return eError;
}
#endif
IMG_EXPORT
PVRSRV_ERROR FreeMemCallBackCommon(PVRSRV_KERNEL_MEM_INFO *psMemInfo,
IMG_UINT32 ui32Param,
PVRSRV_FREE_CALLBACK_ORIGIN eCallbackOrigin)
{
PVRSRV_ERROR eError = PVRSRV_OK;
PVR_UNREFERENCED_PARAMETER(ui32Param);
psMemInfo->ui32RefCount--;
if (psMemInfo->ui32RefCount == 0)
{
if((psMemInfo->ui32Flags & PVRSRV_MEM_EXPORTED) != 0)
{
#if defined (SUPPORT_SID_INTERFACE)
IMG_SID hMemInfo = 0;
#else
IMG_HANDLE hMemInfo = IMG_NULL;
#endif
eError = PVRSRVFindHandle(KERNEL_HANDLE_BASE,
&hMemInfo,
psMemInfo,
PVRSRV_HANDLE_TYPE_MEM_INFO);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "FreeMemCallBackCommon: can't find exported meminfo in the global handle list"));
return eError;
}
eError = PVRSRVReleaseHandle(KERNEL_HANDLE_BASE,
hMemInfo,
PVRSRV_HANDLE_TYPE_MEM_INFO);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "FreeMemCallBackCommon: PVRSRVReleaseHandle failed for exported meminfo"));
return eError;
}
}
#if defined (PVRSRV_FLUSH_KERNEL_OPS_LAST_ONLY)
if (psMemInfo->psKernelSyncInfo)
{
if (psMemInfo->psKernelSyncInfo->ui32RefCount == 1)
{
FlushKernelOps(psMemInfo->psKernelSyncInfo->psSyncData);
}
}
#endif
switch(psMemInfo->memType)
{
case PVRSRV_MEMTYPE_WRAPPED:
freeWrapped(psMemInfo);
case PVRSRV_MEMTYPE_DEVICE:
if (psMemInfo->psKernelSyncInfo)
{
psMemInfo->psKernelSyncInfo->ui32RefCount--;
if (psMemInfo->psKernelSyncInfo->ui32RefCount == 0)
{
eError = PVRSRVFreeSyncInfoKM(psMemInfo->psKernelSyncInfo);
}
}
case PVRSRV_MEMTYPE_DEVICECLASS:
break;
default:
PVR_DPF((PVR_DBG_ERROR, "FreeMemCallBackCommon: Unknown memType"));
eError = PVRSRV_ERROR_INVALID_MEMINFO;
}
}
if (eError == PVRSRV_OK)
{
eError = FreeDeviceMem2(psMemInfo, eCallbackOrigin);
}
return eError;
}
static PVRSRV_ERROR FreeDeviceMemCallBack(IMG_PVOID pvParam,
IMG_UINT32 ui32Param,
IMG_BOOL bDummy)
{
PVRSRV_KERNEL_MEM_INFO *psMemInfo = (PVRSRV_KERNEL_MEM_INFO *)pvParam;
PVR_UNREFERENCED_PARAMETER(bDummy);
return FreeMemCallBackCommon(psMemInfo, ui32Param,
PVRSRV_FREE_CALLBACK_ORIGIN_ALLOCATOR);
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVFreeDeviceMemKM(IMG_HANDLE hDevCookie,
PVRSRV_KERNEL_MEM_INFO *psMemInfo)
{
PVRSRV_ERROR eError;
PVR_UNREFERENCED_PARAMETER(hDevCookie);
if (!psMemInfo)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
if (psMemInfo->sMemBlk.hResItem != IMG_NULL)
{
eError = ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem, CLEANUP_WITH_POLL);
}
else
{
eError = FreeDeviceMemCallBack(psMemInfo, 0, CLEANUP_WITH_POLL);
}
return eError;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV _PVRSRVAllocDeviceMemKM(IMG_HANDLE hDevCookie,
PVRSRV_PER_PROCESS_DATA *psPerProc,
IMG_HANDLE hDevMemHeap,
IMG_UINT32 ui32Flags,
IMG_SIZE_T ui32Size,
IMG_SIZE_T ui32Alignment,
IMG_PVOID pvPrivData,
IMG_UINT32 ui32PrivDataLength,
PVRSRV_KERNEL_MEM_INFO **ppsMemInfo)
{
PVRSRV_KERNEL_MEM_INFO *psMemInfo;
PVRSRV_ERROR eError;
BM_HEAP *psBMHeap;
IMG_HANDLE hDevMemContext;
if (!hDevMemHeap ||
(ui32Size == 0))
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
if (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK)
{
if (((ui32Size % HOST_PAGESIZE()) != 0) ||
((ui32Alignment % HOST_PAGESIZE()) != 0))
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
}
eError = AllocDeviceMem(hDevCookie,
hDevMemHeap,
ui32Flags,
ui32Size,
ui32Alignment,
pvPrivData,
ui32PrivDataLength,
&psMemInfo);
if (eError != PVRSRV_OK)
{
return eError;
}
if (ui32Flags & PVRSRV_MEM_NO_SYNCOBJ)
{
psMemInfo->psKernelSyncInfo = IMG_NULL;
}
else
{
psBMHeap = (BM_HEAP*)hDevMemHeap;
hDevMemContext = (IMG_HANDLE)psBMHeap->pBMContext;
eError = PVRSRVAllocSyncInfoKM(hDevCookie,
hDevMemContext,
&psMemInfo->psKernelSyncInfo);
if(eError != PVRSRV_OK)
{
goto free_mainalloc;
}
psMemInfo->psKernelSyncInfo->ui32RefCount++;
}
*ppsMemInfo = psMemInfo;
if (ui32Flags & PVRSRV_MEM_NO_RESMAN)
{
psMemInfo->sMemBlk.hResItem = IMG_NULL;
}
else
{
psMemInfo->sMemBlk.hResItem = ResManRegisterRes(psPerProc->hResManContext,
RESMAN_TYPE_DEVICEMEM_ALLOCATION,
psMemInfo,
0,
&FreeDeviceMemCallBack);
if (psMemInfo->sMemBlk.hResItem == IMG_NULL)
{
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto free_mainalloc;
}
}
psMemInfo->ui32RefCount++;
psMemInfo->memType = PVRSRV_MEMTYPE_DEVICE;
return (PVRSRV_OK);
free_mainalloc:
FreeDeviceMem(psMemInfo);
return eError;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVDissociateDeviceMemKM(IMG_HANDLE hDevCookie,
PVRSRV_KERNEL_MEM_INFO *psMemInfo)
{
PVRSRV_ERROR eError;
PVRSRV_DEVICE_NODE *psDeviceNode = hDevCookie;
PVR_UNREFERENCED_PARAMETER(hDevCookie);
if (!psMemInfo)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
eError = ResManDissociateRes(psMemInfo->sMemBlk.hResItem, psDeviceNode->hResManContext);
PVR_ASSERT(eError == PVRSRV_OK);
return eError;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVGetFreeDeviceMemKM(IMG_UINT32 ui32Flags,
IMG_SIZE_T *pui32Total,
IMG_SIZE_T *pui32Free,
IMG_SIZE_T *pui32LargestBlock)
{
PVR_UNREFERENCED_PARAMETER(ui32Flags);
PVR_UNREFERENCED_PARAMETER(pui32Total);
PVR_UNREFERENCED_PARAMETER(pui32Free);
PVR_UNREFERENCED_PARAMETER(pui32LargestBlock);
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVUnwrapExtMemoryKM (PVRSRV_KERNEL_MEM_INFO *psMemInfo)
{
if (!psMemInfo)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
return ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem, CLEANUP_WITH_POLL);
}
static PVRSRV_ERROR UnwrapExtMemoryCallBack(IMG_PVOID pvParam,
IMG_UINT32 ui32Param,
IMG_BOOL bDummy)
{
PVRSRV_KERNEL_MEM_INFO *psMemInfo = (PVRSRV_KERNEL_MEM_INFO *)pvParam;
PVR_UNREFERENCED_PARAMETER(bDummy);
return FreeMemCallBackCommon(psMemInfo, ui32Param,
PVRSRV_FREE_CALLBACK_ORIGIN_ALLOCATOR);
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVWrapExtMemoryKM(IMG_HANDLE hDevCookie,
PVRSRV_PER_PROCESS_DATA *psPerProc,
IMG_HANDLE hDevMemContext,
IMG_SIZE_T uByteSize,
IMG_SIZE_T uPageOffset,
IMG_BOOL bPhysContig,
IMG_SYS_PHYADDR *psExtSysPAddr,
IMG_VOID *pvLinAddr,
IMG_UINT32 ui32Flags,
PVRSRV_KERNEL_MEM_INFO **ppsMemInfo)
{
PVRSRV_KERNEL_MEM_INFO *psMemInfo = IMG_NULL;
DEVICE_MEMORY_INFO *psDevMemoryInfo;
IMG_SIZE_T ui32HostPageSize = HOST_PAGESIZE();
IMG_HANDLE hDevMemHeap = IMG_NULL;
PVRSRV_DEVICE_NODE* psDeviceNode;
BM_HANDLE hBuffer;
PVRSRV_MEMBLK *psMemBlock;
IMG_BOOL bBMError;
BM_HEAP *psBMHeap;
PVRSRV_ERROR eError;
IMG_VOID *pvPageAlignedCPUVAddr;
IMG_SYS_PHYADDR *psIntSysPAddr = IMG_NULL;
IMG_HANDLE hOSWrapMem = IMG_NULL;
DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
IMG_UINT32 i;
IMG_SIZE_T uPageCount = 0;
psDeviceNode = (PVRSRV_DEVICE_NODE*)hDevCookie;
PVR_ASSERT(psDeviceNode != IMG_NULL);
if (psDeviceNode == IMG_NULL)
{
PVR_DPF((PVR_DBG_ERROR, "PVRSRVWrapExtMemoryKM: invalid parameter"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
if(pvLinAddr)
{
uPageOffset = (IMG_UINTPTR_T)pvLinAddr & (ui32HostPageSize - 1);
uPageCount = HOST_PAGEALIGN(uByteSize + uPageOffset) / ui32HostPageSize;
pvPageAlignedCPUVAddr = (IMG_VOID *)((IMG_UINTPTR_T)pvLinAddr - uPageOffset);
if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
uPageCount * sizeof(IMG_SYS_PHYADDR),
(IMG_VOID **)&psIntSysPAddr, IMG_NULL,
"Array of Page Addresses") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVWrapExtMemoryKM: Failed to alloc memory for block"));
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
eError = OSAcquirePhysPageAddr(pvPageAlignedCPUVAddr,
uPageCount * ui32HostPageSize,
psIntSysPAddr,
&hOSWrapMem);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVWrapExtMemoryKM: Failed to alloc memory for block"));
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto ErrorExitPhase1;
}
psExtSysPAddr = psIntSysPAddr;
bPhysContig = IMG_FALSE;
}
else
{
}
psDevMemoryInfo = &((BM_CONTEXT*)hDevMemContext)->psDeviceNode->sDevMemoryInfo;
psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap;
for(i=0; i<PVRSRV_MAX_CLIENT_HEAPS; i++)
{
if(HEAP_IDX(psDeviceMemoryHeap[i].ui32HeapID) == psDevMemoryInfo->ui32MappingHeapID)
{
if(psDeviceMemoryHeap[i].DevMemHeapType == DEVICE_MEMORY_HEAP_PERCONTEXT)
{
if (psDeviceMemoryHeap[i].ui32HeapSize > 0)
{
hDevMemHeap = BM_CreateHeap(hDevMemContext, &psDeviceMemoryHeap[i]);
}
else
{
hDevMemHeap = IMG_NULL;
}
}
else
{
hDevMemHeap = psDevMemoryInfo->psDeviceMemoryHeap[i].hDevMemHeap;
}
break;
}
}
if(hDevMemHeap == IMG_NULL)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVWrapExtMemoryKM: unable to find mapping heap"));
eError = PVRSRV_ERROR_UNABLE_TO_FIND_MAPPING_HEAP;
goto ErrorExitPhase2;
}
if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(PVRSRV_KERNEL_MEM_INFO),
(IMG_VOID **)&psMemInfo, IMG_NULL,
"Kernel Memory Info") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVWrapExtMemoryKM: Failed to alloc memory for block"));
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto ErrorExitPhase2;
}
OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
psMemInfo->ui32Flags = ui32Flags;
psMemBlock = &(psMemInfo->sMemBlk);
bBMError = BM_Wrap(hDevMemHeap,
uByteSize,
uPageOffset,
bPhysContig,
psExtSysPAddr,
IMG_NULL,
&psMemInfo->ui32Flags,
&hBuffer);
if (!bBMError)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVWrapExtMemoryKM: BM_Wrap Failed"));
eError = PVRSRV_ERROR_BAD_MAPPING;
goto ErrorExitPhase3;
}
psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
psMemBlock->hOSWrapMem = hOSWrapMem;
psMemBlock->psIntSysPAddr = psIntSysPAddr;
psMemBlock->hBuffer = (IMG_HANDLE)hBuffer;
psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer);
psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
psMemInfo->uAllocSize = uByteSize;
psMemInfo->pvSysBackupBuffer = IMG_NULL;
psBMHeap = (BM_HEAP*)hDevMemHeap;
hDevMemContext = (IMG_HANDLE)psBMHeap->pBMContext;
eError = PVRSRVAllocSyncInfoKM(hDevCookie,
hDevMemContext,
&psMemInfo->psKernelSyncInfo);
if(eError != PVRSRV_OK)
{
goto ErrorExitPhase4;
}
psMemInfo->psKernelSyncInfo->ui32RefCount++;
psMemInfo->ui32RefCount++;
psMemInfo->memType = PVRSRV_MEMTYPE_WRAPPED;
psMemInfo->sMemBlk.hResItem = ResManRegisterRes(psPerProc->hResManContext,
RESMAN_TYPE_DEVICEMEM_WRAP,
psMemInfo,
0,
&UnwrapExtMemoryCallBack);
*ppsMemInfo = psMemInfo;
return PVRSRV_OK;
ErrorExitPhase4:
if(psMemInfo)
{
FreeDeviceMem(psMemInfo);
psMemInfo = IMG_NULL;
}
ErrorExitPhase3:
if(psMemInfo)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_KERNEL_MEM_INFO), psMemInfo, IMG_NULL);
}
ErrorExitPhase2:
if(psIntSysPAddr)
{
OSReleasePhysPageAddr(hOSWrapMem);
}
ErrorExitPhase1:
if(psIntSysPAddr)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, uPageCount * sizeof(IMG_SYS_PHYADDR), psIntSysPAddr, IMG_NULL);
}
return eError;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVUnmapDeviceMemoryKM (PVRSRV_KERNEL_MEM_INFO *psMemInfo)
{
if (!psMemInfo)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
return ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem, CLEANUP_WITH_POLL);
}
static PVRSRV_ERROR UnmapDeviceMemoryCallBack(IMG_PVOID pvParam,
IMG_UINT32 ui32Param,
IMG_BOOL bDummy)
{
PVRSRV_ERROR eError;
RESMAN_MAP_DEVICE_MEM_DATA *psMapData = pvParam;
PVR_UNREFERENCED_PARAMETER(ui32Param);
PVR_UNREFERENCED_PARAMETER(bDummy);
if(psMapData->psMemInfo->sMemBlk.psIntSysPAddr)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(IMG_SYS_PHYADDR), psMapData->psMemInfo->sMemBlk.psIntSysPAddr, IMG_NULL);
psMapData->psMemInfo->sMemBlk.psIntSysPAddr = IMG_NULL;
}
if( psMapData->psMemInfo->psKernelSyncInfo )
{
psMapData->psMemInfo->psKernelSyncInfo->ui32RefCount--;
if (psMapData->psMemInfo->psKernelSyncInfo->ui32RefCount == 0)
{
eError = PVRSRVFreeSyncInfoKM(psMapData->psMemInfo->psKernelSyncInfo);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"UnmapDeviceMemoryCallBack: Failed to free sync info"));
return eError;
}
}
}
eError = FreeDeviceMem(psMapData->psMemInfo);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"UnmapDeviceMemoryCallBack: Failed to free DST meminfo"));
return eError;
}
eError = FreeMemCallBackCommon(psMapData->psSrcMemInfo, 0,
PVRSRV_FREE_CALLBACK_ORIGIN_IMPORTER);
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(RESMAN_MAP_DEVICE_MEM_DATA), psMapData, IMG_NULL);
return eError;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceMemoryKM(PVRSRV_PER_PROCESS_DATA *psPerProc,
PVRSRV_KERNEL_MEM_INFO *psSrcMemInfo,
IMG_HANDLE hDstDevMemHeap,
PVRSRV_KERNEL_MEM_INFO **ppsDstMemInfo)
{
PVRSRV_ERROR eError;
IMG_UINT32 i;
IMG_SIZE_T uPageCount, uPageOffset;
IMG_SIZE_T ui32HostPageSize = HOST_PAGESIZE();
IMG_SYS_PHYADDR *psSysPAddr = IMG_NULL;
IMG_DEV_PHYADDR sDevPAddr;
BM_BUF *psBuf;
IMG_DEV_VIRTADDR sDevVAddr;
PVRSRV_KERNEL_MEM_INFO *psMemInfo = IMG_NULL;
BM_HANDLE hBuffer;
PVRSRV_MEMBLK *psMemBlock;
IMG_BOOL bBMError;
PVRSRV_DEVICE_NODE *psDeviceNode;
IMG_VOID *pvPageAlignedCPUVAddr;
RESMAN_MAP_DEVICE_MEM_DATA *psMapData = IMG_NULL;
if(!psSrcMemInfo || !hDstDevMemHeap || !ppsDstMemInfo)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceMemoryKM: invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
*ppsDstMemInfo = IMG_NULL;
uPageOffset = psSrcMemInfo->sDevVAddr.uiAddr & (ui32HostPageSize - 1);
uPageCount = HOST_PAGEALIGN(psSrcMemInfo->uAllocSize + uPageOffset) / ui32HostPageSize;
pvPageAlignedCPUVAddr = (IMG_VOID *)((IMG_UINTPTR_T)psSrcMemInfo->pvLinAddrKM - uPageOffset);
if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
uPageCount*sizeof(IMG_SYS_PHYADDR),
(IMG_VOID **)&psSysPAddr, IMG_NULL,
"Array of Page Addresses") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceMemoryKM: Failed to alloc memory for block"));
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
psBuf = psSrcMemInfo->sMemBlk.hBuffer;
psDeviceNode = psBuf->pMapping->pBMHeap->pBMContext->psDeviceNode;
sDevVAddr.uiAddr = psSrcMemInfo->sDevVAddr.uiAddr - IMG_CAST_TO_DEVVADDR_UINT(uPageOffset);
for(i=0; i<uPageCount; i++)
{
BM_GetPhysPageAddr(psSrcMemInfo, sDevVAddr, &sDevPAddr);
psSysPAddr[i] = SysDevPAddrToSysPAddr (psDeviceNode->sDevId.eDeviceType, sDevPAddr);
sDevVAddr.uiAddr += IMG_CAST_TO_DEVVADDR_UINT(ui32HostPageSize);
}
if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(RESMAN_MAP_DEVICE_MEM_DATA),
(IMG_VOID **)&psMapData, IMG_NULL,
"Resource Manager Map Data") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceMemoryKM: Failed to alloc resman map data"));
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto ErrorExit;
}
if(OSAllocMem(PVRSRV_PAGEABLE_SELECT,
sizeof(PVRSRV_KERNEL_MEM_INFO),
(IMG_VOID **)&psMemInfo, IMG_NULL,
"Kernel Memory Info") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceMemoryKM: Failed to alloc memory for block"));
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto ErrorExit;
}
OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
psMemInfo->ui32Flags = psSrcMemInfo->ui32Flags;
psMemBlock = &(psMemInfo->sMemBlk);
bBMError = BM_Wrap(hDstDevMemHeap,
psSrcMemInfo->uAllocSize,
uPageOffset,
IMG_FALSE,
psSysPAddr,
pvPageAlignedCPUVAddr,
&psMemInfo->ui32Flags,
&hBuffer);
if (!bBMError)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceMemoryKM: BM_Wrap Failed"));
eError = PVRSRV_ERROR_BAD_MAPPING;
goto ErrorExit;
}
psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
psMemBlock->hBuffer = (IMG_HANDLE)hBuffer;
psMemBlock->psIntSysPAddr = psSysPAddr;
psMemInfo->pvLinAddrKM = psSrcMemInfo->pvLinAddrKM;
psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
psMemInfo->uAllocSize = psSrcMemInfo->uAllocSize;
psMemInfo->psKernelSyncInfo = psSrcMemInfo->psKernelSyncInfo;
if(psMemInfo->psKernelSyncInfo)
{
psMemInfo->psKernelSyncInfo->ui32RefCount++;
}
psMemInfo->pvSysBackupBuffer = IMG_NULL;
psMemInfo->ui32RefCount++;
psSrcMemInfo->ui32RefCount++;
BM_Export(psSrcMemInfo->sMemBlk.hBuffer);
psMemInfo->memType = PVRSRV_MEMTYPE_MAPPED;
psMapData->psMemInfo = psMemInfo;
psMapData->psSrcMemInfo = psSrcMemInfo;
psMemInfo->sMemBlk.hResItem = ResManRegisterRes(psPerProc->hResManContext,
RESMAN_TYPE_DEVICEMEM_MAPPING,
psMapData,
0,
&UnmapDeviceMemoryCallBack);
*ppsDstMemInfo = psMemInfo;
return PVRSRV_OK;
ErrorExit:
if(psSysPAddr)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(IMG_SYS_PHYADDR), psSysPAddr, IMG_NULL);
}
if(psMemInfo)
{
OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_KERNEL_MEM_INFO), psMemInfo, IMG_NULL);
}
if(psMapData)
{
OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(RESMAN_MAP_DEVICE_MEM_DATA), psMapData, IMG_NULL);
}
return eError;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVUnmapDeviceClassMemoryKM(PVRSRV_KERNEL_MEM_INFO *psMemInfo)
{
if (!psMemInfo)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
return ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem, CLEANUP_WITH_POLL);
}
static PVRSRV_ERROR UnmapDeviceClassMemoryCallBack(IMG_PVOID pvParam,
IMG_UINT32 ui32Param,
IMG_BOOL bDummy)
{
PVRSRV_DC_MAPINFO *psDCMapInfo = pvParam;
PVRSRV_KERNEL_MEM_INFO *psMemInfo;
PVR_UNREFERENCED_PARAMETER(ui32Param);
PVR_UNREFERENCED_PARAMETER(bDummy);
psMemInfo = psDCMapInfo->psMemInfo;
#if defined(SUPPORT_MEMORY_TILING)
if(psDCMapInfo->ui32TilingStride > 0)
{
PVRSRV_DEVICE_NODE *psDeviceNode = psDCMapInfo->psDeviceNode;
if (psDeviceNode->pfnFreeMemTilingRange(psDeviceNode,
psDCMapInfo->ui32RangeIndex) != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"UnmapDeviceClassMemoryCallBack: FreeMemTilingRange failed"));
}
}
#endif
(psDCMapInfo->psDeviceClassBuffer->ui32MemMapRefCount)--;
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_MAPINFO), psDCMapInfo, IMG_NULL);
return FreeMemCallBackCommon(psMemInfo, ui32Param,
PVRSRV_FREE_CALLBACK_ORIGIN_ALLOCATOR);
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceClassMemoryKM(PVRSRV_PER_PROCESS_DATA *psPerProc,
IMG_HANDLE hDevMemContext,
IMG_HANDLE hDeviceClassBuffer,
PVRSRV_KERNEL_MEM_INFO **ppsMemInfo,
IMG_HANDLE *phOSMapInfo)
{
PVRSRV_ERROR eError;
PVRSRV_DEVICE_NODE* psDeviceNode;
PVRSRV_KERNEL_MEM_INFO *psMemInfo = IMG_NULL;
PVRSRV_DEVICECLASS_BUFFER *psDeviceClassBuffer;
IMG_SYS_PHYADDR *psSysPAddr;
IMG_VOID *pvCPUVAddr, *pvPageAlignedCPUVAddr;
IMG_BOOL bPhysContig;
BM_CONTEXT *psBMContext;
DEVICE_MEMORY_INFO *psDevMemoryInfo;
DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
IMG_HANDLE hDevMemHeap = IMG_NULL;
IMG_SIZE_T uByteSize;
IMG_SIZE_T ui32Offset;
IMG_SIZE_T ui32PageSize = HOST_PAGESIZE();
BM_HANDLE hBuffer;
PVRSRV_MEMBLK *psMemBlock;
IMG_BOOL bBMError;
IMG_UINT32 i;
PVRSRV_DC_MAPINFO *psDCMapInfo = IMG_NULL;
if(!hDeviceClassBuffer || !ppsMemInfo || !phOSMapInfo || !hDevMemContext)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceClassMemoryKM: invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(PVRSRV_DC_MAPINFO),
(IMG_VOID **)&psDCMapInfo, IMG_NULL,
"PVRSRV_DC_MAPINFO") != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceClassMemoryKM: Failed to alloc memory for psDCMapInfo"));
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
OSMemSet(psDCMapInfo, 0, sizeof(PVRSRV_DC_MAPINFO));
psDeviceClassBuffer = (PVRSRV_DEVICECLASS_BUFFER*)hDeviceClassBuffer;
eError = psDeviceClassBuffer->pfnGetBufferAddr(psDeviceClassBuffer->hExtDevice,
psDeviceClassBuffer->hExtBuffer,
&psSysPAddr,
&uByteSize,
&pvCPUVAddr,
phOSMapInfo,
&bPhysContig,
&psDCMapInfo->ui32TilingStride);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceClassMemoryKM: unable to get buffer address"));
goto ErrorExitPhase1;
}
psBMContext = (BM_CONTEXT*)psDeviceClassBuffer->hDevMemContext;
psDeviceNode = psBMContext->psDeviceNode;
psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo;
psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap;
for(i=0; i<PVRSRV_MAX_CLIENT_HEAPS; i++)
{
if(HEAP_IDX(psDeviceMemoryHeap[i].ui32HeapID) == psDevMemoryInfo->ui32MappingHeapID)
{
if(psDeviceMemoryHeap[i].DevMemHeapType == DEVICE_MEMORY_HEAP_PERCONTEXT)
{
if (psDeviceMemoryHeap[i].ui32HeapSize > 0)
{
hDevMemHeap = BM_CreateHeap(hDevMemContext, &psDeviceMemoryHeap[i]);
}
else
{
hDevMemHeap = IMG_NULL;
}
}
else
{
hDevMemHeap = psDevMemoryInfo->psDeviceMemoryHeap[i].hDevMemHeap;
}
break;
}
}
if(hDevMemHeap == IMG_NULL)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceClassMemoryKM: unable to find mapping heap"));
eError = PVRSRV_ERROR_UNABLE_TO_FIND_RESOURCE;
goto ErrorExitPhase1;
}
ui32Offset = ((IMG_UINTPTR_T)pvCPUVAddr) & (ui32PageSize - 1);
pvPageAlignedCPUVAddr = (IMG_VOID *)((IMG_UINTPTR_T)pvCPUVAddr - ui32Offset);
eError = OSAllocMem(PVRSRV_PAGEABLE_SELECT,
sizeof(PVRSRV_KERNEL_MEM_INFO),
(IMG_VOID **)&psMemInfo, IMG_NULL,
"Kernel Memory Info");
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceClassMemoryKM: Failed to alloc memory for block"));
goto ErrorExitPhase1;
}
OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
psMemBlock = &(psMemInfo->sMemBlk);
bBMError = BM_Wrap(hDevMemHeap,
uByteSize,
ui32Offset,
bPhysContig,
psSysPAddr,
pvPageAlignedCPUVAddr,
&psMemInfo->ui32Flags,
&hBuffer);
if (!bBMError)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceClassMemoryKM: BM_Wrap Failed"));
eError = PVRSRV_ERROR_BAD_MAPPING;
goto ErrorExitPhase2;
}
psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
psMemBlock->hBuffer = (IMG_HANDLE)hBuffer;
psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer);
psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
psMemInfo->uAllocSize = uByteSize;
psMemInfo->psKernelSyncInfo = psDeviceClassBuffer->psKernelSyncInfo;
psMemInfo->pvSysBackupBuffer = IMG_NULL;
psDCMapInfo->psMemInfo = psMemInfo;
psDCMapInfo->psDeviceClassBuffer = psDeviceClassBuffer;
#if defined(SUPPORT_MEMORY_TILING)
psDCMapInfo->psDeviceNode = psDeviceNode;
if(psDCMapInfo->ui32TilingStride > 0)
{
eError = psDeviceNode->pfnAllocMemTilingRange(psDeviceNode,
psMemInfo,
psDCMapInfo->ui32TilingStride,
&psDCMapInfo->ui32RangeIndex);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceClassMemoryKM: AllocMemTilingRange failed"));
goto ErrorExitPhase3;
}
}
#endif
psMemInfo->sMemBlk.hResItem = ResManRegisterRes(psPerProc->hResManContext,
RESMAN_TYPE_DEVICECLASSMEM_MAPPING,
psDCMapInfo,
0,
&UnmapDeviceClassMemoryCallBack);
(psDeviceClassBuffer->ui32MemMapRefCount)++;
psMemInfo->ui32RefCount++;
psMemInfo->memType = PVRSRV_MEMTYPE_DEVICECLASS;
*ppsMemInfo = psMemInfo;
#if defined(SUPPORT_PDUMP_MULTI_PROCESS)
PDUMPCOMMENT("Dump display surface");
PDUMPMEM(IMG_NULL, psMemInfo, ui32Offset, psMemInfo->uAllocSize, PDUMP_FLAGS_CONTINUOUS, ((BM_BUF*)psMemInfo->sMemBlk.hBuffer)->pMapping);
#endif
return PVRSRV_OK;
#if defined(SUPPORT_MEMORY_TILING)
ErrorExitPhase3:
if(psMemInfo)
{
FreeDeviceMem(psMemInfo);
psMemInfo = IMG_NULL;
}
#endif
ErrorExitPhase2:
if(psMemInfo)
{
OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_KERNEL_MEM_INFO), psMemInfo, IMG_NULL);
}
ErrorExitPhase1:
if(psDCMapInfo)
{
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_KERNEL_MEM_INFO), psDCMapInfo, IMG_NULL);
}
return eError;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVChangeDeviceMemoryAttributesKM(IMG_HANDLE hKernelMemInfo, IMG_UINT32 ui32Attribs)
{
PVRSRV_KERNEL_MEM_INFO *psKMMemInfo;
if (hKernelMemInfo == IMG_NULL)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
psKMMemInfo = (PVRSRV_KERNEL_MEM_INFO *)hKernelMemInfo;
if (ui32Attribs & PVRSRV_CHANGEDEVMEM_ATTRIBS_CACHECOHERENT)
{
psKMMemInfo->ui32Flags |= PVRSRV_MEM_CACHE_CONSISTENT;
}
else
{
psKMMemInfo->ui32Flags &= ~PVRSRV_MEM_CACHE_CONSISTENT;
}
return PVRSRV_OK;
}