/********************************************************************** * * 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. * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK * ******************************************************************************/ #include "services_headers.h" #include "sysconfig.h" #include "hash.h" #include "ra.h" #include "pdump_km.h" #include "lists.h" static IMG_BOOL ZeroBuf(BM_BUF *pBuf, BM_MAPPING *pMapping, IMG_SIZE_T ui32Bytes, IMG_UINT32 ui32Flags); static IMG_VOID BM_FreeMemory (IMG_VOID *pH, IMG_UINTPTR_T base, BM_MAPPING *psMapping); static IMG_BOOL BM_ImportMemory(IMG_VOID *pH, IMG_SIZE_T uSize, IMG_SIZE_T *pActualSize, BM_MAPPING **ppsMapping, IMG_UINT32 uFlags, IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength, IMG_UINTPTR_T *pBase); static IMG_BOOL DevMemoryAlloc (BM_CONTEXT *pBMContext, BM_MAPPING *pMapping, IMG_SIZE_T *pActualSize, IMG_UINT32 uFlags, IMG_UINT32 dev_vaddr_alignment, IMG_DEV_VIRTADDR *pDevVAddr); static IMG_VOID DevMemoryFree (BM_MAPPING *pMapping); static IMG_BOOL AllocMemory (BM_CONTEXT *pBMContext, BM_HEAP *psBMHeap, IMG_DEV_VIRTADDR *psDevVAddr, IMG_SIZE_T uSize, IMG_UINT32 uFlags, IMG_UINT32 uDevVAddrAlignment, IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength, BM_BUF *pBuf) { BM_MAPPING *pMapping; IMG_UINTPTR_T uOffset; RA_ARENA *pArena = IMG_NULL; PVR_DPF ((PVR_DBG_MESSAGE, "AllocMemory (uSize=0x%x, uFlags=0x%x, align=0x%x)", uSize, uFlags, uDevVAddrAlignment)); if(uFlags & PVRSRV_MEM_RAM_BACKED_ALLOCATION) { if(uFlags & PVRSRV_MEM_USER_SUPPLIED_DEVVADDR) { PVR_DPF ((PVR_DBG_ERROR, "AllocMemory: combination of DevVAddr management and RAM backing mode unsupported")); return IMG_FALSE; } if(psBMHeap->ui32Attribs & (PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG |PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG)) { pArena = psBMHeap->pImportArena; PVR_ASSERT(psBMHeap->sDevArena.psDeviceMemoryHeapInfo->ui32Attribs & PVRSRV_MEM_RAM_BACKED_ALLOCATION); } else { PVR_DPF ((PVR_DBG_ERROR, "AllocMemory: backing store type doesn't match heap")); return IMG_FALSE; } if (!RA_Alloc(pArena, uSize, IMG_NULL, (IMG_VOID*) &pMapping, uFlags, uDevVAddrAlignment, 0, pvPrivData, ui32PrivDataLength, (IMG_UINTPTR_T *)&(pBuf->DevVAddr.uiAddr))) { PVR_DPF((PVR_DBG_ERROR, "AllocMemory: RA_Alloc(0x%x) FAILED", uSize)); return IMG_FALSE; } uOffset = pBuf->DevVAddr.uiAddr - pMapping->DevVAddr.uiAddr; if(pMapping->CpuVAddr) { pBuf->CpuVAddr = (IMG_VOID*) ((IMG_UINTPTR_T)pMapping->CpuVAddr + uOffset); } else { pBuf->CpuVAddr = IMG_NULL; } if(uSize == pMapping->uSize) { pBuf->hOSMemHandle = pMapping->hOSMemHandle; } else { if(OSGetSubMemHandle(pMapping->hOSMemHandle, uOffset, uSize, psBMHeap->ui32Attribs, &pBuf->hOSMemHandle)!=PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "AllocMemory: OSGetSubMemHandle FAILED")); return IMG_FALSE; } } pBuf->CpuPAddr.uiAddr = pMapping->CpuPAddr.uiAddr + uOffset; if(uFlags & PVRSRV_MEM_ZERO) { if(!ZeroBuf(pBuf, pMapping, uSize, psBMHeap->ui32Attribs | uFlags)) { return IMG_FALSE; } } } else { if(uFlags & PVRSRV_MEM_USER_SUPPLIED_DEVVADDR) { PVR_ASSERT(psDevVAddr != IMG_NULL); if (psDevVAddr == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "AllocMemory: invalid parameter - psDevVAddr")); return IMG_FALSE; } pBMContext->psDeviceNode->pfnMMUAlloc (psBMHeap->pMMUHeap, uSize, IMG_NULL, PVRSRV_MEM_USER_SUPPLIED_DEVVADDR, uDevVAddrAlignment, psDevVAddr); pBuf->DevVAddr = *psDevVAddr; } else { IMG_BOOL bResult; bResult = pBMContext->psDeviceNode->pfnMMUAlloc (psBMHeap->pMMUHeap, uSize, IMG_NULL, 0, uDevVAddrAlignment, &pBuf->DevVAddr); if(!bResult) { PVR_DPF((PVR_DBG_ERROR, "AllocMemory: MMUAlloc failed")); return IMG_FALSE; } } if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (struct _BM_MAPPING_), (IMG_PVOID *)&pMapping, IMG_NULL, "Buffer Manager Mapping") != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "AllocMemory: OSAllocMem(0x%x) FAILED", sizeof(*pMapping))); return IMG_FALSE; } pBuf->CpuVAddr = IMG_NULL; pBuf->hOSMemHandle = 0; pBuf->CpuPAddr.uiAddr = 0; pMapping->CpuVAddr = IMG_NULL; pMapping->CpuPAddr.uiAddr = 0; pMapping->DevVAddr = pBuf->DevVAddr; pMapping->psSysAddr = IMG_NULL; pMapping->uSize = uSize; pMapping->hOSMemHandle = 0; } pMapping->pArena = pArena; pMapping->pBMHeap = psBMHeap; pBuf->pMapping = pMapping; PVR_DPF ((PVR_DBG_MESSAGE, "AllocMemory: pMapping=%08x: DevV=%08X CpuV=%08x CpuP=%08X uSize=0x%x", (IMG_UINTPTR_T)pMapping, pMapping->DevVAddr.uiAddr, (IMG_UINTPTR_T)pMapping->CpuVAddr, pMapping->CpuPAddr.uiAddr, pMapping->uSize)); PVR_DPF ((PVR_DBG_MESSAGE, "AllocMemory: pBuf=%08x: DevV=%08X CpuV=%08x CpuP=%08X uSize=0x%x", (IMG_UINTPTR_T)pBuf, pBuf->DevVAddr.uiAddr, (IMG_UINTPTR_T)pBuf->CpuVAddr, pBuf->CpuPAddr.uiAddr, uSize)); PVR_ASSERT(((pBuf->DevVAddr.uiAddr) & (uDevVAddrAlignment - 1)) == 0); return IMG_TRUE; } static IMG_BOOL WrapMemory (BM_HEAP *psBMHeap, IMG_SIZE_T uSize, IMG_SIZE_T ui32BaseOffset, IMG_BOOL bPhysContig, IMG_SYS_PHYADDR *psAddr, IMG_VOID *pvCPUVAddr, IMG_UINT32 uFlags, BM_BUF *pBuf) { IMG_DEV_VIRTADDR DevVAddr = {0}; BM_MAPPING *pMapping; IMG_BOOL bResult; IMG_SIZE_T const ui32PageSize = HOST_PAGESIZE(); PVR_DPF ((PVR_DBG_MESSAGE, "WrapMemory(psBMHeap=%08X, size=0x%x, offset=0x%x, bPhysContig=0x%x, pvCPUVAddr = 0x%08x, flags=0x%x)", (IMG_UINTPTR_T)psBMHeap, uSize, ui32BaseOffset, bPhysContig, (IMG_UINTPTR_T)pvCPUVAddr, uFlags)); PVR_ASSERT((psAddr->uiAddr & (ui32PageSize - 1)) == 0); PVR_ASSERT(((IMG_UINTPTR_T)pvCPUVAddr & (ui32PageSize - 1)) == 0); uSize += ui32BaseOffset; uSize = HOST_PAGEALIGN (uSize); if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*pMapping), (IMG_PVOID *)&pMapping, IMG_NULL, "Mocked-up mapping") != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "WrapMemory: OSAllocMem(0x%x) FAILED",sizeof(*pMapping))); return IMG_FALSE; } OSMemSet(pMapping, 0, sizeof (*pMapping)); pMapping->uSize = uSize; pMapping->pBMHeap = psBMHeap; if(pvCPUVAddr) { pMapping->CpuVAddr = pvCPUVAddr; if (bPhysContig) { pMapping->eCpuMemoryOrigin = hm_wrapped_virtaddr; pMapping->CpuPAddr = SysSysPAddrToCpuPAddr(psAddr[0]); if(OSRegisterMem(pMapping->CpuPAddr, pMapping->CpuVAddr, pMapping->uSize, uFlags, &pMapping->hOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "WrapMemory: OSRegisterMem Phys=0x%08X, Size=%d) failed", pMapping->CpuPAddr.uiAddr, pMapping->uSize)); goto fail_cleanup; } } else { pMapping->eCpuMemoryOrigin = hm_wrapped_scatter_virtaddr; pMapping->psSysAddr = psAddr; if(OSRegisterDiscontigMem(pMapping->psSysAddr, pMapping->CpuVAddr, pMapping->uSize, uFlags, &pMapping->hOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "WrapMemory: OSRegisterDiscontigMem Size=%d) failed", pMapping->uSize)); goto fail_cleanup; } } } else { if (bPhysContig) { pMapping->eCpuMemoryOrigin = hm_wrapped; pMapping->CpuPAddr = SysSysPAddrToCpuPAddr(psAddr[0]); if(OSReservePhys(pMapping->CpuPAddr, pMapping->uSize, uFlags, &pMapping->CpuVAddr, &pMapping->hOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "WrapMemory: OSReservePhys Phys=0x%08X, Size=%d) failed", pMapping->CpuPAddr.uiAddr, pMapping->uSize)); goto fail_cleanup; } } else { pMapping->eCpuMemoryOrigin = hm_wrapped_scatter; pMapping->psSysAddr = psAddr; if(OSReserveDiscontigPhys(pMapping->psSysAddr, pMapping->uSize, uFlags, &pMapping->CpuVAddr, &pMapping->hOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "WrapMemory: OSReserveDiscontigPhys Size=%d) failed", pMapping->uSize)); goto fail_cleanup; } } } bResult = DevMemoryAlloc(psBMHeap->pBMContext, pMapping, IMG_NULL, uFlags | PVRSRV_MEM_READ | PVRSRV_MEM_WRITE, IMG_CAST_TO_DEVVADDR_UINT(ui32PageSize), &DevVAddr); if (!bResult) { PVR_DPF((PVR_DBG_ERROR, "WrapMemory: DevMemoryAlloc(0x%x) failed", pMapping->uSize)); goto fail_cleanup; } pBuf->CpuPAddr.uiAddr = pMapping->CpuPAddr.uiAddr + ui32BaseOffset; if(!ui32BaseOffset) { pBuf->hOSMemHandle = pMapping->hOSMemHandle; } else { if(OSGetSubMemHandle(pMapping->hOSMemHandle, ui32BaseOffset, (pMapping->uSize-ui32BaseOffset), uFlags, &pBuf->hOSMemHandle)!=PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "WrapMemory: OSGetSubMemHandle failed")); goto fail_cleanup; } } if(pMapping->CpuVAddr) { pBuf->CpuVAddr = (IMG_VOID*) ((IMG_UINTPTR_T)pMapping->CpuVAddr + ui32BaseOffset); } pBuf->DevVAddr.uiAddr = pMapping->DevVAddr.uiAddr + IMG_CAST_TO_DEVVADDR_UINT(ui32BaseOffset); if(uFlags & PVRSRV_MEM_ZERO) { if(!ZeroBuf(pBuf, pMapping, uSize, uFlags)) { return IMG_FALSE; } } PVR_DPF ((PVR_DBG_MESSAGE, "DevVaddr.uiAddr=%08X", DevVAddr.uiAddr)); PVR_DPF ((PVR_DBG_MESSAGE, "WrapMemory: DevV=%08X CpuP=%08X uSize=0x%x", pMapping->DevVAddr.uiAddr, pMapping->CpuPAddr.uiAddr, pMapping->uSize)); PVR_DPF ((PVR_DBG_MESSAGE, "WrapMemory: DevV=%08X CpuP=%08X uSize=0x%x", pBuf->DevVAddr.uiAddr, pBuf->CpuPAddr.uiAddr, uSize)); pBuf->pMapping = pMapping; return IMG_TRUE; fail_cleanup: if(ui32BaseOffset && pBuf->hOSMemHandle) { OSReleaseSubMemHandle(pBuf->hOSMemHandle, uFlags); } if(pMapping && (pMapping->CpuVAddr || pMapping->hOSMemHandle)) { switch(pMapping->eCpuMemoryOrigin) { case hm_wrapped: OSUnReservePhys(pMapping->CpuVAddr, pMapping->uSize, uFlags, pMapping->hOSMemHandle); break; case hm_wrapped_virtaddr: OSUnRegisterMem(pMapping->CpuVAddr, pMapping->uSize, uFlags, pMapping->hOSMemHandle); break; case hm_wrapped_scatter: OSUnReserveDiscontigPhys(pMapping->CpuVAddr, pMapping->uSize, uFlags, pMapping->hOSMemHandle); break; case hm_wrapped_scatter_virtaddr: OSUnRegisterDiscontigMem(pMapping->CpuVAddr, pMapping->uSize, uFlags, pMapping->hOSMemHandle); break; default: break; } } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_MAPPING), pMapping, IMG_NULL); return IMG_FALSE; } static IMG_BOOL ZeroBuf(BM_BUF *pBuf, BM_MAPPING *pMapping, IMG_SIZE_T ui32Bytes, IMG_UINT32 ui32Flags) { IMG_VOID *pvCpuVAddr; if(pBuf->CpuVAddr) { OSMemSet(pBuf->CpuVAddr, 0, ui32Bytes); } else if(pMapping->eCpuMemoryOrigin == hm_contiguous || pMapping->eCpuMemoryOrigin == hm_wrapped) { pvCpuVAddr = OSMapPhysToLin(pBuf->CpuPAddr, ui32Bytes, PVRSRV_HAP_KERNEL_ONLY | (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK), IMG_NULL); if(!pvCpuVAddr) { PVR_DPF((PVR_DBG_ERROR, "ZeroBuf: OSMapPhysToLin for contiguous buffer failed")); return IMG_FALSE; } OSMemSet(pvCpuVAddr, 0, ui32Bytes); OSUnMapPhysToLin(pvCpuVAddr, ui32Bytes, PVRSRV_HAP_KERNEL_ONLY | (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK), IMG_NULL); } else { IMG_SIZE_T ui32BytesRemaining = ui32Bytes; IMG_SIZE_T ui32CurrentOffset = 0; IMG_CPU_PHYADDR CpuPAddr; PVR_ASSERT(pBuf->hOSMemHandle); while(ui32BytesRemaining > 0) { IMG_SIZE_T ui32BlockBytes = MIN(ui32BytesRemaining, HOST_PAGESIZE()); CpuPAddr = OSMemHandleToCpuPAddr(pBuf->hOSMemHandle, ui32CurrentOffset); if(CpuPAddr.uiAddr & (HOST_PAGESIZE() -1)) { ui32BlockBytes = MIN(ui32BytesRemaining, (IMG_UINT32)(HOST_PAGEALIGN(CpuPAddr.uiAddr) - CpuPAddr.uiAddr)); } pvCpuVAddr = OSMapPhysToLin(CpuPAddr, ui32BlockBytes, PVRSRV_HAP_KERNEL_ONLY | (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK), IMG_NULL); if(!pvCpuVAddr) { PVR_DPF((PVR_DBG_ERROR, "ZeroBuf: OSMapPhysToLin while zeroing non-contiguous memory FAILED")); return IMG_FALSE; } OSMemSet(pvCpuVAddr, 0, ui32BlockBytes); OSUnMapPhysToLin(pvCpuVAddr, ui32BlockBytes, PVRSRV_HAP_KERNEL_ONLY | (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK), IMG_NULL); ui32BytesRemaining -= ui32BlockBytes; ui32CurrentOffset += ui32BlockBytes; } } return IMG_TRUE; } static IMG_VOID FreeBuf (BM_BUF *pBuf, IMG_UINT32 ui32Flags, IMG_BOOL bFromAllocator) { BM_MAPPING *pMapping; PVRSRV_DEVICE_NODE *psDeviceNode; PVR_DPF ((PVR_DBG_MESSAGE, "FreeBuf: pBuf=0x%x: DevVAddr=%08X CpuVAddr=0x%x CpuPAddr=%08X", (IMG_UINTPTR_T)pBuf, pBuf->DevVAddr.uiAddr, (IMG_UINTPTR_T)pBuf->CpuVAddr, pBuf->CpuPAddr.uiAddr)); pMapping = pBuf->pMapping; psDeviceNode = pMapping->pBMHeap->pBMContext->psDeviceNode; if (psDeviceNode->pfnCacheInvalidate) { psDeviceNode->pfnCacheInvalidate(psDeviceNode); } if(ui32Flags & PVRSRV_MEM_USER_SUPPLIED_DEVVADDR) { if ((pBuf->ui32ExportCount == 0) && (pBuf->ui32RefCount == 0)) { if(ui32Flags & PVRSRV_MEM_RAM_BACKED_ALLOCATION) { PVR_DPF ((PVR_DBG_ERROR, "FreeBuf: combination of DevVAddr management and RAM backing mode unsupported")); } else { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_MAPPING), pMapping, IMG_NULL); pBuf->pMapping = IMG_NULL; } } } else { if(pBuf->hOSMemHandle != pMapping->hOSMemHandle) { if ((pBuf->ui32ExportCount == 0) && (pBuf->ui32RefCount == 0)) { OSReleaseSubMemHandle(pBuf->hOSMemHandle, ui32Flags); } } if(ui32Flags & PVRSRV_MEM_RAM_BACKED_ALLOCATION) { if ((pBuf->ui32ExportCount == 0) && (pBuf->ui32RefCount == 0)) { PVR_ASSERT(pBuf->ui32ExportCount == 0) RA_Free (pBuf->pMapping->pArena, pBuf->DevVAddr.uiAddr, IMG_FALSE); } } else { if ((pBuf->ui32ExportCount == 0) && (pBuf->ui32RefCount == 0)) { switch (pMapping->eCpuMemoryOrigin) { case hm_wrapped: OSUnReservePhys(pMapping->CpuVAddr, pMapping->uSize, ui32Flags, pMapping->hOSMemHandle); break; case hm_wrapped_virtaddr: OSUnRegisterMem(pMapping->CpuVAddr, pMapping->uSize, ui32Flags, pMapping->hOSMemHandle); break; case hm_wrapped_scatter: OSUnReserveDiscontigPhys(pMapping->CpuVAddr, pMapping->uSize, ui32Flags, pMapping->hOSMemHandle); break; case hm_wrapped_scatter_virtaddr: OSUnRegisterDiscontigMem(pMapping->CpuVAddr, pMapping->uSize, ui32Flags, pMapping->hOSMemHandle); break; default: break; } } if (bFromAllocator) DevMemoryFree (pMapping); if ((pBuf->ui32ExportCount == 0) && (pBuf->ui32RefCount == 0)) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_MAPPING), pMapping, IMG_NULL); pBuf->pMapping = IMG_NULL; } } } if ((pBuf->ui32ExportCount == 0) && (pBuf->ui32RefCount == 0)) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_BUF), pBuf, IMG_NULL); } } static PVRSRV_ERROR BM_DestroyContext_AnyCb(BM_HEAP *psBMHeap) { if(psBMHeap->ui32Attribs & (PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG |PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG)) { if (psBMHeap->pImportArena) { IMG_BOOL bTestDelete = RA_TestDelete(psBMHeap->pImportArena); if (!bTestDelete) { PVR_DPF ((PVR_DBG_ERROR, "BM_DestroyContext_AnyCb: RA_TestDelete failed")); return PVRSRV_ERROR_UNABLE_TO_DESTROY_BM_HEAP; } } } return PVRSRV_OK; } PVRSRV_ERROR BM_DestroyContext(IMG_HANDLE hBMContext, IMG_BOOL *pbDestroyed) { PVRSRV_ERROR eError; BM_CONTEXT *pBMContext = (BM_CONTEXT*)hBMContext; PVR_DPF ((PVR_DBG_MESSAGE, "BM_DestroyContext")); if (pbDestroyed != IMG_NULL) { *pbDestroyed = IMG_FALSE; } if (pBMContext == IMG_NULL) { PVR_DPF ((PVR_DBG_ERROR, "BM_DestroyContext: Invalid handle")); return PVRSRV_ERROR_INVALID_PARAMS; } pBMContext->ui32RefCount--; if (pBMContext->ui32RefCount > 0) { return PVRSRV_OK; } eError = List_BM_HEAP_PVRSRV_ERROR_Any(pBMContext->psBMHeap, &BM_DestroyContext_AnyCb); if(eError != PVRSRV_OK) { PVR_DPF ((PVR_DBG_ERROR, "BM_DestroyContext: List_BM_HEAP_PVRSRV_ERROR_Any failed")); #if 0 PVR_DPF ((PVR_DBG_ERROR, "BM_DestroyContext: Cleaning up with ResManFreeSpecial")); if(ResManFreeSpecial() != PVRSRV_OK) { PVR_DPF ((PVR_DBG_ERROR, "BM_DestroyContext: ResManFreeSpecial failed %d",eError)); } #endif return eError; } else { eError = ResManFreeResByPtr(pBMContext->hResItem, CLEANUP_WITH_POLL); if(eError != PVRSRV_OK) { PVR_DPF ((PVR_DBG_ERROR, "BM_DestroyContext: ResManFreeResByPtr failed %d",eError)); return eError; } if (pbDestroyed != IMG_NULL) { *pbDestroyed = IMG_TRUE; } } return PVRSRV_OK; } static PVRSRV_ERROR BM_DestroyContextCallBack_AnyVaCb(BM_HEAP *psBMHeap, va_list va) { PVRSRV_DEVICE_NODE *psDeviceNode; psDeviceNode = va_arg(va, PVRSRV_DEVICE_NODE*); if(psBMHeap->ui32Attribs & (PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG |PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG)) { if (psBMHeap->pImportArena) { RA_Delete (psBMHeap->pImportArena); } } else { PVR_DPF((PVR_DBG_ERROR, "BM_DestroyContext: backing store type unsupported")); return PVRSRV_ERROR_UNSUPPORTED_BACKING_STORE; } psDeviceNode->pfnMMUDelete(psBMHeap->pMMUHeap); OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_HEAP), psBMHeap, IMG_NULL); return PVRSRV_OK; } static PVRSRV_ERROR BM_DestroyContextCallBack(IMG_PVOID pvParam, IMG_UINT32 ui32Param, IMG_BOOL bDummy) { BM_CONTEXT *pBMContext = pvParam; PVRSRV_DEVICE_NODE *psDeviceNode; PVRSRV_ERROR eError; PVR_UNREFERENCED_PARAMETER(ui32Param); PVR_UNREFERENCED_PARAMETER(bDummy); psDeviceNode = pBMContext->psDeviceNode; eError = List_BM_HEAP_PVRSRV_ERROR_Any_va(pBMContext->psBMHeap, &BM_DestroyContextCallBack_AnyVaCb, psDeviceNode); if (eError != PVRSRV_OK) { return eError; } if (pBMContext->psMMUContext) { psDeviceNode->pfnMMUFinalise(pBMContext->psMMUContext); } if (pBMContext->pBufferHash) { HASH_Delete(pBMContext->pBufferHash); } if (pBMContext == psDeviceNode->sDevMemoryInfo.pBMKernelContext) { psDeviceNode->sDevMemoryInfo.pBMKernelContext = IMG_NULL; } else { if (pBMContext->ppsThis != IMG_NULL) { List_BM_CONTEXT_Remove(pBMContext); } } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_CONTEXT), pBMContext, IMG_NULL); return PVRSRV_OK; } static IMG_HANDLE BM_CreateContext_IncRefCount_AnyVaCb(BM_CONTEXT *pBMContext, va_list va) { PRESMAN_CONTEXT hResManContext; hResManContext = va_arg(va, PRESMAN_CONTEXT); if(ResManFindResourceByPtr(hResManContext, pBMContext->hResItem) == PVRSRV_OK) { pBMContext->ui32RefCount++; return pBMContext; } return IMG_NULL; } static IMG_VOID BM_CreateContext_InsertHeap_ForEachVaCb(BM_HEAP *psBMHeap, va_list va) { PVRSRV_DEVICE_NODE *psDeviceNode; BM_CONTEXT *pBMContext; psDeviceNode = va_arg(va, PVRSRV_DEVICE_NODE*); pBMContext = va_arg(va, BM_CONTEXT*); switch(psBMHeap->sDevArena.DevMemHeapType) { case DEVICE_MEMORY_HEAP_SHARED: case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: { psDeviceNode->pfnMMUInsertHeap(pBMContext->psMMUContext, psBMHeap->pMMUHeap); break; } } } IMG_HANDLE BM_CreateContext(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_DEV_PHYADDR *psPDDevPAddr, PVRSRV_PER_PROCESS_DATA *psPerProc, IMG_BOOL *pbCreated) { BM_CONTEXT *pBMContext; DEVICE_MEMORY_INFO *psDevMemoryInfo; IMG_BOOL bKernelContext; PRESMAN_CONTEXT hResManContext; PVR_DPF((PVR_DBG_MESSAGE, "BM_CreateContext")); if (psPerProc == IMG_NULL) { bKernelContext = IMG_TRUE; hResManContext = psDeviceNode->hResManContext; } else { bKernelContext = IMG_FALSE; hResManContext = psPerProc->hResManContext; } if (pbCreated != IMG_NULL) { *pbCreated = IMG_FALSE; } psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo; if (bKernelContext == IMG_FALSE) { IMG_HANDLE res = (IMG_HANDLE) List_BM_CONTEXT_Any_va(psDevMemoryInfo->pBMContext, &BM_CreateContext_IncRefCount_AnyVaCb, hResManContext); if (res) { return res; } } if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (struct _BM_CONTEXT_), (IMG_PVOID *)&pBMContext, IMG_NULL, "Buffer Manager Context") != PVRSRV_OK) { PVR_DPF ((PVR_DBG_ERROR, "BM_CreateContext: Alloc failed")); return IMG_NULL; } OSMemSet(pBMContext, 0, sizeof (BM_CONTEXT)); pBMContext->psDeviceNode = psDeviceNode; pBMContext->pBufferHash = HASH_Create(32); if (pBMContext->pBufferHash==IMG_NULL) { PVR_DPF ((PVR_DBG_ERROR, "BM_CreateContext: HASH_Create failed")); goto cleanup; } if((IMG_NULL == psDeviceNode->pfnMMUInitialise) || (psDeviceNode->pfnMMUInitialise(psDeviceNode, &pBMContext->psMMUContext, psPDDevPAddr) != PVRSRV_OK)) { PVR_DPF((PVR_DBG_ERROR, "BM_CreateContext: MMUInitialise failed")); goto cleanup; } if(bKernelContext) { PVR_ASSERT(psDevMemoryInfo->pBMKernelContext == IMG_NULL); psDevMemoryInfo->pBMKernelContext = pBMContext; } else { PVR_ASSERT(psDevMemoryInfo->pBMKernelContext); if (psDevMemoryInfo->pBMKernelContext == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "BM_CreateContext: psDevMemoryInfo->pBMKernelContext invalid")); goto cleanup; } PVR_ASSERT(psDevMemoryInfo->pBMKernelContext->psBMHeap); pBMContext->psBMSharedHeap = psDevMemoryInfo->pBMKernelContext->psBMHeap; List_BM_HEAP_ForEach_va(pBMContext->psBMSharedHeap, &BM_CreateContext_InsertHeap_ForEachVaCb, psDeviceNode, pBMContext); List_BM_CONTEXT_Insert(&psDevMemoryInfo->pBMContext, pBMContext); } pBMContext->ui32RefCount++; pBMContext->hResItem = ResManRegisterRes(hResManContext, RESMAN_TYPE_DEVICEMEM_CONTEXT, pBMContext, 0, &BM_DestroyContextCallBack); if (pBMContext->hResItem == IMG_NULL) { PVR_DPF ((PVR_DBG_ERROR, "BM_CreateContext: ResManRegisterRes failed")); goto cleanup; } if (pbCreated != IMG_NULL) { *pbCreated = IMG_TRUE; } return (IMG_HANDLE)pBMContext; cleanup: (IMG_VOID)BM_DestroyContextCallBack(pBMContext, 0, CLEANUP_WITH_POLL); return IMG_NULL; } static IMG_VOID *BM_CreateHeap_AnyVaCb(BM_HEAP *psBMHeap, va_list va) { DEVICE_MEMORY_HEAP_INFO *psDevMemHeapInfo; psDevMemHeapInfo = va_arg(va, DEVICE_MEMORY_HEAP_INFO*); if (psBMHeap->sDevArena.ui32HeapID == psDevMemHeapInfo->ui32HeapID) { return psBMHeap; } else { return IMG_NULL; } } IMG_HANDLE BM_CreateHeap (IMG_HANDLE hBMContext, DEVICE_MEMORY_HEAP_INFO *psDevMemHeapInfo) { BM_CONTEXT *pBMContext = (BM_CONTEXT*)hBMContext; PVRSRV_DEVICE_NODE *psDeviceNode; BM_HEAP *psBMHeap; PVR_DPF((PVR_DBG_MESSAGE, "BM_CreateHeap")); if(!pBMContext) { PVR_DPF((PVR_DBG_ERROR, "BM_CreateHeap: BM_CONTEXT null")); return IMG_NULL; } psDeviceNode = pBMContext->psDeviceNode; PVR_ASSERT((psDevMemHeapInfo->ui32HeapSize & (psDevMemHeapInfo->ui32DataPageSize - 1)) == 0); PVR_ASSERT(psDevMemHeapInfo->ui32HeapSize > 0); if(pBMContext->ui32RefCount > 0) { psBMHeap = (BM_HEAP*)List_BM_HEAP_Any_va(pBMContext->psBMHeap, &BM_CreateHeap_AnyVaCb, psDevMemHeapInfo); if (psBMHeap) { return psBMHeap; } } if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (BM_HEAP), (IMG_PVOID *)&psBMHeap, IMG_NULL, "Buffer Manager Heap") != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "BM_CreateHeap: Alloc failed")); return IMG_NULL; } OSMemSet (psBMHeap, 0, sizeof (BM_HEAP)); psBMHeap->sDevArena.ui32HeapID = psDevMemHeapInfo->ui32HeapID; psBMHeap->sDevArena.pszName = psDevMemHeapInfo->pszName; psBMHeap->sDevArena.BaseDevVAddr = psDevMemHeapInfo->sDevVAddrBase; psBMHeap->sDevArena.ui32Size = psDevMemHeapInfo->ui32HeapSize; psBMHeap->sDevArena.DevMemHeapType = psDevMemHeapInfo->DevMemHeapType; psBMHeap->sDevArena.ui32DataPageSize = psDevMemHeapInfo->ui32DataPageSize; psBMHeap->sDevArena.psDeviceMemoryHeapInfo = psDevMemHeapInfo; psBMHeap->ui32Attribs = psDevMemHeapInfo->ui32Attribs; #if defined(SUPPORT_MEMORY_TILING) psBMHeap->ui32XTileStride = psDevMemHeapInfo->ui32XTileStride; #endif psBMHeap->pBMContext = pBMContext; psBMHeap->pMMUHeap = psDeviceNode->pfnMMUCreate (pBMContext->psMMUContext, &psBMHeap->sDevArena, &psBMHeap->pVMArena, &psBMHeap->psMMUAttrib); if (!psBMHeap->pMMUHeap) { PVR_DPF((PVR_DBG_ERROR, "BM_CreateHeap: MMUCreate failed")); goto ErrorExit; } psBMHeap->pImportArena = RA_Create (psDevMemHeapInfo->pszBSName, 0, 0, IMG_NULL, MAX(HOST_PAGESIZE(), psBMHeap->sDevArena.ui32DataPageSize), &BM_ImportMemory, &BM_FreeMemory, IMG_NULL, psBMHeap); if(psBMHeap->pImportArena == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "BM_CreateHeap: RA_Create failed")); goto ErrorExit; } if(psBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG) { psBMHeap->pLocalDevMemArena = psDevMemHeapInfo->psLocalDevMemArena; if(psBMHeap->pLocalDevMemArena == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "BM_CreateHeap: LocalDevMemArena null")); goto ErrorExit; } } List_BM_HEAP_Insert(&pBMContext->psBMHeap, psBMHeap); return (IMG_HANDLE)psBMHeap; ErrorExit: if (psBMHeap->pMMUHeap != IMG_NULL) { psDeviceNode->pfnMMUDelete (psBMHeap->pMMUHeap); } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_HEAP), psBMHeap, IMG_NULL); return IMG_NULL; } IMG_VOID BM_DestroyHeap (IMG_HANDLE hDevMemHeap) { BM_HEAP* psBMHeap = (BM_HEAP*)hDevMemHeap; PVRSRV_DEVICE_NODE *psDeviceNode = psBMHeap->pBMContext->psDeviceNode; PVR_DPF((PVR_DBG_MESSAGE, "BM_DestroyHeap")); if(psBMHeap) { if(psBMHeap->ui32Attribs & (PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG |PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG)) { if (psBMHeap->pImportArena) { RA_Delete (psBMHeap->pImportArena); } } else { PVR_DPF((PVR_DBG_ERROR, "BM_DestroyHeap: backing store type unsupported")); return; } psDeviceNode->pfnMMUDelete (psBMHeap->pMMUHeap); List_BM_HEAP_Remove(psBMHeap); OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_HEAP), psBMHeap, IMG_NULL); } else { PVR_DPF ((PVR_DBG_ERROR, "BM_DestroyHeap: invalid heap handle")); } } IMG_BOOL BM_Reinitialise (PVRSRV_DEVICE_NODE *psDeviceNode) { PVR_DPF((PVR_DBG_MESSAGE, "BM_Reinitialise")); PVR_UNREFERENCED_PARAMETER(psDeviceNode); return IMG_TRUE; } IMG_BOOL BM_Alloc ( IMG_HANDLE hDevMemHeap, IMG_DEV_VIRTADDR *psDevVAddr, IMG_SIZE_T uSize, IMG_UINT32 *pui32Flags, IMG_UINT32 uDevVAddrAlignment, IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength, BM_HANDLE *phBuf) { BM_BUF *pBuf; BM_CONTEXT *pBMContext; BM_HEAP *psBMHeap; SYS_DATA *psSysData; IMG_UINT32 uFlags; if (pui32Flags == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "BM_Alloc: invalid parameter")); PVR_DBG_BREAK; return IMG_FALSE; } uFlags = *pui32Flags; PVR_DPF ((PVR_DBG_MESSAGE, "BM_Alloc (uSize=0x%x, uFlags=0x%x, uDevVAddrAlignment=0x%x)", uSize, uFlags, uDevVAddrAlignment)); SysAcquireData(&psSysData); psBMHeap = (BM_HEAP*)hDevMemHeap; pBMContext = psBMHeap->pBMContext; if(uDevVAddrAlignment == 0) { uDevVAddrAlignment = 1; } if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (BM_BUF), (IMG_PVOID *)&pBuf, IMG_NULL, "Buffer Manager buffer") != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "BM_Alloc: BM_Buf alloc FAILED")); return IMG_FALSE; } OSMemSet(pBuf, 0, sizeof (BM_BUF)); if (AllocMemory(pBMContext, psBMHeap, psDevVAddr, uSize, uFlags, uDevVAddrAlignment, pvPrivData, ui32PrivDataLength, pBuf) != IMG_TRUE) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (BM_BUF), pBuf, IMG_NULL); PVR_DPF((PVR_DBG_ERROR, "BM_Alloc: AllocMemory FAILED")); return IMG_FALSE; } PVR_DPF ((PVR_DBG_MESSAGE, "BM_Alloc (uSize=0x%x, uFlags=0x%x)", uSize, uFlags)); pBuf->ui32RefCount = 1; *phBuf = (BM_HANDLE)pBuf; *pui32Flags = uFlags | psBMHeap->ui32Attribs; if(uFlags & PVRSRV_HAP_CACHETYPE_MASK) { *pui32Flags &= ~PVRSRV_HAP_CACHETYPE_MASK; *pui32Flags |= (uFlags & PVRSRV_HAP_CACHETYPE_MASK); } return IMG_TRUE; } #if defined(PVR_LMA) static IMG_BOOL ValidSysPAddrArrayForDev(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_SYS_PHYADDR *psSysPAddr, IMG_UINT32 ui32PageCount, IMG_SIZE_T ui32PageSize) { IMG_UINT32 i; for (i = 0; i < ui32PageCount; i++) { IMG_SYS_PHYADDR sStartSysPAddr = psSysPAddr[i]; IMG_SYS_PHYADDR sEndSysPAddr; if (!SysVerifySysPAddrToDevPAddr(psDeviceNode->sDevId.eDeviceType, sStartSysPAddr)) { return IMG_FALSE; } sEndSysPAddr.uiAddr = sStartSysPAddr.uiAddr + ui32PageSize; if (!SysVerifySysPAddrToDevPAddr(psDeviceNode->sDevId.eDeviceType, sEndSysPAddr)) { return IMG_FALSE; } } return IMG_TRUE; } static IMG_BOOL ValidSysPAddrRangeForDev(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_SYS_PHYADDR sStartSysPAddr, IMG_SIZE_T ui32Range) { IMG_SYS_PHYADDR sEndSysPAddr; if (!SysVerifySysPAddrToDevPAddr(psDeviceNode->sDevId.eDeviceType, sStartSysPAddr)) { return IMG_FALSE; } sEndSysPAddr.uiAddr = sStartSysPAddr.uiAddr + ui32Range; if (!SysVerifySysPAddrToDevPAddr(psDeviceNode->sDevId.eDeviceType, sEndSysPAddr)) { return IMG_FALSE; } return IMG_TRUE; } #define WRAP_MAPPING_SIZE(ui32ByteSize, ui32PageOffset) HOST_PAGEALIGN((ui32ByteSize) + (ui32PageOffset)) #define WRAP_PAGE_COUNT(ui32ByteSize, ui32PageOffset, ui32HostPageSize) (WRAP_MAPPING_SIZE(ui32ByteSize, ui32PageOffset) / (ui32HostPageSize)) #endif IMG_BOOL BM_Wrap ( IMG_HANDLE hDevMemHeap, IMG_SIZE_T ui32Size, IMG_SIZE_T ui32Offset, IMG_BOOL bPhysContig, IMG_SYS_PHYADDR *psSysAddr, IMG_VOID *pvCPUVAddr, IMG_UINT32 *pui32Flags, BM_HANDLE *phBuf) { BM_BUF *pBuf; BM_CONTEXT *psBMContext; BM_HEAP *psBMHeap; SYS_DATA *psSysData; IMG_SYS_PHYADDR sHashAddress; IMG_UINT32 uFlags; psBMHeap = (BM_HEAP*)hDevMemHeap; psBMContext = psBMHeap->pBMContext; uFlags = psBMHeap->ui32Attribs & (PVRSRV_HAP_CACHETYPE_MASK | PVRSRV_HAP_MAPTYPE_MASK); if ((pui32Flags != IMG_NULL) && ((*pui32Flags & PVRSRV_HAP_CACHETYPE_MASK) != 0)) { uFlags &= ~PVRSRV_HAP_CACHETYPE_MASK; uFlags |= *pui32Flags & PVRSRV_HAP_CACHETYPE_MASK; } PVR_DPF ((PVR_DBG_MESSAGE, "BM_Wrap (uSize=0x%x, uOffset=0x%x, bPhysContig=0x%x, pvCPUVAddr=0x%x, uFlags=0x%x)", ui32Size, ui32Offset, bPhysContig, (IMG_UINTPTR_T)pvCPUVAddr, uFlags)); SysAcquireData(&psSysData); #if defined(PVR_LMA) if (bPhysContig) { if (!ValidSysPAddrRangeForDev(psBMContext->psDeviceNode, *psSysAddr, WRAP_MAPPING_SIZE(ui32Size, ui32Offset))) { PVR_DPF((PVR_DBG_ERROR, "BM_Wrap: System address range invalid for device")); return IMG_FALSE; } } else { IMG_SIZE_T ui32HostPageSize = HOST_PAGESIZE(); if (!ValidSysPAddrArrayForDev(psBMContext->psDeviceNode, psSysAddr, WRAP_PAGE_COUNT(ui32Size, ui32Offset, ui32HostPageSize), ui32HostPageSize)) { PVR_DPF((PVR_DBG_ERROR, "BM_Wrap: Array of system addresses invalid for device")); return IMG_FALSE; } } #endif sHashAddress = psSysAddr[0]; sHashAddress.uiAddr += ui32Offset; pBuf = (BM_BUF *)HASH_Retrieve(psBMContext->pBufferHash, sHashAddress.uiAddr); if(pBuf) { IMG_SIZE_T ui32MappingSize = HOST_PAGEALIGN (ui32Size + ui32Offset); if(pBuf->pMapping->uSize == ui32MappingSize && (pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped || pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr)) { PVR_DPF((PVR_DBG_MESSAGE, "BM_Wrap (Matched previous Wrap! uSize=0x%x, uOffset=0x%x, SysAddr=%08X)", ui32Size, ui32Offset, sHashAddress.uiAddr)); PVRSRVBMBufIncRef(pBuf); *phBuf = (BM_HANDLE)pBuf; if(pui32Flags) *pui32Flags = uFlags; return IMG_TRUE; } else { HASH_Remove(psBMContext->pBufferHash, (IMG_UINTPTR_T)sHashAddress.uiAddr); } } if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (BM_BUF), (IMG_PVOID *)&pBuf, IMG_NULL, "Buffer Manager buffer") != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "BM_Wrap: BM_Buf alloc FAILED")); return IMG_FALSE; } OSMemSet(pBuf, 0, sizeof (BM_BUF)); if (WrapMemory (psBMHeap, ui32Size, ui32Offset, bPhysContig, psSysAddr, pvCPUVAddr, uFlags, pBuf) != IMG_TRUE) { PVR_DPF((PVR_DBG_ERROR, "BM_Wrap: WrapMemory FAILED")); OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (BM_BUF), pBuf, IMG_NULL); return IMG_FALSE; } if(pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped || pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr) { PVR_ASSERT(SysSysPAddrToCpuPAddr(sHashAddress).uiAddr == pBuf->CpuPAddr.uiAddr); if (!HASH_Insert (psBMContext->pBufferHash, sHashAddress.uiAddr, (IMG_UINTPTR_T)pBuf)) { FreeBuf (pBuf, uFlags, IMG_TRUE); PVR_DPF((PVR_DBG_ERROR, "BM_Wrap: HASH_Insert FAILED")); return IMG_FALSE; } } PVR_DPF ((PVR_DBG_MESSAGE, "BM_Wrap (uSize=0x%x, uFlags=0x%x, devVAddr=%08X)", ui32Size, uFlags, pBuf->DevVAddr.uiAddr)); pBuf->ui32RefCount = 1; *phBuf = (BM_HANDLE)pBuf; if(pui32Flags) { *pui32Flags = (uFlags & ~PVRSRV_HAP_MAPTYPE_MASK) | PVRSRV_HAP_MULTI_PROCESS; } return IMG_TRUE; } IMG_VOID BM_Export (BM_HANDLE hBuf) { BM_BUF *pBuf = (BM_BUF *)hBuf; PVRSRVBMBufIncExport(pBuf); } IMG_VOID BM_FreeExport(BM_HANDLE hBuf, IMG_UINT32 ui32Flags) { BM_BUF *pBuf = (BM_BUF *)hBuf; PVRSRVBMBufDecExport(pBuf); FreeBuf (pBuf, ui32Flags, IMG_FALSE); } IMG_VOID BM_Free (BM_HANDLE hBuf, IMG_UINT32 ui32Flags) { BM_BUF *pBuf = (BM_BUF *)hBuf; SYS_DATA *psSysData; IMG_SYS_PHYADDR sHashAddr; PVR_DPF ((PVR_DBG_MESSAGE, "BM_Free (h=0x%x)", (IMG_UINTPTR_T)hBuf)); PVR_ASSERT (pBuf!=IMG_NULL); if (pBuf == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "BM_Free: invalid parameter")); return; } SysAcquireData(&psSysData); PVRSRVBMBufDecRef(pBuf); if(pBuf->ui32RefCount == 0) { if(pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped || pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr) { sHashAddr = SysCpuPAddrToSysPAddr(pBuf->CpuPAddr); HASH_Remove (pBuf->pMapping->pBMHeap->pBMContext->pBufferHash, (IMG_UINTPTR_T)sHashAddr.uiAddr); } FreeBuf (pBuf, ui32Flags, IMG_TRUE); } } IMG_CPU_VIRTADDR BM_HandleToCpuVaddr (BM_HANDLE hBuf) { BM_BUF *pBuf = (BM_BUF *)hBuf; PVR_ASSERT (pBuf != IMG_NULL); if (pBuf == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "BM_HandleToCpuVaddr: invalid parameter")); return IMG_NULL; } PVR_DPF ((PVR_DBG_MESSAGE, "BM_HandleToCpuVaddr(h=0x%x)=0x%x", (IMG_UINTPTR_T)hBuf, (IMG_UINTPTR_T)pBuf->CpuVAddr)); return pBuf->CpuVAddr; } IMG_DEV_VIRTADDR BM_HandleToDevVaddr (BM_HANDLE hBuf) { BM_BUF *pBuf = (BM_BUF *)hBuf; PVR_ASSERT (pBuf != IMG_NULL); if (pBuf == IMG_NULL) { IMG_DEV_VIRTADDR DevVAddr = {0}; PVR_DPF((PVR_DBG_ERROR, "BM_HandleToDevVaddr: invalid parameter")); return DevVAddr; } PVR_DPF ((PVR_DBG_MESSAGE, "BM_HandleToDevVaddr(h=0x%x)=%08X", (IMG_UINTPTR_T)hBuf, pBuf->DevVAddr.uiAddr)); return pBuf->DevVAddr; } IMG_SYS_PHYADDR BM_HandleToSysPaddr (BM_HANDLE hBuf) { BM_BUF *pBuf = (BM_BUF *)hBuf; PVR_ASSERT (pBuf != IMG_NULL); if (pBuf == IMG_NULL) { IMG_SYS_PHYADDR PhysAddr = {0}; PVR_DPF((PVR_DBG_ERROR, "BM_HandleToSysPaddr: invalid parameter")); return PhysAddr; } PVR_DPF ((PVR_DBG_MESSAGE, "BM_HandleToSysPaddr(h=0x%x)=%08X", (IMG_UINTPTR_T)hBuf, pBuf->CpuPAddr.uiAddr)); return SysCpuPAddrToSysPAddr (pBuf->CpuPAddr); } IMG_HANDLE BM_HandleToOSMemHandle(BM_HANDLE hBuf) { BM_BUF *pBuf = (BM_BUF *)hBuf; PVR_ASSERT (pBuf != IMG_NULL); if (pBuf == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "BM_HandleToOSMemHandle: invalid parameter")); return IMG_NULL; } PVR_DPF ((PVR_DBG_MESSAGE, "BM_HandleToOSMemHandle(h=0x%x)=0x%x", (IMG_UINTPTR_T)hBuf, (IMG_UINTPTR_T)pBuf->hOSMemHandle)); return pBuf->hOSMemHandle; } static IMG_BOOL DevMemoryAlloc (BM_CONTEXT *pBMContext, BM_MAPPING *pMapping, IMG_SIZE_T *pActualSize, IMG_UINT32 uFlags, IMG_UINT32 dev_vaddr_alignment, IMG_DEV_VIRTADDR *pDevVAddr) { PVRSRV_DEVICE_NODE *psDeviceNode; #ifdef PDUMP IMG_UINT32 ui32PDumpSize = (IMG_UINT32)pMapping->uSize; #endif psDeviceNode = pBMContext->psDeviceNode; if(uFlags & PVRSRV_MEM_INTERLEAVED) { pMapping->uSize *= 2; } #ifdef PDUMP if(uFlags & PVRSRV_MEM_DUMMY) { ui32PDumpSize = pMapping->pBMHeap->sDevArena.ui32DataPageSize; } #endif if (!psDeviceNode->pfnMMUAlloc (pMapping->pBMHeap->pMMUHeap, pMapping->uSize, pActualSize, 0, dev_vaddr_alignment, &(pMapping->DevVAddr))) { PVR_DPF((PVR_DBG_ERROR, "DevMemoryAlloc ERROR MMU_Alloc")); return IMG_FALSE; } #ifdef SUPPORT_SGX_MMU_BYPASS EnableHostAccess(pBMContext->psMMUContext); #endif #if defined(PDUMP) PDUMPMALLOCPAGES(&psDeviceNode->sDevId, pMapping->DevVAddr.uiAddr, pMapping->CpuVAddr, pMapping->hOSMemHandle, ui32PDumpSize, pMapping->pBMHeap->sDevArena.ui32DataPageSize, #if defined(SUPPORT_PDUMP_MULTI_PROCESS) psDeviceNode->pfnMMUIsHeapShared(pMapping->pBMHeap->pMMUHeap), #else IMG_FALSE, #endif (IMG_HANDLE)pMapping); #endif switch (pMapping->eCpuMemoryOrigin) { case hm_wrapped: case hm_wrapped_virtaddr: case hm_contiguous: { psDeviceNode->pfnMMUMapPages ( pMapping->pBMHeap->pMMUHeap, pMapping->DevVAddr, SysCpuPAddrToSysPAddr (pMapping->CpuPAddr), pMapping->uSize, uFlags, (IMG_HANDLE)pMapping); *pDevVAddr = pMapping->DevVAddr; break; } case hm_env: { psDeviceNode->pfnMMUMapShadow ( pMapping->pBMHeap->pMMUHeap, pMapping->DevVAddr, pMapping->uSize, pMapping->CpuVAddr, pMapping->hOSMemHandle, pDevVAddr, uFlags, (IMG_HANDLE)pMapping); break; } case hm_wrapped_scatter: case hm_wrapped_scatter_virtaddr: { psDeviceNode->pfnMMUMapScatter (pMapping->pBMHeap->pMMUHeap, pMapping->DevVAddr, pMapping->psSysAddr, pMapping->uSize, uFlags, (IMG_HANDLE)pMapping); *pDevVAddr = pMapping->DevVAddr; break; } default: PVR_DPF((PVR_DBG_ERROR, "Illegal value %d for pMapping->eCpuMemoryOrigin", pMapping->eCpuMemoryOrigin)); return IMG_FALSE; } #ifdef SUPPORT_SGX_MMU_BYPASS DisableHostAccess(pBMContext->psMMUContext); #endif return IMG_TRUE; } static IMG_VOID DevMemoryFree (BM_MAPPING *pMapping) { PVRSRV_DEVICE_NODE *psDeviceNode; IMG_DEV_PHYADDR sDevPAddr; #ifdef PDUMP IMG_UINT32 ui32PSize; #endif psDeviceNode = pMapping->pBMHeap->pBMContext->psDeviceNode; sDevPAddr = psDeviceNode->pfnMMUGetPhysPageAddr(pMapping->pBMHeap->pMMUHeap, pMapping->DevVAddr); if (sDevPAddr.uiAddr != 0) { #ifdef PDUMP if(pMapping->ui32Flags & PVRSRV_MEM_DUMMY) { ui32PSize = pMapping->pBMHeap->sDevArena.ui32DataPageSize; } else { ui32PSize = (IMG_UINT32)pMapping->uSize; } PDUMPFREEPAGES(pMapping->pBMHeap, pMapping->DevVAddr, ui32PSize, pMapping->pBMHeap->sDevArena.ui32DataPageSize, (IMG_HANDLE)pMapping, (pMapping->ui32Flags & PVRSRV_MEM_INTERLEAVED) ? IMG_TRUE : IMG_FALSE); #endif } psDeviceNode->pfnMMUFree (pMapping->pBMHeap->pMMUHeap, pMapping->DevVAddr, IMG_CAST_TO_DEVVADDR_UINT(pMapping->uSize)); } #ifndef XPROC_WORKAROUND_NUM_SHAREABLES #define XPROC_WORKAROUND_NUM_SHAREABLES 200 #endif #define XPROC_WORKAROUND_BAD_SHAREINDEX 0773407734 #define XPROC_WORKAROUND_UNKNOWN 0 #define XPROC_WORKAROUND_ALLOC 1 #define XPROC_WORKAROUND_MAP 2 static IMG_UINT32 gXProcWorkaroundShareIndex = XPROC_WORKAROUND_BAD_SHAREINDEX; static IMG_UINT32 gXProcWorkaroundState = XPROC_WORKAROUND_UNKNOWN; static struct { IMG_UINT32 ui32RefCount; IMG_UINT32 ui32AllocFlags; IMG_UINT32 ui32Size; IMG_UINT32 ui32PageSize; RA_ARENA *psArena; IMG_SYS_PHYADDR sSysPAddr; IMG_VOID *pvCpuVAddr; IMG_HANDLE hOSMemHandle; } gXProcWorkaroundShareData[XPROC_WORKAROUND_NUM_SHAREABLES] = {{0}}; PVRSRV_ERROR BM_XProcWorkaroundSetShareIndex(IMG_UINT32 ui32Index) { if (gXProcWorkaroundShareIndex != XPROC_WORKAROUND_BAD_SHAREINDEX) { PVR_DPF((PVR_DBG_ERROR, "No, it's already set!")); return PVRSRV_ERROR_INVALID_PARAMS; } gXProcWorkaroundShareIndex = ui32Index; gXProcWorkaroundState = XPROC_WORKAROUND_MAP; return PVRSRV_OK; } PVRSRV_ERROR BM_XProcWorkaroundUnsetShareIndex(IMG_UINT32 ui32Index) { if (gXProcWorkaroundShareIndex == XPROC_WORKAROUND_BAD_SHAREINDEX) { PVR_DPF((PVR_DBG_ERROR, "huh? how can it be bad??")); return PVRSRV_ERROR_INVALID_PARAMS; } if (gXProcWorkaroundShareIndex != ui32Index) { PVR_DPF((PVR_DBG_ERROR, "gXProcWorkaroundShareIndex == 0x%08x != 0x%08x == ui32Index", gXProcWorkaroundShareIndex, ui32Index)); return PVRSRV_ERROR_INVALID_PARAMS; } gXProcWorkaroundShareIndex = XPROC_WORKAROUND_BAD_SHAREINDEX; gXProcWorkaroundState = XPROC_WORKAROUND_UNKNOWN; return PVRSRV_OK; } PVRSRV_ERROR BM_XProcWorkaroundFindNewBufferAndSetShareIndex(IMG_UINT32 *pui32Index) { if (gXProcWorkaroundShareIndex != XPROC_WORKAROUND_BAD_SHAREINDEX) { return PVRSRV_ERROR_INVALID_PARAMS; } for (*pui32Index = 0; *pui32Index < XPROC_WORKAROUND_NUM_SHAREABLES; (*pui32Index)++) { if (gXProcWorkaroundShareData[*pui32Index].ui32RefCount == 0) { gXProcWorkaroundShareIndex = *pui32Index; gXProcWorkaroundState = XPROC_WORKAROUND_ALLOC; return PVRSRV_OK; } } PVR_DPF((PVR_DBG_ERROR, "ran out of shared buffers")); return PVRSRV_ERROR_OUT_OF_MEMORY; } static PVRSRV_ERROR XProcWorkaroundAllocShareable(RA_ARENA *psArena, IMG_UINT32 ui32AllocFlags, IMG_UINT32 ui32Size, IMG_UINT32 ui32PageSize, IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength, IMG_VOID **ppvCpuVAddr, IMG_HANDLE *phOSMemHandle) { if ((ui32AllocFlags & PVRSRV_MEM_XPROC) == 0) { PVR_DPF((PVR_DBG_VERBOSE, "XProcWorkaroundAllocShareable: bad flags")); return PVRSRV_ERROR_INVALID_PARAMS; } if (gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32RefCount > 0) { PVR_DPF((PVR_DBG_VERBOSE, "XProcWorkaroundAllocShareable: re-using previously allocated pages")); ui32AllocFlags &= ~PVRSRV_HAP_MAPTYPE_MASK; ui32AllocFlags |= PVRSRV_HAP_SINGLE_PROCESS; if (ui32AllocFlags != gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32AllocFlags) { PVR_DPF((PVR_DBG_ERROR, "Can't! Flags don't match! (I had 0x%08x, you gave 0x%08x)", gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32AllocFlags, ui32AllocFlags)); return PVRSRV_ERROR_INVALID_PARAMS; } if (ui32Size != gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32Size) { PVR_DPF((PVR_DBG_ERROR, "Can't! Size doesn't match!")); return PVRSRV_ERROR_INVALID_PARAMS; } if (ui32PageSize != gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32PageSize) { PVR_DPF((PVR_DBG_ERROR, "Can't! Page Size doesn't match!")); return PVRSRV_ERROR_INVALID_PARAMS; } *ppvCpuVAddr = gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].pvCpuVAddr; *phOSMemHandle = gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].hOSMemHandle; gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32RefCount++; return PVRSRV_OK; } else { if (gXProcWorkaroundState != XPROC_WORKAROUND_ALLOC) { PVR_DPF((PVR_DBG_ERROR, "XPROC workaround in bad state! About to allocate memory from non-alloc state! (%d)", gXProcWorkaroundState)); } PVR_ASSERT(gXProcWorkaroundState == XPROC_WORKAROUND_ALLOC); if (psArena != IMG_NULL) { IMG_CPU_PHYADDR sCpuPAddr; IMG_SYS_PHYADDR sSysPAddr; PVR_DPF((PVR_DBG_VERBOSE, "XProcWorkaroundAllocShareable: making a NEW allocation from local mem")); if (!RA_Alloc (psArena, ui32Size, IMG_NULL, IMG_NULL, 0, ui32PageSize, 0, pvPrivData, ui32PrivDataLength, (IMG_UINTPTR_T *)&sSysPAddr.uiAddr)) { PVR_DPF((PVR_DBG_ERROR, "XProcWorkaroundAllocShareable: RA_Alloc(0x%x) FAILED", ui32Size)); return PVRSRV_ERROR_OUT_OF_MEMORY; } sCpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); if(OSReservePhys(sCpuPAddr, ui32Size, ui32AllocFlags, (IMG_VOID **)&gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].pvCpuVAddr, &gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].hOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "XProcWorkaroundAllocShareable: OSReservePhys failed")); return PVRSRV_ERROR_OUT_OF_MEMORY; } gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].sSysPAddr = sSysPAddr; } else { PVR_DPF((PVR_DBG_VERBOSE, "XProcWorkaroundAllocShareable: making a NEW allocation from OS")); ui32AllocFlags &= ~PVRSRV_HAP_MAPTYPE_MASK; ui32AllocFlags |= PVRSRV_HAP_SINGLE_PROCESS; if (OSAllocPages(ui32AllocFlags, ui32Size, ui32PageSize, pvPrivData, ui32PrivDataLength, (IMG_VOID **)&gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].pvCpuVAddr, &gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].hOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "XProcWorkaroundAllocShareable: OSAllocPages(0x%x) failed", ui32PageSize)); return PVRSRV_ERROR_OUT_OF_MEMORY; } } gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].psArena = psArena; gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32AllocFlags = ui32AllocFlags; gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32Size = ui32Size; gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32PageSize = ui32PageSize; *ppvCpuVAddr = gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].pvCpuVAddr; *phOSMemHandle = gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].hOSMemHandle; gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32RefCount++; return PVRSRV_OK; } } static PVRSRV_ERROR XProcWorkaroundHandleToSI(IMG_HANDLE hOSMemHandle, IMG_UINT32 *pui32SI) { IMG_UINT32 ui32SI; IMG_BOOL bFound; IMG_BOOL bErrorDups; bFound = IMG_FALSE; bErrorDups = IMG_FALSE; for (ui32SI = 0; ui32SI < XPROC_WORKAROUND_NUM_SHAREABLES; ui32SI++) { if (gXProcWorkaroundShareData[ui32SI].ui32RefCount>0 && gXProcWorkaroundShareData[ui32SI].hOSMemHandle == hOSMemHandle) { if (bFound) { bErrorDups = IMG_TRUE; } else { *pui32SI = ui32SI; bFound = IMG_TRUE; } } } if (bErrorDups || !bFound) { return PVRSRV_ERROR_BM_BAD_SHAREMEM_HANDLE; } return PVRSRV_OK; } static IMG_VOID XProcWorkaroundFreeShareable(IMG_HANDLE hOSMemHandle) { IMG_UINT32 ui32SI = (IMG_UINT32)((IMG_UINTPTR_T)hOSMemHandle & 0xffffU); PVRSRV_ERROR eError; eError = XProcWorkaroundHandleToSI(hOSMemHandle, &ui32SI); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "bad handle")); return; } gXProcWorkaroundShareData[ui32SI].ui32RefCount--; PVR_DPF((PVR_DBG_VERBOSE, "Reduced refcount of SI[%d] from %d to %d", ui32SI, gXProcWorkaroundShareData[ui32SI].ui32RefCount+1, gXProcWorkaroundShareData[ui32SI].ui32RefCount)); if (gXProcWorkaroundShareData[ui32SI].ui32RefCount == 0) { if (gXProcWorkaroundShareData[ui32SI].psArena != IMG_NULL) { IMG_SYS_PHYADDR sSysPAddr; if (gXProcWorkaroundShareData[ui32SI].pvCpuVAddr != IMG_NULL) { OSUnReservePhys(gXProcWorkaroundShareData[ui32SI].pvCpuVAddr, gXProcWorkaroundShareData[ui32SI].ui32Size, gXProcWorkaroundShareData[ui32SI].ui32AllocFlags, gXProcWorkaroundShareData[ui32SI].hOSMemHandle); } sSysPAddr = gXProcWorkaroundShareData[ui32SI].sSysPAddr; RA_Free (gXProcWorkaroundShareData[ui32SI].psArena, sSysPAddr.uiAddr, IMG_FALSE); } else { PVR_DPF((PVR_DBG_VERBOSE, "freeing OS memory")); OSFreePages(gXProcWorkaroundShareData[ui32SI].ui32AllocFlags, gXProcWorkaroundShareData[ui32SI].ui32PageSize, gXProcWorkaroundShareData[ui32SI].pvCpuVAddr, gXProcWorkaroundShareData[ui32SI].hOSMemHandle); } } } static IMG_BOOL BM_ImportMemory (IMG_VOID *pH, IMG_SIZE_T uRequestSize, IMG_SIZE_T *pActualSize, BM_MAPPING **ppsMapping, IMG_UINT32 uFlags, IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength, IMG_UINTPTR_T *pBase) { BM_MAPPING *pMapping; BM_HEAP *pBMHeap = pH; BM_CONTEXT *pBMContext = pBMHeap->pBMContext; IMG_BOOL bResult; IMG_SIZE_T uSize; IMG_SIZE_T uPSize; IMG_SIZE_T uDevVAddrAlignment = 0; PVR_DPF ((PVR_DBG_MESSAGE, "BM_ImportMemory (pBMContext=0x%x, uRequestSize=0x%x, uFlags=0x%x, uAlign=0x%x)", (IMG_UINTPTR_T)pBMContext, uRequestSize, uFlags, uDevVAddrAlignment)); PVR_ASSERT (ppsMapping != IMG_NULL); PVR_ASSERT (pBMContext != IMG_NULL); if (ppsMapping == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "BM_ImportMemory: invalid parameter")); goto fail_exit; } uSize = HOST_PAGEALIGN (uRequestSize); PVR_ASSERT (uSize >= uRequestSize); if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (BM_MAPPING), (IMG_PVOID *)&pMapping, IMG_NULL, "Buffer Manager Mapping") != PVRSRV_OK) { PVR_DPF ((PVR_DBG_ERROR, "BM_ImportMemory: failed BM_MAPPING alloc")); goto fail_exit; } pMapping->hOSMemHandle = 0; pMapping->CpuVAddr = 0; pMapping->DevVAddr.uiAddr = 0; pMapping->CpuPAddr.uiAddr = 0; pMapping->uSize = uSize; pMapping->pBMHeap = pBMHeap; pMapping->ui32Flags = uFlags; if (pActualSize) { *pActualSize = uSize; } if(pMapping->ui32Flags & PVRSRV_MEM_DUMMY) { uPSize = pBMHeap->sDevArena.ui32DataPageSize; } else { uPSize = pMapping->uSize; } if (uFlags & PVRSRV_MEM_XPROC) { IMG_UINT32 ui32Attribs = pBMHeap->ui32Attribs | PVRSRV_MEM_XPROC; IMG_BOOL bBadBackingStoreType; if(uFlags & PVRSRV_MEM_ION) { ui32Attribs |= PVRSRV_MEM_ION; } bBadBackingStoreType = IMG_TRUE; if ((ui32Attribs & PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG) != 0) { #ifndef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif uDevVAddrAlignment = MAX(pBMHeap->sDevArena.ui32DataPageSize, HOST_PAGESIZE()); if (uPSize % uDevVAddrAlignment != 0) { PVR_DPF((PVR_DBG_ERROR, "Cannot use use this memory sharing workaround with allocations that might be suballocated")); goto fail_mapping_alloc; } uDevVAddrAlignment = 0; if (pMapping->ui32Flags & PVRSRV_HAP_CACHETYPE_MASK) { ui32Attribs &= ~PVRSRV_HAP_CACHETYPE_MASK; ui32Attribs |= (pMapping->ui32Flags & PVRSRV_HAP_CACHETYPE_MASK); } if (XProcWorkaroundAllocShareable(IMG_NULL, ui32Attribs, (IMG_UINT32)uPSize, pBMHeap->sDevArena.ui32DataPageSize, pvPrivData, ui32PrivDataLength, (IMG_VOID **)&pMapping->CpuVAddr, &pMapping->hOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "BM_ImportMemory: XProcWorkaroundAllocShareable(0x%x) failed", uPSize)); goto fail_mapping_alloc; } pMapping->eCpuMemoryOrigin = hm_env; bBadBackingStoreType = IMG_FALSE; } if ((ui32Attribs & PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG) != 0) { uDevVAddrAlignment = pBMHeap->sDevArena.ui32DataPageSize; if (uPSize % uDevVAddrAlignment != 0) { PVR_DPF((PVR_DBG_ERROR, "Cannot use use this memory sharing workaround with allocations that might be suballocated")); goto fail_mapping_alloc; } uDevVAddrAlignment = 0; if (pMapping->ui32Flags & PVRSRV_HAP_CACHETYPE_MASK) { ui32Attribs &= ~PVRSRV_HAP_CACHETYPE_MASK; ui32Attribs |= (pMapping->ui32Flags & PVRSRV_HAP_CACHETYPE_MASK); } if (XProcWorkaroundAllocShareable(pBMHeap->pLocalDevMemArena, ui32Attribs, (IMG_UINT32)uPSize, pBMHeap->sDevArena.ui32DataPageSize, pvPrivData, ui32PrivDataLength, (IMG_VOID **)&pMapping->CpuVAddr, &pMapping->hOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "BM_ImportMemory: XProcWorkaroundAllocShareable(0x%x) failed", uPSize)); goto fail_mapping_alloc; } pMapping->eCpuMemoryOrigin = hm_env; bBadBackingStoreType = IMG_FALSE; } if (bBadBackingStoreType) { PVR_DPF((PVR_DBG_ERROR, "Cannot use this memory sharing workaround with this type of backing store")); goto fail_mapping_alloc; } } else if(pBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG) { IMG_UINT32 ui32Attribs = pBMHeap->ui32Attribs; if (pMapping->ui32Flags & PVRSRV_HAP_CACHETYPE_MASK) { ui32Attribs &= ~PVRSRV_HAP_CACHETYPE_MASK; ui32Attribs |= (pMapping->ui32Flags & PVRSRV_HAP_CACHETYPE_MASK); } if (pMapping->ui32Flags & PVRSRV_MEM_ALLOCATENONCACHEDMEM) { ui32Attribs &= ~PVRSRV_MEM_ALLOCATENONCACHEDMEM; ui32Attribs |= (pMapping->ui32Flags & PVRSRV_MEM_ALLOCATENONCACHEDMEM); } if (OSAllocPages(ui32Attribs, uPSize, pBMHeap->sDevArena.ui32DataPageSize, pvPrivData, ui32PrivDataLength, (IMG_VOID **)&pMapping->CpuVAddr, &pMapping->hOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "BM_ImportMemory: OSAllocPages(0x%x) failed", uPSize)); goto fail_mapping_alloc; } pMapping->eCpuMemoryOrigin = hm_env; } else if(pBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG) { IMG_SYS_PHYADDR sSysPAddr; IMG_UINT32 ui32Attribs = pBMHeap->ui32Attribs; PVR_ASSERT(pBMHeap->pLocalDevMemArena != IMG_NULL); if (pMapping->ui32Flags & PVRSRV_HAP_CACHETYPE_MASK) { ui32Attribs &= ~PVRSRV_HAP_CACHETYPE_MASK; ui32Attribs |= (pMapping->ui32Flags & PVRSRV_HAP_CACHETYPE_MASK); } if (!RA_Alloc (pBMHeap->pLocalDevMemArena, uPSize, IMG_NULL, IMG_NULL, 0, pBMHeap->sDevArena.ui32DataPageSize, 0, pvPrivData, ui32PrivDataLength, (IMG_UINTPTR_T *)&sSysPAddr.uiAddr)) { PVR_DPF((PVR_DBG_ERROR, "BM_ImportMemory: RA_Alloc(0x%x) FAILED", uPSize)); goto fail_mapping_alloc; } pMapping->CpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); if(OSReservePhys(pMapping->CpuPAddr, uPSize, ui32Attribs, &pMapping->CpuVAddr, &pMapping->hOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "BM_ImportMemory: OSReservePhys failed")); goto fail_dev_mem_alloc; } pMapping->eCpuMemoryOrigin = hm_contiguous; } else { PVR_DPF((PVR_DBG_ERROR, "BM_ImportMemory: Invalid backing store type")); goto fail_mapping_alloc; } bResult = DevMemoryAlloc (pBMContext, pMapping, IMG_NULL, uFlags, (IMG_UINT32)uDevVAddrAlignment, &pMapping->DevVAddr); if (!bResult) { PVR_DPF((PVR_DBG_ERROR, "BM_ImportMemory: DevMemoryAlloc(0x%x) failed", pMapping->uSize)); goto fail_dev_mem_alloc; } PVR_ASSERT (uDevVAddrAlignment>1?(pMapping->DevVAddr.uiAddr%uDevVAddrAlignment)==0:1); *pBase = pMapping->DevVAddr.uiAddr; *ppsMapping = pMapping; PVR_DPF ((PVR_DBG_MESSAGE, "BM_ImportMemory: IMG_TRUE")); return IMG_TRUE; fail_dev_mem_alloc: if (pMapping && (pMapping->CpuVAddr || pMapping->hOSMemHandle)) { if(pMapping->ui32Flags & PVRSRV_MEM_INTERLEAVED) { pMapping->uSize /= 2; } if(pMapping->ui32Flags & PVRSRV_MEM_DUMMY) { uPSize = pBMHeap->sDevArena.ui32DataPageSize; } else { uPSize = pMapping->uSize; } if (uFlags & PVRSRV_MEM_XPROC) { XProcWorkaroundFreeShareable(pMapping->hOSMemHandle); } else if(pBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG) { OSFreePages(pBMHeap->ui32Attribs, uPSize, (IMG_VOID *)pMapping->CpuVAddr, pMapping->hOSMemHandle); } else { IMG_SYS_PHYADDR sSysPAddr; if(pMapping->CpuVAddr) { OSUnReservePhys(pMapping->CpuVAddr, uPSize, pBMHeap->ui32Attribs, pMapping->hOSMemHandle); } sSysPAddr = SysCpuPAddrToSysPAddr(pMapping->CpuPAddr); RA_Free (pBMHeap->pLocalDevMemArena, sSysPAddr.uiAddr, IMG_FALSE); } } fail_mapping_alloc: OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_MAPPING), pMapping, IMG_NULL); fail_exit: return IMG_FALSE; } static IMG_VOID BM_FreeMemory (IMG_VOID *h, IMG_UINTPTR_T _base, BM_MAPPING *psMapping) { BM_HEAP *pBMHeap = h; IMG_SIZE_T uPSize; PVR_UNREFERENCED_PARAMETER (_base); PVR_DPF ((PVR_DBG_MESSAGE, "BM_FreeMemory (h=0x%x, base=0x%x, psMapping=0x%x)", (IMG_UINTPTR_T)h, _base, (IMG_UINTPTR_T)psMapping)); PVR_ASSERT (psMapping != IMG_NULL); if (psMapping == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "BM_FreeMemory: invalid parameter")); return; } DevMemoryFree (psMapping); if((psMapping->ui32Flags & PVRSRV_MEM_INTERLEAVED) != 0) { psMapping->uSize /= 2; } if(psMapping->ui32Flags & PVRSRV_MEM_DUMMY) { uPSize = psMapping->pBMHeap->sDevArena.ui32DataPageSize; } else { uPSize = psMapping->uSize; } if (psMapping->ui32Flags & PVRSRV_MEM_XPROC) { XProcWorkaroundFreeShareable(psMapping->hOSMemHandle); } else if(pBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG) { OSFreePages(pBMHeap->ui32Attribs, uPSize, (IMG_VOID *) psMapping->CpuVAddr, psMapping->hOSMemHandle); } else if(pBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG) { IMG_SYS_PHYADDR sSysPAddr; OSUnReservePhys(psMapping->CpuVAddr, uPSize, pBMHeap->ui32Attribs, psMapping->hOSMemHandle); sSysPAddr = SysCpuPAddrToSysPAddr(psMapping->CpuPAddr); RA_Free (pBMHeap->pLocalDevMemArena, sSysPAddr.uiAddr, IMG_FALSE); } else { PVR_DPF((PVR_DBG_ERROR, "BM_FreeMemory: Invalid backing store type")); } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_MAPPING), psMapping, IMG_NULL); PVR_DPF((PVR_DBG_MESSAGE, "..BM_FreeMemory (h=0x%x, base=0x%x)", (IMG_UINTPTR_T)h, _base)); } IMG_VOID BM_GetPhysPageAddr(PVRSRV_KERNEL_MEM_INFO *psMemInfo, IMG_DEV_VIRTADDR sDevVPageAddr, IMG_DEV_PHYADDR *psDevPAddr) { PVRSRV_DEVICE_NODE *psDeviceNode; PVR_DPF((PVR_DBG_MESSAGE, "BM_GetPhysPageAddr")); PVR_ASSERT (psMemInfo && psDevPAddr) PVR_ASSERT((sDevVPageAddr.uiAddr & 0xFFF) == 0); psDeviceNode = ((BM_BUF*)psMemInfo->sMemBlk.hBuffer)->pMapping->pBMHeap->pBMContext->psDeviceNode; *psDevPAddr = psDeviceNode->pfnMMUGetPhysPageAddr(((BM_BUF*)psMemInfo->sMemBlk.hBuffer)->pMapping->pBMHeap->pMMUHeap, sDevVPageAddr); } MMU_CONTEXT* BM_GetMMUContext(IMG_HANDLE hDevMemHeap) { BM_HEAP *pBMHeap = (BM_HEAP*)hDevMemHeap; PVR_DPF((PVR_DBG_VERBOSE, "BM_GetMMUContext")); return pBMHeap->pBMContext->psMMUContext; } MMU_CONTEXT* BM_GetMMUContextFromMemContext(IMG_HANDLE hDevMemContext) { BM_CONTEXT *pBMContext = (BM_CONTEXT*)hDevMemContext; PVR_DPF ((PVR_DBG_VERBOSE, "BM_GetMMUContextFromMemContext")); return pBMContext->psMMUContext; } IMG_HANDLE BM_GetMMUHeap(IMG_HANDLE hDevMemHeap) { PVR_DPF((PVR_DBG_VERBOSE, "BM_GetMMUHeap")); return (IMG_HANDLE)((BM_HEAP*)hDevMemHeap)->pMMUHeap; } PVRSRV_DEVICE_NODE* BM_GetDeviceNode(IMG_HANDLE hDevMemContext) { PVR_DPF((PVR_DBG_VERBOSE, "BM_GetDeviceNode")); return ((BM_CONTEXT*)hDevMemContext)->psDeviceNode; } IMG_HANDLE BM_GetMappingHandle(PVRSRV_KERNEL_MEM_INFO *psMemInfo) { PVR_DPF((PVR_DBG_VERBOSE, "BM_GetMappingHandle")); return ((BM_BUF*)psMemInfo->sMemBlk.hBuffer)->pMapping->hOSMemHandle; }