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 ui32PageCount, ui32PageOffset; 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; ui32PageOffset = psSrcMemInfo->sDevVAddr.uiAddr & (ui32HostPageSize - 1); ui32PageCount = HOST_PAGEALIGN(psSrcMemInfo->ui32AllocSize + ui32PageOffset) / ui32HostPageSize; pvPageAlignedCPUVAddr = (IMG_VOID *)((IMG_UINTPTR_T)psSrcMemInfo->pvLinAddrKM - ui32PageOffset); if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, ui32PageCount*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(ui32PageOffset); for(i=0; i<ui32PageCount; 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->ui32AllocSize, ui32PageOffset, 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->ui32AllocSize = psSrcMemInfo->ui32AllocSize; 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; }
enum PVRSRV_ERROR PVRSRVMapDeviceMemoryKM( struct PVRSRV_PER_PROCESS_DATA *psPerProc, struct PVRSRV_KERNEL_MEM_INFO *psSrcMemInfo, void *hDstDevMemHeap, struct PVRSRV_KERNEL_MEM_INFO **ppsDstMemInfo) { enum PVRSRV_ERROR eError; u32 ui32PageOffset; u32 ui32HostPageSize = HOST_PAGESIZE(); int page_count; int i; struct IMG_SYS_PHYADDR *psSysPAddr = NULL; struct IMG_DEV_PHYADDR sDevPAddr; struct BM_BUF *psBuf; struct IMG_DEV_VIRTADDR sDevVAddr; struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = NULL; void *hBuffer; struct PVRSRV_MEMBLK *psMemBlock; IMG_BOOL bBMError; struct PVRSRV_DEVICE_NODE *psDeviceNode; void *pvPageAlignedCPUVAddr; struct RESMAN_MAP_DEVICE_MEM_DATA *psMapData = NULL; if (!psSrcMemInfo || !hDstDevMemHeap || !ppsDstMemInfo) { PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: invalid parameters"); return PVRSRV_ERROR_INVALID_PARAMS; } *ppsDstMemInfo = NULL; get_page_details((u32)psSrcMemInfo->pvLinAddrKM, psSrcMemInfo->ui32AllocSize, &ui32PageOffset, &page_count); pvPageAlignedCPUVAddr = (void *) ((u8 *) psSrcMemInfo->pvLinAddrKM - ui32PageOffset); if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, page_count * sizeof(struct IMG_SYS_PHYADDR), (void **) &psSysPAddr, NULL) != 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 - ui32PageOffset; for (i = 0; i < page_count; i++) { eError = BM_GetPhysPageAddr(psSrcMemInfo, sDevVAddr, &sDevPAddr); if (eError != PVRSRV_OK) { PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: " "Failed to retrieve page list from device"); goto ErrorExit; } psSysPAddr[i] = SysDevPAddrToSysPAddr(psDeviceNode->sDevId.eDeviceType, sDevPAddr); sDevVAddr.uiAddr += ui32HostPageSize; } if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA), (void **)&psMapData, NULL) != 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(struct PVRSRV_KERNEL_MEM_INFO), (void **)&psMemInfo, NULL) != 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)); psMemBlock = &(psMemInfo->sMemBlk); bBMError = BM_Wrap(hDstDevMemHeap, psSrcMemInfo->ui32AllocSize, ui32PageOffset, bm_is_continuous(psBuf), 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 = (void *) hBuffer; psMemBlock->psIntSysPAddr = psSysPAddr; psMemInfo->pvLinAddrKM = psSrcMemInfo->pvLinAddrKM; psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr; psMemInfo->ui32AllocSize = psSrcMemInfo->ui32AllocSize; psMemInfo->psKernelSyncInfo = psSrcMemInfo->psKernelSyncInfo; psMemInfo->pvSysBackupBuffer = NULL; psSrcMemInfo->ui32RefCount++; 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(struct IMG_SYS_PHYADDR), psSysPAddr, NULL); } if (psMemInfo) { OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo, NULL); } if (psMapData) { OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA), psMapData, NULL); } return eError; }