diff options
Diffstat (limited to 'drivers/gpu/pvr/services4/srvkm/common/devicemem.c')
| -rw-r--r-- | drivers/gpu/pvr/services4/srvkm/common/devicemem.c | 2580 | 
1 files changed, 2580 insertions, 0 deletions
| diff --git a/drivers/gpu/pvr/services4/srvkm/common/devicemem.c b/drivers/gpu/pvr/services4/srvkm/common/devicemem.c new file mode 100644 index 00000000000..872c0bab0ff --- /dev/null +++ b/drivers/gpu/pvr/services4/srvkm/common/devicemem.c @@ -0,0 +1,2580 @@ +/*************************************************************************/ /*! +@Title          Device addressable memory functions +@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description    Device addressable memory APIs +@License        Dual MIT/GPLv2 + +The contents of this file are subject to the MIT license as set out below. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Alternatively, the contents of this file may be used under the terms of +the GNU General Public License Version 2 ("GPL") in which case the provisions +of GPL are applicable instead of those above. + +If you wish to allow use of your version of this file only under the terms of +GPL, and not to allow others to use your version of this file under the terms +of the MIT license, indicate your decision by deleting the provisions above +and replace them with the notice and other provisions required by GPL as set +out in the file called "GPL-COPYING" included in this distribution. If you do +not delete the provisions above, a recipient may use your version of this file +under the terms of either the MIT license or GPL. + +This License is also included in this distribution in the file called +"MIT-COPYING". + +EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS +PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ /**************************************************************************/ + +#include <stddef.h> + +#include "services_headers.h" +#include "buffer_manager.h" +#include "pdump_km.h" +#include "pvr_bridge_km.h" +#include "osfunc.h" +#if defined(CONFIG_GCBV) +#include "gc_bvmapping.h" +#endif + +#if defined(SUPPORT_ION) +#include "ion.h" +#include "env_perproc.h" +#endif + +/* local function prototypes */ +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, +								   IMG_UINT32		ui32ChunkSize, +								   IMG_UINT32		ui32NumVirtChunks, +								   IMG_UINT32		ui32NumPhysChunks, +								   IMG_BOOL			*pabMapChunk, +								   PVRSRV_KERNEL_MEM_INFO **ppsMemInfo); + +/* local structures */ + +/* +	structure stored in resman to store references +	to the SRC and DST meminfo +*/ +typedef struct _RESMAN_MAP_DEVICE_MEM_DATA_ +{ +	/* the DST meminfo created by the map */ +	PVRSRV_KERNEL_MEM_INFO	*psMemInfo; +	/* SRC meminfo */ +	PVRSRV_KERNEL_MEM_INFO	*psSrcMemInfo; +} RESMAN_MAP_DEVICE_MEM_DATA; + +/* +	map device class resman memory storage structure +*/ +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; + +/*! +****************************************************************************** + + @Function	PVRSRVGetDeviceMemHeapsKM + + @Description + + Gets the device shared memory heaps + + @Input	   hDevCookie : + @Output   phDevMemContext : ptr to handle to memory context + @Output   psHeapInfo : ptr to array of heap info + + @Return   PVRSRV_DEVICE_NODE, valid devnode or IMG_NULL + +******************************************************************************/ +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; + +	/* Setup useful pointers */ +	ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount; +	psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap; + +	/* check we don't exceed the max number of heaps */ +	PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS); + +	/* retrieve heap information */ +	for(i=0; i<ui32HeapCount; i++) +	{ +		/* return information about the heap */ +		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; +		/* (XTileStride > 0) denotes a tiled heap */ +		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; +} + +/*! +****************************************************************************** + + @Function	PVRSRVCreateDeviceMemContextKM + + @Description + + Creates a device memory context + + @Input	   hDevCookie : + @Input	   psPerProc : Per-process data + @Output   phDevMemContext : ptr to handle to memory context + @Output   pui32ClientHeapCount : ptr to heap count + @Output   psHeapInfo : ptr to array of heap info + + @Return   PVRSRV_DEVICE_NODE, valid devnode or IMG_NULL + +******************************************************************************/ +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; + +	/* +		Setup useful pointers +	*/ +	ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount; +	psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap; + +	/* +		check we don't exceed the max number of heaps +	*/ +	PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS); + +	/* +		Create a memory context for the caller +	*/ +	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; +	} + +	/* create the per context heaps */ +	for(i=0; i<ui32HeapCount; i++) +	{ +		switch(psDeviceMemoryHeap[i].DevMemHeapType) +		{ +			case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: +			{ +				/* return information about the heap */ +				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; +				} + +				/* return information about the heap */ +				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; +			} +		} +	} + +	/* return shared_exported and per context heap information to the caller */ +	*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); +} + + + + +/*! +****************************************************************************** + + @Function	PVRSRVGetDeviceMemHeapInfoKM + + @Description + + gets heap info + + @Input	   hDevCookie : + @Input    hDevMemContext : ptr to handle to memory context + @Output   pui32ClientHeapCount : ptr to heap count + @Output   psHeapInfo : ptr to array of heap info + + @Return + +******************************************************************************/ +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; + +	/* +		Setup useful pointers +	*/ +	ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount; +	psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap; + +	/* +		check we don't exceed the max number of heaps +	*/ +	PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS); + +	/* create the per context heaps */ +	for(i=0; i<ui32HeapCount; i++) +	{ +		switch(psDeviceMemoryHeap[i].DevMemHeapType) +		{ +			case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: +			{ +				/* return information about the heap */ +				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; +				} + +				/* return information about the heap */ +				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; +			} +		} +	} + +	/* return shared_exported and per context heap information to the caller */ +	*pui32ClientHeapCount = ui32ClientHeapCount; + +	return PVRSRV_OK; +} + +static PVRSRV_ERROR UpdateDeviceMemoryPlaneOffsets(PVRSRV_KERNEL_MEM_INFO *psMemInfo) +{ +	if(psMemInfo->ui32Flags & PVRSRV_MEM_ION) +	{ + +		PVRSRV_MEMBLK *psMemBlock = &(psMemInfo->sMemBlk); +		IMG_UINT32 ui32AddressOffsets[PVRSRV_MAX_NUMBER_OF_MM_BUFFER_PLANES]; +		IMG_UINT32 ui32NumAddrOffsets = PVRSRV_MAX_NUMBER_OF_MM_BUFFER_PLANES; + +		IMG_INT32 retSize = OSGetMemMultiPlaneInfo(psMemBlock->hOSMemHandle, +				ui32AddressOffsets, &ui32NumAddrOffsets); + +		if((retSize > 0) && ui32NumAddrOffsets) +		{ +			int i; +			for(i = 0; i < PVRSRV_MAX_NUMBER_OF_MM_BUFFER_PLANES; i++) +			{ +				if(i < ui32NumAddrOffsets) +					psMemInfo->planeOffsets[i] = ui32AddressOffsets[i]; +				else +					psMemInfo->planeOffsets[i] = (IMG_INT32)-1; +			} +		} +	} + +	return PVRSRV_OK; + +} + +/*! +****************************************************************************** + + @Function	AllocDeviceMem + + @Description + + Allocates device memory + + @Input	   hDevCookie : + + @Input	   hDevMemHeap + + @Input	   ui32Flags : Some combination of PVRSRV_MEM_ flags + + @Input	   ui32Size :  Number of bytes to allocate + + @Input	   ui32Alignment : Alignment of allocation + + @Input    pvPrivData : Opaque private data passed through to allocator + + @Input    ui32PrivDataLength : Length of opaque private data + + @Output   **ppsMemInfo : On success, receives a pointer to the created MEM_INFO structure + + @Return   PVRSRV_ERROR : + +******************************************************************************/ +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, +								   IMG_UINT32		ui32ChunkSize, +								   IMG_UINT32		ui32NumVirtChunks, +								   IMG_UINT32		ui32NumPhysChunks, +								   IMG_BOOL			*pabMapChunk, +								   PVRSRV_KERNEL_MEM_INFO **ppsMemInfo) +{ + 	PVRSRV_KERNEL_MEM_INFO	*psMemInfo; +	BM_HANDLE 		hBuffer; +	/* Pointer to implementation details within the mem_info */ +	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); + +	/* ION and DYNAMIC re-mapping +	 * require the PAGEABLE FLAG set +	 */ +	if (ui32Flags & (PVRSRV_MEM_ION | +			PVRSRV_HAP_NO_GPU_VIRTUAL_ON_ALLOC)) +	{ +		ui32Flags |= PVRSRV_HAP_GPU_PAGEABLE; +	} + +	/* BM supplied Device Virtual Address with physical backing RAM */ +	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, +							ui32ChunkSize, +							ui32NumVirtChunks, +							ui32NumPhysChunks, +							pabMapChunk, +							&hBuffer); + +	if (!bBMError) +	{ +		PVR_DPF((PVR_DBG_ERROR,"AllocDeviceMem: BM_Alloc Failed")); +		OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_KERNEL_MEM_INFO), psMemInfo, IMG_NULL); +		/*not nulling pointer, out of scope*/ +		return PVRSRV_ERROR_OUT_OF_MEMORY; +	} + +	/* Fill in "Implementation dependant" section of mem info */ +	psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer); +	psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer); + +	/* Convert from BM_HANDLE to external IMG_HANDLE */ +	psMemBlock->hBuffer = (IMG_HANDLE)hBuffer; + +	/* Fill in the public fields of the MEM_INFO structure */ + +	psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer); + +	psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr; + +	if (ui32Flags & PVRSRV_MEM_SPARSE) +	{ +		psMemInfo->uAllocSize = ui32ChunkSize * ui32NumVirtChunks; +	} +	else +	{ +		psMemInfo->uAllocSize = ui32Size; +	} + +	/* Clear the Backup buffer pointer as we do not have one at this point. We only allocate this as we are going up/down */ +	psMemInfo->pvSysBackupBuffer = IMG_NULL; + +	/* Update the Multimedia plane offsets */ +	UpdateDeviceMemoryPlaneOffsets(psMemInfo); + +	/* +	 * Setup the output. +	 */ +	*ppsMemInfo = psMemInfo; + +	/* +	 * And I think we're done for now.... +	 */ +	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); +} + + +/*! +****************************************************************************** + + @Function	PVRSRVAllocSyncInfoKM + + @Description + + Allocates a sync info + + @Return   PVRSRV_ERROR : + +******************************************************************************/ +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; +	} + +	eError = OSAtomicAlloc(&psKernelSyncInfo->pvRefCount); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR,"PVRSRVAllocSyncInfoKM: Failed to allocate atomic")); +		OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_KERNEL_SYNC_INFO), psKernelSyncInfo, IMG_NULL); +		return PVRSRV_ERROR_OUT_OF_MEMORY; +	} +	 + +	/* Get the devnode from the devheap */ +	pBMContext = (BM_CONTEXT*)hDevMemContext; +	psDevMemoryInfo = &pBMContext->psDeviceNode->sDevMemoryInfo; + +	/* and choose a heap for the syncinfo */ +	hSyncDevMemHeap = psDevMemoryInfo->psDeviceMemoryHeap[psDevMemoryInfo->ui32SyncHeapID].hDevMemHeap; + +	/* +		Cache consistent flag would be unnecessary if the heap attributes were +		changed to specify it. +	*/ +	eError = AllocDeviceMem(hDevCookie, +							hSyncDevMemHeap, +							PVRSRV_MEM_CACHE_CONSISTENT, +							sizeof(PVRSRV_SYNC_DATA), +							sizeof(IMG_UINT32), +							IMG_NULL, +							0, +							0, 0, 0, IMG_NULL, /* Sparse mapping args, not required */ +							&psKernelSyncInfo->psSyncDataMemInfoKM); + +	if (eError != PVRSRV_OK) +	{ + +		PVR_DPF((PVR_DBG_ERROR,"PVRSRVAllocSyncInfoKM: Failed to alloc memory")); +		OSAtomicFree(psKernelSyncInfo->pvRefCount); +		OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_KERNEL_SYNC_INFO), psKernelSyncInfo, IMG_NULL); +		/*not nulling pointer, out of scope*/ +		return PVRSRV_ERROR_OUT_OF_MEMORY; +	} + +	/* init sync data */ +	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; +	psSyncData->ui64LastWrite = 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++; + +	/* syncinfo meminfo has no syncinfo! */ +	psKernelSyncInfo->psSyncDataMemInfoKM->psKernelSyncInfo = IMG_NULL; + +	OSAtomicInc(psKernelSyncInfo->pvRefCount); + +	/* return result */ +	*ppsKernelSyncInfo = psKernelSyncInfo; + +	return PVRSRV_OK; +} + +IMG_EXPORT +IMG_VOID PVRSRVAcquireSyncInfoKM(PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo) +{ +	OSAtomicInc(psKernelSyncInfo->pvRefCount); +} + +/*! +****************************************************************************** + + @Function	PVRSRVFreeSyncInfoKM + + @Description + + Frees a sync info + + @Return   PVRSRV_ERROR : + +******************************************************************************/ +IMG_EXPORT +IMG_VOID IMG_CALLCONV PVRSRVReleaseSyncInfoKM(PVRSRV_KERNEL_SYNC_INFO	*psKernelSyncInfo) +{ +	if (OSAtomicDecAndTest(psKernelSyncInfo->pvRefCount)) +	{ +		FreeDeviceMem(psKernelSyncInfo->psSyncDataMemInfoKM); +	 +		/* Catch anyone who is trying to access the freed structure */ +		psKernelSyncInfo->psSyncDataMemInfoKM = IMG_NULL; +		psKernelSyncInfo->psSyncData = IMG_NULL; +		OSAtomicFree(psKernelSyncInfo->pvRefCount); +		(IMG_VOID)OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_KERNEL_SYNC_INFO), psKernelSyncInfo, IMG_NULL); +		/*not nulling pointer, copy on stack*/ +	} +} + +/*! +****************************************************************************** + + @Function	freeExternal + + @Description + + Code for freeing meminfo elements that are specific to external types memory + + @Input	   psMemInfo : Kernel meminfo + + @Return   PVRSRV_ERROR : + +******************************************************************************/ + +static IMG_VOID freeExternal(PVRSRV_KERNEL_MEM_INFO *psMemInfo) +{ +	IMG_HANDLE hOSWrapMem = psMemInfo->sMemBlk.hOSWrapMem; + +	/* free the page addr array if req'd */ +	if(psMemInfo->sMemBlk.psIntSysPAddr) +	{ +		OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(IMG_SYS_PHYADDR), psMemInfo->sMemBlk.psIntSysPAddr, IMG_NULL); +		psMemInfo->sMemBlk.psIntSysPAddr = IMG_NULL; +	} + +	/* Mem type dependent stuff */ +	if (psMemInfo->memType == PVRSRV_MEMTYPE_WRAPPED) +	{ +		if(hOSWrapMem) +		{ +			OSReleasePhysPageAddr(hOSWrapMem); +		} +	} +#if defined(SUPPORT_ION) +	else if (psMemInfo->memType == PVRSRV_MEMTYPE_ION) +	{ +		if (hOSWrapMem) +		{ +			IonUnimportBufferAndReleasePhysAddr(hOSWrapMem); +		} +	} +#endif +} + +/*! +****************************************************************************** + + @Function	FreeMemCallBackCommon + + @Description + + Common code for freeing device mem (called for freeing, unwrapping and unmapping) + + @Input	   psMemInfo : Kernel meminfo + @Input	   ui32Param :  packet size + @Input	   uibFromAllocatorParam :  Are we being called by the original allocator? + + @Return   PVRSRV_ERROR : + +******************************************************************************/ +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); + +	/* decrement the refcount */ +	PVRSRVKernelMemInfoDecRef(psMemInfo); + +	/* check no other processes has this meminfo mapped */ +	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 + +			/* find the handle */ +			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; +			} + +			/* release the handle */ +			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; +			} +		} + +		switch(psMemInfo->memType) +		{ +			/* Fall through: Free only what we should for each memory type */ +			case PVRSRV_MEMTYPE_WRAPPED: +			case PVRSRV_MEMTYPE_ION: +				freeExternal(psMemInfo); +			case PVRSRV_MEMTYPE_DEVICE: +			case PVRSRV_MEMTYPE_DEVICECLASS: +				if (psMemInfo->psKernelSyncInfo) +				{ +					PVRSRVKernelSyncInfoDecRef(psMemInfo->psKernelSyncInfo, psMemInfo); +				} +				break; +			default: +				PVR_DPF((PVR_DBG_ERROR, "FreeMemCallBackCommon: Unknown memType")); +				eError = PVRSRV_ERROR_INVALID_MEMINFO; +		} +	} + +#if defined(CONFIG_GCBV) +	if (psMemInfo->ui32Flags & PVRSRV_MAP_GC_MMU) +		gc_bvunmap_meminfo(psMemInfo); +#endif + +	/* +	 * FreeDeviceMem2 will do the right thing, freeing +	 * the virtual memory info when the allocator calls +	 * but only releaseing the physical pages when everyone +	 * is done. +	 */ + +	if (eError == PVRSRV_OK) +	{ +		eError = FreeDeviceMem2(psMemInfo, eCallbackOrigin); +	} + +	return eError; +} + +/*! +****************************************************************************** + + @Function	FreeDeviceMemCallBack + + @Description + + ResMan call back to free device memory + + @Input	   pvParam : data packet + @Input	   ui32Param :  packet size + + @Return   PVRSRV_ERROR : + +******************************************************************************/ +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); +} + + +/*! +****************************************************************************** + + @Function	PVRSRVFreeDeviceMemKM + + @Description + + Frees memory allocated with PVRAllocDeviceMem, including the mem_info structure + + @Input	   psMemInfo : + + @Return   PVRSRV_ERROR  : + +******************************************************************************/ +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 +	{ +		/* PVRSRV_MEM_NO_RESMAN */ +		eError = FreeDeviceMemCallBack(psMemInfo, 0, CLEANUP_WITH_POLL); +	} + +	return eError; +} + + +/*! +****************************************************************************** + + @Function	PVRSRVRemapToDevKM + + @Description + + Remaps buffer to GPU virtual address space + + @Input    psMemInfo + + @Return   PVRSRV_ERROR : 0 means the memory is still unmapped - ERROR, + *                        bigger than 0 (mapping reference count) - success mapping + *                        smaller than 0 - PVRSRV error +******************************************************************************/ +IMG_EXPORT +IMG_INT32 IMG_CALLCONV PVRSRVRemapToDevKM(IMG_HANDLE	hDevCookie, +		PVRSRV_KERNEL_MEM_INFO *psMemInfo, IMG_DEV_VIRTADDR *psDevVAddr) +{ +	PVRSRV_MEMBLK *psMemBlock; +	IMG_INT32 result; + +	PVR_UNREFERENCED_PARAMETER(hDevCookie); + +	if (!psMemInfo) +	{ +		PVR_DPF((PVR_DBG_ERROR,"PVRSRVRemapToDevKM: invalid parameters")); +		return PVRSRV_ERROR_INVALID_PARAMS; +	} + +	psMemBlock = &(psMemInfo->sMemBlk); + +	result = BM_RemapToDev(psMemBlock->hBuffer); + +	if(result <= 0) +	{ +		PVR_DPF((PVR_DBG_ERROR,"PVRSRVRemapToDevKM: could not remap")); +	} + +	*psDevVAddr = psMemInfo->sDevVAddr = +					psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(psMemBlock->hBuffer); + +	UpdateDeviceMemoryPlaneOffsets(psMemInfo); + +	return result; +} + + +/*! +****************************************************************************** + + @Function	PVRSRVUnmapFromDevKM + + @Description + + Unmaps buffer from GPU virtual address space + + @Input    psMemInfo + + @Return   PVRSRV_ERROR : 0 means the memory is unmapped, + *                        bigger than 0 (mapping reference count) still mapped + *                        smaller than 0 - PVRSRV error +******************************************************************************/ +IMG_EXPORT +IMG_INT32 IMG_CALLCONV PVRSRVUnmapFromDevKM(IMG_HANDLE	hDevCookie, +		PVRSRV_KERNEL_MEM_INFO *psMemInfo) +{ +	PVRSRV_MEMBLK *psMemBlock; +	IMG_INT32 result; + +	PVR_UNREFERENCED_PARAMETER(hDevCookie); + +	if (!psMemInfo) +	{ +		PVR_DPF((PVR_DBG_ERROR,"PVRSRVUnmapFromDevKM: invalid parameters")); +		return PVRSRV_ERROR_INVALID_PARAMS; +	} + +	psMemBlock = &(psMemInfo->sMemBlk); + +	result = BM_UnmapFromDev(psMemBlock->hBuffer); +	/* 0 means the memory is unmapped, +	 * bigger than 0 (mapping ref count) still mapped +	 * smaller than 0 PVRSRV error +	*/ +	if(result < 0) +	{ +		PVR_DPF((PVR_DBG_ERROR,"PVRSRVUnmapFromDevKM: could not unmap")); +	} + +	psMemInfo->sDevVAddr = +					psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(psMemBlock->hBuffer); + +	return result; +} + + +/*! +****************************************************************************** + + @Function	PVRSRVAllocDeviceMemKM + + @Description + + Allocates device memory + + @Input	   hDevCookie : + @Input	   psPerProc : Per-process data + @Input	   hDevMemHeap + @Input	   ui32Flags : Some combination of PVRSRV_MEM_ flags + @Input	   ui32Size :  Number of bytes to allocate + @Input	   ui32Alignment : + @Output   **ppsMemInfo : On success, receives a pointer to the created MEM_INFO structure + + @Return   PVRSRV_ERROR : + +******************************************************************************/ +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, +												  IMG_UINT32				ui32ChunkSize, +												  IMG_UINT32				ui32NumVirtChunks, +												  IMG_UINT32				ui32NumPhysChunks, +												  IMG_BOOL					*pabMapChunk, +												  PVRSRV_KERNEL_MEM_INFO	**ppsMemInfo) +{ +	PVRSRV_KERNEL_MEM_INFO	*psMemInfo; +	PVRSRV_ERROR 			eError; +	BM_HEAP					*psBMHeap; +	IMG_HANDLE				hDevMemContext; + +	if (!hDevMemHeap || +		((ui32Size == 0) && ((ui32Flags & PVRSRV_MEM_SPARSE) == 0)) || +		(((ui32ChunkSize == 0) || (ui32NumVirtChunks == 0) || (ui32NumPhysChunks == 0) || +		(pabMapChunk == IMG_NULL )) && (ui32Flags & PVRSRV_MEM_SPARSE))) +	{ +		return PVRSRV_ERROR_INVALID_PARAMS; +	} + +	/* Sprase alloc input validation */ +	if (ui32Flags & PVRSRV_MEM_SPARSE) +	{ +		IMG_UINT32 i; +		IMG_UINT32 ui32Check = 0; + +		if (ui32NumVirtChunks < ui32NumPhysChunks) +		{ +			return PVRSRV_ERROR_INVALID_PARAMS; +		} + +		for (i=0;i<ui32NumVirtChunks;i++) +		{ +			if (pabMapChunk[i]) +			{ +				ui32Check++; +			} +		} +		if (ui32NumPhysChunks != ui32Check) +		{ +			return PVRSRV_ERROR_INVALID_PARAMS; +		} +	} + +	/* FIXME: At the moment we force CACHETYPE override allocations to +	 *        be multiples of PAGE_SIZE and page aligned. If the RA/BM +	 *        is fixed, this limitation can be removed. +	 * +	 * INTEGRATION_POINT: HOST_PAGESIZE() is not correct, should be device-specific. +	 */ +	if (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK) +	{ +		/* PRQA S 3415 1 */ /* order of evaluation is not important */ +		if (((ui32Size % HOST_PAGESIZE()) != 0) || +			((ui32Alignment % HOST_PAGESIZE()) != 0)) +		{ +			return PVRSRV_ERROR_INVALID_PARAMS; +		} +	} + +	eError = AllocDeviceMem(hDevCookie, +							hDevMemHeap, +							ui32Flags, +							ui32Size, +							ui32Alignment, +							pvPrivData, +							ui32PrivDataLength, +							ui32ChunkSize, +							ui32NumVirtChunks, +							ui32NumPhysChunks, +							pabMapChunk, +							&psMemInfo); + +	if (eError != PVRSRV_OK) +	{ +		return eError; +	} + +#if defined(CONFIG_GCBV) +	if (ui32Flags & PVRSRV_MAP_GC_MMU) +		gc_bvmap_meminfo(psMemInfo); +#endif + +	if (ui32Flags & PVRSRV_MEM_NO_SYNCOBJ) +	{ +		psMemInfo->psKernelSyncInfo = IMG_NULL; +	} +	else +	{ +		/* +			allocate a syncinfo but don't register with resman +			because the holding devicemem will handle the syncinfo +		*/ +		psBMHeap = (BM_HEAP*)hDevMemHeap; +		hDevMemContext = (IMG_HANDLE)psBMHeap->pBMContext; +		eError = PVRSRVAllocSyncInfoKM(hDevCookie, +									   hDevMemContext, +									   &psMemInfo->psKernelSyncInfo); +		if(eError != PVRSRV_OK) +		{ +			goto free_mainalloc; +		} +	} + +	/* +	 * Setup the output. +	 */ +	*ppsMemInfo = psMemInfo; + +	if (ui32Flags & PVRSRV_MEM_NO_RESMAN) +	{ +		psMemInfo->sMemBlk.hResItem = IMG_NULL; +	} +	else +	{ +		/* register with the resman */ +		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; +		} +	} + +	/* increment the refcount */ +	PVRSRVKernelMemInfoIncRef(psMemInfo); + +	psMemInfo->memType = PVRSRV_MEMTYPE_DEVICE; + +	/* +	 * And I think we're done for now.... +	 */ +	return (PVRSRV_OK); + +free_mainalloc: +	if (psMemInfo->psKernelSyncInfo) +	{ +		PVRSRVKernelSyncInfoDecRef(psMemInfo->psKernelSyncInfo, psMemInfo); +	} +	FreeDeviceMem(psMemInfo); + +	return eError; +} + +#if defined(SUPPORT_ION) +static PVRSRV_ERROR IonUnmapCallback(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); +} + +/*! +****************************************************************************** + + @Function	PVRSRVMapIonHandleKM + + @Description + + Map an ION buffer into the specified device memory context + + @Input	   psPerProc : PerProcess data + @Input    hDevCookie : Device node cookie + @Input    hDevMemContext : Device memory context cookie + @Input    hIon : Handle to ION buffer + @Input    ui32Flags : Mapping flags + @Input    ui32Size : Mapping size + @Output   ppsKernelMemInfo: Output kernel meminfo if successful + + @Return   PVRSRV_ERROR  : + +******************************************************************************/ +IMG_EXPORT +PVRSRV_ERROR PVRSRVMapIonHandleKM(PVRSRV_PER_PROCESS_DATA *psPerProc, +								  IMG_HANDLE hDevCookie, +								  IMG_HANDLE hDevMemContext, +								  IMG_HANDLE hIon, +								  IMG_UINT32 ui32Flags, +								  IMG_UINT32 ui32Size, +								  PVRSRV_KERNEL_MEM_INFO **ppsKernelMemInfo) +{ +	PVRSRV_ENV_PER_PROCESS_DATA *psPerProcEnv = PVRSRVProcessPrivateData(psPerProc); +	PVRSRV_DEVICE_NODE *psDeviceNode;  +	PVRSRV_KERNEL_MEM_INFO *psNewKernelMemInfo; +	DEVICE_MEMORY_INFO *psDevMemoryInfo; +	DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; +	IMG_SYS_PHYADDR *pasSysPhysAddr; +	PVRSRV_MEMBLK *psMemBlock; +	PVRSRV_ERROR eError; +	IMG_HANDLE hDevMemHeap = IMG_NULL; +	IMG_HANDLE hPriv; +	BM_HANDLE hBuffer; +	IMG_UINT32 ui32HeapCount; +	IMG_UINT32 ui32PageCount; +	IMG_UINT32 i; +	IMG_BOOL bAllocSync = (ui32Flags & PVRSRV_MEM_NO_SYNCOBJ)?IMG_FALSE:IMG_TRUE; + +	if ((hDevCookie == IMG_NULL) || (ui32Size == 0) +		 || (hDevMemContext == IMG_NULL) || (ppsKernelMemInfo == IMG_NULL)) +	{ +		PVR_DPF((PVR_DBG_ERROR, "%s: Invalid params", __FUNCTION__)); +		return PVRSRV_ERROR_INVALID_PARAMS; +	} + +	psDeviceNode = (PVRSRV_DEVICE_NODE *)hDevCookie; + +	if(OSAllocMem(PVRSRV_PAGEABLE_SELECT, +					sizeof(PVRSRV_KERNEL_MEM_INFO), +					(IMG_VOID **)&psNewKernelMemInfo, IMG_NULL, +					"Kernel Memory Info") != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR,"%s: Failed to alloc memory for block", __FUNCTION__)); +		return PVRSRV_ERROR_OUT_OF_MEMORY; +	} +	OSMemSet(psNewKernelMemInfo, 0, sizeof(PVRSRV_KERNEL_MEM_INFO)); + +	/* Choose the heap to map to */ +	ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount; +	psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo; +	psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;	 +	for(i=0; i<PVRSRV_MAX_CLIENT_HEAPS; i++) +	{ +		if(HEAP_IDX(psDeviceMemoryHeap[i].ui32HeapID) == psDevMemoryInfo->ui32IonHeapID) +		{ +			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, "%s: Failed to get ION heap", __FUNCTION__)); +		eError = PVRSRV_ERROR_FAILED_TO_RETRIEVE_HEAPINFO; +		goto exitFailedHeap; +	} + +	/* Import the ION buffer into our ion_client and DMA map it */ +	eError = IonImportBufferAndAquirePhysAddr(psPerProcEnv->psIONClient, +											  hIon, +											  &ui32PageCount, +											  &pasSysPhysAddr, +											  &psNewKernelMemInfo->pvLinAddrKM, +											  &hPriv); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR, "%s: Failed to get ion buffer/buffer phys addr", __FUNCTION__)); +		goto exitFailedHeap; +	} + +	/* Wrap the returned addresses into our memory context */ +	if (!BM_Wrap(hDevMemHeap, +				 ui32Size, +				 0, +				 IMG_FALSE, +				 pasSysPhysAddr, +				 IMG_NULL, +				 &ui32Flags,	/* This function clobbers our bits in ui32Flags */ +				 &hBuffer)) +	{ +		PVR_DPF((PVR_DBG_ERROR, "%s: Failed to wrap ion buffer", __FUNCTION__)); +		eError = PVRSRV_ERROR_OUT_OF_MEMORY; +		goto exitFailedWrap; +	} + +	/* Fill in "Implementation dependant" section of mem info */ +	psMemBlock = &psNewKernelMemInfo->sMemBlk; +	psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer); +	psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer); +	psMemBlock->hBuffer = (IMG_HANDLE) hBuffer; +	psMemBlock->hOSWrapMem = hPriv;			/* Saves creating a new element as we know hOSWrapMem will not be used */ +	psMemBlock->psIntSysPAddr = pasSysPhysAddr; + +	psNewKernelMemInfo->ui32Flags = ui32Flags; +	psNewKernelMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr; +	psNewKernelMemInfo->uAllocSize = ui32Size; +	psNewKernelMemInfo->memType = PVRSRV_MEMTYPE_ION; +	PVRSRVKernelMemInfoIncRef(psNewKernelMemInfo); + +	/* Clear the Backup buffer pointer as we do not have one at this point. We only allocate this as we are going up/down */ +	psNewKernelMemInfo->pvSysBackupBuffer = IMG_NULL; + +	if (!bAllocSync) +	{ +		psNewKernelMemInfo->psKernelSyncInfo = IMG_NULL; +	} +	else +	{ +		eError = PVRSRVAllocSyncInfoKM(hDevCookie, +									   hDevMemContext, +									   &psNewKernelMemInfo->psKernelSyncInfo); +		if(eError != PVRSRV_OK) +		{ +			goto exitFailedSync; +		} +	} + +	/* register with the resman */ +	psNewKernelMemInfo->sMemBlk.hResItem = ResManRegisterRes(psPerProc->hResManContext, +															 RESMAN_TYPE_DEVICEMEM_ION, +															 psNewKernelMemInfo, +															 0, +															 &IonUnmapCallback); +	if (psNewKernelMemInfo->sMemBlk.hResItem == IMG_NULL) +	{ +		eError = PVRSRV_ERROR_OUT_OF_MEMORY; +		goto exitFailedResman; +	} + +	psNewKernelMemInfo->memType = PVRSRV_MEMTYPE_ION; + +	*ppsKernelMemInfo = psNewKernelMemInfo; +	return PVRSRV_OK; + +exitFailedResman: +	if (psNewKernelMemInfo->psKernelSyncInfo) +	{ +		PVRSRVKernelSyncInfoDecRef(psNewKernelMemInfo->psKernelSyncInfo, psNewKernelMemInfo); +	} +exitFailedSync: +	BM_Free(hBuffer, ui32Flags); +exitFailedWrap: +	IonUnimportBufferAndReleasePhysAddr(hPriv); +	OSFreeMem(PVRSRV_PAGEABLE_SELECT, +			  sizeof(IMG_SYS_PHYADDR) * ui32PageCount, +			  pasSysPhysAddr, +			  IMG_NULL); +exitFailedHeap: +	OSFreeMem(PVRSRV_PAGEABLE_SELECT, +			  sizeof(PVRSRV_KERNEL_MEM_INFO), +			  psNewKernelMemInfo, +			  IMG_NULL); + +	return eError; +} + +/*! +****************************************************************************** + + @Function	PVRSRVUnmapIonHandleKM + + @Description + + Frees an ion buffer mapped with PVRSRVMapIonHandleKM, including the mem_info structure + + @Input	   psMemInfo : + + @Return   PVRSRV_ERROR  : + +******************************************************************************/ +IMG_EXPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVUnmapIonHandleKM(PVRSRV_KERNEL_MEM_INFO *psMemInfo) +{ +	if (!psMemInfo) +	{ +		return PVRSRV_ERROR_INVALID_PARAMS; +	} + +	return ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem, CLEANUP_WITH_POLL); +} +#endif	/* SUPPORT_ION */ + +/*! +****************************************************************************** + + @Function	PVRSRVDissociateDeviceMemKM + + @Description + + Dissociates memory from the process that allocates it.  Intended for + transfering the ownership of device memory from a particular process + to the kernel. + + @Input	   psMemInfo : + + @Return   PVRSRV_ERROR  : + +******************************************************************************/ +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; +} + + +/*! +****************************************************************************** + + @Function	PVRSRVGetFreeDeviceMemKM + + @Description + + Determines how much memory remains available in the system with the specified + capabilities. + + @Input	   ui32Flags : + + @Output   pui32Total : + + @Output   pui32Free : + + @Output   pui32LargestBlock : + + @Return   PVRSRV_ERROR  : + +******************************************************************************/ +IMG_EXPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVGetFreeDeviceMemKM(IMG_UINT32 ui32Flags, +												   IMG_SIZE_T *pui32Total, +												   IMG_SIZE_T *pui32Free, +												   IMG_SIZE_T *pui32LargestBlock) +{ +	/* TO BE IMPLEMENTED */ + +	PVR_UNREFERENCED_PARAMETER(ui32Flags); +	PVR_UNREFERENCED_PARAMETER(pui32Total); +	PVR_UNREFERENCED_PARAMETER(pui32Free); +	PVR_UNREFERENCED_PARAMETER(pui32LargestBlock); + +	return PVRSRV_OK; +} + + + + +/*! +****************************************************************************** +	@Function   PVRSRVUnwrapExtMemoryKM + +	@Description  On last unwrap of a given meminfo, unmaps physical pages from a +				wrapped allocation, and frees the associated device address space. +				Note: this can only unmap memory mapped by PVRSRVWrapExtMemory + +	@Input	    psMemInfo - mem info describing the wrapped allocation +	@Return     None +******************************************************************************/ +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); +} + + +/*! +****************************************************************************** +	@Function   UnwrapExtMemoryCallBack + +	@Description Resman callback to unwrap memory + +	@Input	    pvParam - opaque void ptr param +	@Input	    ui32Param - opaque unsigned long param +	@Return     PVRSRV_ERROR +******************************************************************************/ +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); +} + + +/*! +****************************************************************************** +	@Function   PVRSRVWrapExtMemoryKM + +	@Description  Allocates a Device Virtual Address in the shared mapping heap +				and maps physical pages into that allocation. Note, if the pages are +				already mapped into the heap, the existing allocation is returned. + +	@Input	    hDevCookie - Device cookie +	@Input	    psPerProc - Per-process data +	@Input	    hDevMemContext - device memory context +	@Input	    uByteSize - Size of allocation +	@Input	    uPageOffset - Offset into the first page of the memory to be wrapped +	@Input	    bPhysContig - whether the underlying memory is physically contiguous +	@Input	    psExtSysPAddr - The list of Device Physical page addresses +	@Input	    pvLinAddr - ptr to buffer to wrap +	@Output     ppsMemInfo - mem info describing the wrapped allocation +	@Return     None +******************************************************************************/ + +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) +	{ +		/* derive the page offset from the cpu ptr (in case it's not supplied) */ +		uPageOffset = (IMG_UINTPTR_T)pvLinAddr & (ui32HostPageSize - 1); + +		/* get the pagecount and the page aligned base ptr */ +		uPageCount = HOST_PAGEALIGN(uByteSize + uPageOffset) / ui32HostPageSize; +		pvPageAlignedCPUVAddr = (IMG_VOID *)((IMG_UINTPTR_T)pvLinAddr - uPageOffset); + +		/* allocate array of SysPAddr to hold page addresses */ +		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;//FIXME: need better error code +			goto ErrorExitPhase1; +		} + +		/* replace the supplied page address list */ +		psExtSysPAddr = psIntSysPAddr; + +		/* assume memory is not physically contiguous; +  		   we shouldn't trust what the user says here +  		*/ +		bPhysContig = IMG_FALSE; +	} + +	/* Choose the heap to map to */ +	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; +	} + +	/* Fill in "Implementation dependant" section of mem info */ +	psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer); +	psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer); +	psMemBlock->hOSWrapMem = hOSWrapMem; +	psMemBlock->psIntSysPAddr = psIntSysPAddr; + +	/* Convert from BM_HANDLE to external IMG_HANDLE */ +	psMemBlock->hBuffer = (IMG_HANDLE)hBuffer; + +	/* Fill in the public fields of the MEM_INFO structure */ +	psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer); +	psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr; +	psMemInfo->uAllocSize = uByteSize; + +	/* Clear the Backup buffer pointer as we do not have one at this point. +	   We only allocate this as we are going up/down +	 */ +	psMemInfo->pvSysBackupBuffer = IMG_NULL; + +	/* +		allocate a syncinfo but don't register with resman +		because the holding devicemem will handle the syncinfo +	*/ +	psBMHeap = (BM_HEAP*)hDevMemHeap; +	hDevMemContext = (IMG_HANDLE)psBMHeap->pBMContext; +	eError = PVRSRVAllocSyncInfoKM(hDevCookie, +									hDevMemContext, +									&psMemInfo->psKernelSyncInfo); +	if(eError != PVRSRV_OK) +	{ +		goto ErrorExitPhase4; +	} + +	/* increment the refcount */ +	PVRSRVKernelMemInfoIncRef(psMemInfo); + +	psMemInfo->memType = PVRSRV_MEMTYPE_WRAPPED; + +	/* Register Resource */ +	psMemInfo->sMemBlk.hResItem = ResManRegisterRes(psPerProc->hResManContext, +													RESMAN_TYPE_DEVICEMEM_WRAP, +													psMemInfo, +													0, +													&UnwrapExtMemoryCallBack); + +	/* return the meminfo */ +	*ppsMemInfo = psMemInfo; + +	return PVRSRV_OK; + +	/* error handling: */ + +ErrorExitPhase4: +	if(psMemInfo) +	{ +		FreeDeviceMem(psMemInfo); +		/* +			FreeDeviceMem will free the meminfo so set +			it to NULL to avoid double free below +		*/ +		psMemInfo = IMG_NULL; +	} + +ErrorExitPhase3: +	if(psMemInfo) +	{ +		OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_KERNEL_MEM_INFO), psMemInfo, IMG_NULL); +		/*not nulling pointer, out of scope*/ +	} + +ErrorExitPhase2: +	if(psIntSysPAddr) +	{ +		OSReleasePhysPageAddr(hOSWrapMem); +	} + +ErrorExitPhase1: +	if(psIntSysPAddr) +	{ +		OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, uPageCount * sizeof(IMG_SYS_PHYADDR), psIntSysPAddr, IMG_NULL); +		/*not nulling shared pointer, uninitialized to this point*/ +	} + +	return eError; +} + + +/*! +****************************************************************************** + + @Function	PVRSRVUnmapDeviceMemoryKM + + @Description + 		Unmaps an existing allocation previously mapped by PVRSRVMapDeviceMemory + + @Input    psMemInfo + + @Return   PVRSRV_ERROR : + +******************************************************************************/ +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); +} + + +/*! +****************************************************************************** +	@Function   UnmapDeviceMemoryCallBack + +	@Description Resman callback to unmap memory memory previously mapped +				from one allocation to another + +	@Input	    pvParam - opaque void ptr param +	@Input	    ui32Param - opaque unsigned long param +	@Return     PVRSRV_ERROR +******************************************************************************/ +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 ) +	{ +		PVRSRVKernelSyncInfoDecRef(psMapData->psMemInfo->psKernelSyncInfo, psMapData->psMemInfo); +	} + +	eError = FreeDeviceMem(psMapData->psMemInfo); +	if(eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR,"UnmapDeviceMemoryCallBack: Failed to free DST meminfo")); +		return eError; +	} + +	/* This will only free the src psMemInfo if we hold the last reference */ +	eError = FreeMemCallBackCommon(psMapData->psSrcMemInfo, 0, +								   PVRSRV_FREE_CALLBACK_ORIGIN_IMPORTER); + +	OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(RESMAN_MAP_DEVICE_MEM_DATA), psMapData, IMG_NULL); +	/*not nulling pointer, copy on stack*/ + +	return eError; +} + + +/*! +****************************************************************************** + + @Function	PVRSRVMapDeviceMemoryKM + + @Description + 		Maps an existing allocation to a specific device address space and heap + 		Note: it's valid to map from one physical device to another + + @Input	   psPerProc : Per-process data + @Input    psSrcMemInfo + @Input    hDstDevMemHeap + @Input    ppsDstMemInfo + + @Return   PVRSRV_ERROR : + +******************************************************************************/ +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; + +	/* check params */ +	if(!psSrcMemInfo || !hDstDevMemHeap || !ppsDstMemInfo) +	{ +		PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceMemoryKM: invalid parameters")); +		return PVRSRV_ERROR_INVALID_PARAMS; +	} + +	/* initialise the Dst Meminfo to NULL*/ +	*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); + +	/* +		allocate array of SysPAddr to hold SRC allocation page addresses +	*/ +	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; + +	/* get the device node */ +	psDeviceNode = psBuf->pMapping->pBMHeap->pBMContext->psDeviceNode; + +	/* build a list of physical page addresses */ +	sDevVAddr.uiAddr = psSrcMemInfo->sDevVAddr.uiAddr - IMG_CAST_TO_DEVVADDR_UINT(uPageOffset); +	for(i=0; i<uPageCount; i++) +	{ +		BM_GetPhysPageAddr(psSrcMemInfo, sDevVAddr, &sDevPAddr); + +		/* save the address */ +		psSysPAddr[i] = SysDevPAddrToSysPAddr (psDeviceNode->sDevId.eDeviceType, sDevPAddr); + +		/* advance the DevVaddr one page */ +		sDevVAddr.uiAddr += IMG_CAST_TO_DEVVADDR_UINT(ui32HostPageSize); +	} + +	/* allocate the resman map data */ +	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; +	} + +	/* Fill in "Implementation dependant" section of mem info */ +	psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer); +	psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer); + +	/* Convert from BM_HANDLE to external IMG_HANDLE */ +	psMemBlock->hBuffer = (IMG_HANDLE)hBuffer; + +	/* Store page list */ +	psMemBlock->psIntSysPAddr = psSysPAddr; + +	/* patch up the CPU VAddr into the meminfo */ +	psMemInfo->pvLinAddrKM = psSrcMemInfo->pvLinAddrKM; + +	/* Fill in the public fields of the MEM_INFO structure */ +	psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr; +	psMemInfo->uAllocSize = psSrcMemInfo->uAllocSize; +	psMemInfo->psKernelSyncInfo = psSrcMemInfo->psKernelSyncInfo; + +	/* reference the same ksi that the original meminfo referenced */ +	if(psMemInfo->psKernelSyncInfo) +	{ +		PVRSRVKernelSyncInfoIncRef(psMemInfo->psKernelSyncInfo, psMemInfo); +	} + +	/* Clear the Backup buffer pointer as we do not have one at this point. +	   We only allocate this as we are going up/down +	 */ +	psMemInfo->pvSysBackupBuffer = IMG_NULL; + +	/* increment our refcount */ +	PVRSRVKernelMemInfoIncRef(psMemInfo); + +	/* increment the src refcount */ +	PVRSRVKernelMemInfoIncRef(psSrcMemInfo); + +	/* Tell the buffer manager about the export */ +	BM_Export(psSrcMemInfo->sMemBlk.hBuffer); + +	psMemInfo->memType = PVRSRV_MEMTYPE_MAPPED; + +	/* setup the resman map data */ +	psMapData->psMemInfo = psMemInfo; +	psMapData->psSrcMemInfo = psSrcMemInfo; + +	/* Register Resource */ +	psMemInfo->sMemBlk.hResItem = ResManRegisterRes(psPerProc->hResManContext, +													RESMAN_TYPE_DEVICEMEM_MAPPING, +													psMapData, +													0, +													&UnmapDeviceMemoryCallBack); + +	*ppsDstMemInfo = psMemInfo; + +	return PVRSRV_OK; + +	/* error handling: */ + +ErrorExit: + +	if(psSysPAddr) +	{ +		/* Free the page address list */ +		OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(IMG_SYS_PHYADDR), psSysPAddr, IMG_NULL); +		/*not nulling shared pointer, holding structure could be not initialized*/ +	} + +	if(psMemInfo) +	{ +		/* Free the page address list */ +		OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_KERNEL_MEM_INFO), psMemInfo, IMG_NULL); +		/*not nulling shared pointer, holding structure could be not initialized*/ +	} + +	if(psMapData) +	{ +		/* Free the resman map data */ +		OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(RESMAN_MAP_DEVICE_MEM_DATA), psMapData, IMG_NULL); +		/*not nulling pointer, out of scope*/ +	} + +	return eError; +} + + +/*! +****************************************************************************** +	@Function   PVRSRVUnmapDeviceClassMemoryKM + +	@Description  unmaps physical pages from devices address space at a specified +				Device Virtual Address. +				Note: this can only unmap memory mapped by +				PVRSRVMapDeviceClassMemoryKM + +	@Input	    psMemInfo - mem info describing the device virtual address +									to unmap RAM from +	@Return     None +******************************************************************************/ +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); +} + + +/*! +****************************************************************************** +	@Function   UnmapDeviceClassMemoryCallBack + +	@Description Resman callback to unmap device class memory + +	@Input	    pvParam - opaque void ptr param +	@Input	    ui32Param - opaque unsigned long param +	@Return     PVRSRV_ERROR +******************************************************************************/ +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); +} + + +/*! +****************************************************************************** +	@Function   PVRSRVMapDeviceClassMemoryKM + +	@Description  maps physical pages for DeviceClass buffers into a devices +				address space at a specified and pre-allocated Device +				Virtual Address + +	@Input	    psPerProc - Per-process data +	@Input	    hDevMemContext - Device memory context +	@Input	    hDeviceClassBuffer - Device Class Buffer (Surface) handle +	@Input	    hDevMemContext - device memory context to which mapping +										is made +	@Output     ppsMemInfo - mem info describing the mapped memory +	@Output     phOSMapInfo - OS specific mapping information +	@Return     None +******************************************************************************/ +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; +	} + +	/* allocate resman storage structure */ +	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; + +	/* +		call into external driver to get info so we can map a meminfo +		Notes: +		It's expected that third party displays will only support +		physically contiguous display surfaces.  However, it's possible +		a given display may have an MMU and therefore support non-contig' +		display surfaces. + +		If surfaces are contiguous, ext driver should return: +		 - a CPU virtual address, or IMG_NULL where the surface is not mapped to CPU +		 - (optional) an OS Mapping handle for KM->UM surface mapping +		 - the size in bytes +		 - a single system physical address + +		If surfaces are non-contiguous, ext driver should return: +		 - a CPU virtual address +		 - (optional) an OS Mapping handle for KM->UM surface mapping +		 - the size in bytes (must be multiple of 4kB) +		 - a list of system physical addresses (at 4kB intervals) +	*/ +	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; +	} + +	/* Choose the heap to map to */ +	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; +	} + +	/* Only need lower 12 bits of the cpu addr - don't care what size a void* is */ +	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")); +		/*not nulling pointer, out of scope*/ +		eError = PVRSRV_ERROR_BAD_MAPPING; +		goto ErrorExitPhase2; +	} + +	/* Fill in "Implementation dependant" section of mem info */ +	psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer); +	psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer); + +	/* Convert from BM_HANDLE to external IMG_HANDLE */ +	psMemBlock->hBuffer = (IMG_HANDLE)hBuffer; + +	/* patch up the CPU VAddr into the meminfo - use the address from the BM, not the one from the deviceclass +	   api, to ensure user mode mapping is possible +	 */ +	psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer); + +	/* Fill in the public fields of the MEM_INFO structure */ +	psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr; +	psMemInfo->uAllocSize = uByteSize; +	psMemInfo->psKernelSyncInfo = psDeviceClassBuffer->psKernelSyncInfo; + +	PVR_ASSERT(psMemInfo->psKernelSyncInfo != IMG_NULL); +	if (psMemInfo->psKernelSyncInfo) +	{ +		PVRSRVKernelSyncInfoIncRef(psMemInfo->psKernelSyncInfo, psMemInfo); +	} + +	/* Clear the Backup buffer pointer as we do not have one at this point. +	   We only allocate this as we are going up/down +	 */ +	psMemInfo->pvSysBackupBuffer = IMG_NULL; + +	/* setup DCMapInfo */ +	psDCMapInfo->psMemInfo = psMemInfo; +	psDCMapInfo->psDeviceClassBuffer = psDeviceClassBuffer; + +#if defined(SUPPORT_MEMORY_TILING) +	psDCMapInfo->psDeviceNode = psDeviceNode; + +	if(psDCMapInfo->ui32TilingStride > 0) +	{ +		/* try to acquire a tiling range on this device */ +		eError = psDeviceNode->pfnAllocMemTilingRange(psDeviceNode, +														psMemInfo, +														psDCMapInfo->ui32TilingStride, +														&psDCMapInfo->ui32RangeIndex); +		if (eError != PVRSRV_OK) +		{ +			PVR_DPF((PVR_DBG_ERROR,"PVRSRVMapDeviceClassMemoryKM: AllocMemTilingRange failed")); +			goto ErrorExitPhase3; +		} +	} +#endif + +	/* Register Resource */ +	psMemInfo->sMemBlk.hResItem = ResManRegisterRes(psPerProc->hResManContext, +													RESMAN_TYPE_DEVICECLASSMEM_MAPPING, +													psDCMapInfo, +													0, +													&UnmapDeviceClassMemoryCallBack); + +	(psDeviceClassBuffer->ui32MemMapRefCount)++; +	PVRSRVKernelMemInfoIncRef(psMemInfo); + +	psMemInfo->memType = PVRSRV_MEMTYPE_DEVICECLASS; + +	/* return the meminfo */ +	*ppsMemInfo = psMemInfo; + +#if defined(SUPPORT_PDUMP_MULTI_PROCESS) +	/* If the 3PDD supplies a kernel virtual address, we can PDUMP it */ +	if(psMemInfo->pvLinAddrKM) +	{ +		/* FIXME: +		 *	Initialise the display surface here when it is mapped into Services. +		 *	Otherwise there is a risk that pdump toolchain will assign previously +		 *	used physical pages, leading to visual artefacts on the unrendered surface +		 *	(e.g. during LLS rendering). +		 * +		 *	A better method is to pdump the allocation from the DC driver, so the +		 *	BM_Wrap pdumps only the virtual memory which better represents the driver +		 *	behaviour.	 +		 */ +		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) +	{ +		if (psMemInfo->psKernelSyncInfo) +		{ +			PVRSRVKernelSyncInfoDecRef(psMemInfo->psKernelSyncInfo, psMemInfo); +		} + +		FreeDeviceMem(psMemInfo); +		/* +			FreeDeviceMem will free the meminfo so set +			it to NULL to avoid double free below +		*/ +		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; +} + + +/****************************************************************************** + End of file (devicemem.c) +******************************************************************************/ + |