diff options
Diffstat (limited to 'sgx/services4/srvkm')
98 files changed, 26106 insertions, 8759 deletions
diff --git a/sgx/services4/srvkm/bridged/bridged_pvr_bridge.c b/sgx/services4/srvkm/bridged/bridged_pvr_bridge.c index f3b4cb0..f933477 100644 --- a/sgx/services4/srvkm/bridged/bridged_pvr_bridge.c +++ b/sgx/services4/srvkm/bridged/bridged_pvr_bridge.c @@ -1,28 +1,46 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title PVR Common Bridge Module (kernel side) +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Receives calls from the user portion of services and + despatches them to functions in the kernel portion. +@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. + +*/ /**************************************************************************/ @@ -46,6 +64,7 @@ #include "perproc.h" #include "device.h" #include "buffer_manager.h" +#include "refcount.h" #include "pdump_km.h" #include "syscommon.h" @@ -70,6 +89,18 @@ #include "srvkm.h" +/* FIXME: we should include an OS specific header here to allow configuration of + * which functions should be excluded (like the shared srvclient bridge code) + * so that ports may choose to override certain things. */ + +/* For the purpose of maintainability, it is intended that this file should not + * contain large amounts of OS specific #ifdefs. Headers are fine, and perhaps + * a few one liners, but for anything more, please find a way to add e.g. + * an osfunc.c abstraction or override the entire function in question within + * env,*,pvr_bridge_k.c + */ + + PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY g_BridgeDispatchTable[BRIDGE_DISPATCH_TABLE_ENTRY_COUNT]; #if defined(DEBUG_BRIDGE_KM) @@ -147,7 +178,10 @@ PVRSRVAcquireDeviceDataBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* + * Handle is not allocated in batch mode, as there is no resource + * allocation to undo if the handle allocation fails. + */ psAcquireDevInfoOUT->eError = PVRSRVAllocHandle(psPerProc->psHandleBase, &psAcquireDevInfoOUT->hDevCookie, @@ -175,7 +209,10 @@ PVRSRVCreateDeviceMemContextBW(IMG_UINT32 ui32BridgeID, PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_CREATE_DEVMEMCONTEXT); - + /* + * We potentially need one handle for the device memory context, + * and one handle for each client heap. + */ NEW_HANDLE_BATCH_OR_ERROR(psCreateDevMemContextOUT->eError, psPerProc, PVRSRV_MAX_CLIENT_HEAPS + 1) psCreateDevMemContextOUT->eError = @@ -206,7 +243,11 @@ PVRSRVCreateDeviceMemContextBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* + * Only allocate a handle if the device memory context was created. + * If an existing context was returned, lookup the existing + * handle. + */ if(bCreated) { PVRSRVAllocHandleNR(psPerProc->psHandleBase, @@ -240,7 +281,13 @@ PVRSRVCreateDeviceMemContextBW(IMG_UINT32 ui32BridgeID, if(abSharedDeviceMemHeap[i]) #endif { - + /* + * Heaps shared by everybody. These heaps are not + * created as part of the device memory context + * creation, and exist for the lifetime of the + * driver, hence, we use shared handles for these + * heaps. + */ #if defined (SUPPORT_SID_INTERFACE) PVRSRVAllocHandleNR(psPerProc->psHandleBase, &hDevMemHeapExt, @@ -257,7 +304,12 @@ PVRSRVCreateDeviceMemContextBW(IMG_UINT32 ui32BridgeID, #if defined(PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE) else { - + /* + * Heaps belonging to this context. The handles for + * these are made subhandles of the memory context + * handle, so that they are automatically deallocated + * when the memory context handle is deallocated. + */ if(bCreated) { #if defined (SUPPORT_SID_INTERFACE) @@ -425,7 +477,13 @@ PVRSRVGetDeviceMemHeapInfoBW(IMG_UINT32 ui32BridgeID, if(abSharedDeviceMemHeap[i]) #endif { - + /* + * Heaps shared by everybody. These heaps are not + * created as part of the device memory context + * creation, and exist for the lifetime of the + * driver, hence, we use shared handles for these + * heaps. + */ #if defined (SUPPORT_SID_INTERFACE) PVRSRVAllocHandleNR(psPerProc->psHandleBase, &hDevMemHeapExt, @@ -442,7 +500,12 @@ PVRSRVGetDeviceMemHeapInfoBW(IMG_UINT32 ui32BridgeID, #if defined(PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE) else { - + /* + * Heaps belonging to this context. The handles for + * these are made subhandles of the memory context + * handle, so that they are automatically deallocated + * when the memory context handle is deallocated. + */ psGetDevMemHeapInfoOUT->eError = PVRSRVFindHandle(psPerProc->psHandleBase, &hDevMemHeapExt, @@ -475,6 +538,7 @@ PVRSRVGetDeviceMemHeapInfoBW(IMG_UINT32 ui32BridgeID, #if defined(OS_PVRSRV_ALLOC_DEVICE_MEM_BW) +/* customised version */ IMG_INT PVRSRVAllocDeviceMemBW(IMG_UINT32 ui32BridgeID, PVRSRV_BRIDGE_IN_ALLOCDEVICEMEM *psAllocDeviceMemIN, @@ -490,12 +554,32 @@ PVRSRVAllocDeviceMemBW(IMG_UINT32 ui32BridgeID, PVRSRV_KERNEL_MEM_INFO *psMemInfo; IMG_HANDLE hDevCookieInt; IMG_HANDLE hDevMemHeapInt; - PXProcShareDataNode pShareDataNode = NULL; + IMG_UINT32 ui32ShareIndex; + IMG_BOOL bUseShareMemWorkaround; + IMG_BOOL *pabMapChunk = IMG_NULL; PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_ALLOC_DEVICEMEM); NEW_HANDLE_BATCH_OR_ERROR(psAllocDeviceMemOUT->eError, psPerProc, 2) + /* Do same sanity checking */ + if (psAllocDeviceMemIN->ui32Attribs & PVRSRV_MEM_SPARSE) + { + if (psAllocDeviceMemIN->ui32NumPhysChunks > psAllocDeviceMemIN->ui32NumVirtChunks) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocDeviceMemBW: more physical chunks then virtual space")); + psAllocDeviceMemOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; + return 0; + } + + if (psAllocDeviceMemIN->pabMapChunk == IMG_NULL) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocDeviceMemBW: Called in sparse mapping mode but without MapChunk array")); + psAllocDeviceMemOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; + return 0; + } + } + psAllocDeviceMemOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, psAllocDeviceMemIN->hDevCookie, @@ -516,18 +600,74 @@ PVRSRVAllocDeviceMemBW(IMG_UINT32 ui32BridgeID, return 0; } - /* Start mutually exclusive region */ + /* Memory sharing workaround, version 2 */ - if((psAllocDeviceMemIN->ui32Attribs & PVRSRV_MEM_XPROC) != 0) + bUseShareMemWorkaround = ((psAllocDeviceMemIN->ui32Attribs & PVRSRV_MEM_XPROC) != 0) ? IMG_TRUE : IMG_FALSE; + ui32ShareIndex = 7654321; /* stops MSVC compiler warning */ + + if (bUseShareMemWorkaround) + { + /* allocate a shared-surface ID, prior to the call to AllocDeviceMem */ + /* We could plumb in an extra argument, but for now, we'll keep the + shared-surface ID as a piece of global state, and rely upon the + bridge mutex to make it safe for us */ + + psAllocDeviceMemOUT->eError = + BM_XProcWorkaroundFindNewBufferAndSetShareIndex(&ui32ShareIndex); + if(psAllocDeviceMemOUT->eError != PVRSRV_OK) + { + return 0; + } + } + + /* Check access to private data, if provided */ + if(psAllocDeviceMemIN->pvPrivData) + { + if(!OSAccessOK(PVR_VERIFY_READ, + psAllocDeviceMemIN->pvPrivData, + psAllocDeviceMemIN->ui32PrivDataLength)) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocDeviceMemBW: Access check failed for pvPrivData")); + return -EFAULT; + } + } + + if (psAllocDeviceMemIN->ui32Attribs & PVRSRV_MEM_SPARSE) { - pShareDataNode = BM_XProcAllocNewBuffer(); - if(pShareDataNode == NULL) + /* Check access to the sparse mapping table, if provided */ + if(!OSAccessOK(PVR_VERIFY_READ, + psAllocDeviceMemIN->pabMapChunk, + psAllocDeviceMemIN->ui32NumVirtChunks)) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocDeviceMemBW: Access check failed for pabMapChunk")); + return -EFAULT; + } + + psAllocDeviceMemOUT->eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(IMG_BOOL) * psAllocDeviceMemIN->ui32NumVirtChunks, + (IMG_VOID **) &pabMapChunk, + 0, + "MapChunk kernel copy"); + if (psAllocDeviceMemOUT->eError != PVRSRV_OK) + { + return 0; + } + + psAllocDeviceMemOUT->eError = OSCopyFromUser(psPerProc, + pabMapChunk, + psAllocDeviceMemIN->pabMapChunk, + sizeof(IMG_BOOL) * psAllocDeviceMemIN->ui32NumVirtChunks); + if (psAllocDeviceMemOUT->eError != PVRSRV_OK) { - psAllocDeviceMemOUT->eError = PVRSRV_ERROR_OUT_OF_MEMORY; + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(IMG_BOOL) * psAllocDeviceMemIN->ui32NumVirtChunks, + pabMapChunk, + 0); return 0; } } + psAllocDeviceMemOUT->eError = PVRSRVAllocDeviceMemKM(hDevCookieInt, psPerProc, @@ -535,26 +675,31 @@ PVRSRVAllocDeviceMemBW(IMG_UINT32 ui32BridgeID, psAllocDeviceMemIN->ui32Attribs, psAllocDeviceMemIN->ui32Size, psAllocDeviceMemIN->ui32Alignment, + psAllocDeviceMemIN->pvPrivData, + psAllocDeviceMemIN->ui32PrivDataLength, + psAllocDeviceMemIN->ui32ChunkSize, + psAllocDeviceMemIN->ui32NumVirtChunks, + psAllocDeviceMemIN->ui32NumPhysChunks, + pabMapChunk, &psMemInfo, - "" ); + "" /*FIXME: add something meaningful*/); - if (pShareDataNode) + if (bUseShareMemWorkaround) { - IMG_BOOL freeIfNotUsed = (psAllocDeviceMemOUT->eError == PVRSRV_OK) ? IMG_FALSE : IMG_TRUE; - BM_XProcFinishShareIndex(pShareDataNode, freeIfNotUsed); + PVR_ASSERT(ui32ShareIndex != 7654321); + BM_XProcWorkaroundUnsetShareIndex(ui32ShareIndex); } - /* End mutually exclusive region */ - if(psAllocDeviceMemOUT->eError != PVRSRV_OK) { return 0; } - if (pShareDataNode) + psMemInfo->sShareMemWorkaround.bInUse = bUseShareMemWorkaround; + if (bUseShareMemWorkaround) { - psMemInfo->sShareMemWorkaround.bInUse = IMG_TRUE; - psMemInfo->sShareMemWorkaround.pShareDataNode = pShareDataNode; + PVR_ASSERT(ui32ShareIndex != 7654321); + psMemInfo->sShareMemWorkaround.ui32ShareIndex = ui32ShareIndex; psMemInfo->sShareMemWorkaround.hDevCookieInt = hDevCookieInt; psMemInfo->sShareMemWorkaround.ui32OrigReqAttribs = psAllocDeviceMemIN->ui32Attribs; psMemInfo->sShareMemWorkaround.ui32OrigReqSize = (IMG_UINT32)psAllocDeviceMemIN->ui32Size; @@ -577,7 +722,7 @@ PVRSRVAllocDeviceMemBW(IMG_UINT32 ui32BridgeID, psAllocDeviceMemOUT->sClientMemInfo.ui32Flags = psMemInfo->ui32Flags; psAllocDeviceMemOUT->sClientMemInfo.uAllocSize = psMemInfo->uAllocSize; #if defined (SUPPORT_SID_INTERFACE) - + /* see below */ #else psAllocDeviceMemOUT->sClientMemInfo.hMappingInfo = psMemInfo->sMemBlk.hOSMemHandle; #endif @@ -608,7 +753,7 @@ PVRSRVAllocDeviceMemBW(IMG_UINT32 ui32BridgeID, if(psAllocDeviceMemIN->ui32Attribs & PVRSRV_MEM_NO_SYNCOBJ) { - + /* signal no syncinfo */ OSMemSet(&psAllocDeviceMemOUT->sClientSyncInfo, 0, sizeof (PVRSRV_CLIENT_SYNC_INFO)); @@ -616,7 +761,7 @@ PVRSRVAllocDeviceMemBW(IMG_UINT32 ui32BridgeID, } else { - + /* and setup the sync info */ #if !defined(PVRSRV_DISABLE_UM_SYNCOBJ_MAPPINGS) psAllocDeviceMemOUT->sClientSyncInfo.psSyncData = @@ -625,6 +770,8 @@ PVRSRVAllocDeviceMemBW(IMG_UINT32 ui32BridgeID, psMemInfo->psKernelSyncInfo->sWriteOpsCompleteDevVAddr; psAllocDeviceMemOUT->sClientSyncInfo.sReadOpsCompleteDevVAddr = psMemInfo->psKernelSyncInfo->sReadOpsCompleteDevVAddr; + psAllocDeviceMemOUT->sClientSyncInfo.sReadOps2CompleteDevVAddr = + psMemInfo->psKernelSyncInfo->sReadOps2CompleteDevVAddr; #if defined (SUPPORT_SID_INTERFACE) if (psMemInfo->psKernelSyncInfo->psSyncDataMemInfoKM->sMemBlk.hOSMemHandle != IMG_NULL) @@ -655,7 +802,6 @@ PVRSRVAllocDeviceMemBW(IMG_UINT32 ui32BridgeID, psAllocDeviceMemOUT->sClientMemInfo.psClientSyncInfo = &psAllocDeviceMemOUT->sClientSyncInfo; - } COMMIT_HANDLE_BATCH_OR_ERROR(psAllocDeviceMemOUT->eError, psPerProc) @@ -663,7 +809,7 @@ PVRSRVAllocDeviceMemBW(IMG_UINT32 ui32BridgeID, return 0; } -#endif +#endif /* OS_PVRSRV_ALLOC_DEVICE_MEM_BW */ static IMG_INT PVRSRVFreeDeviceMemBW(IMG_UINT32 ui32BridgeID, @@ -674,7 +820,6 @@ PVRSRVFreeDeviceMemBW(IMG_UINT32 ui32BridgeID, IMG_HANDLE hDevCookieInt; IMG_VOID *pvKernelMemInfo; - PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_FREE_DEVICEMEM); psRetOUT->eError = @@ -841,7 +986,7 @@ PVRSRVExportDeviceMemBW(IMG_UINT32 ui32BridgeID, ui32BridgeID == PVRSRV_GET_BRIDGE_ID(PVRSRV_BRIDGE_EXPORT_DEVICEMEM_2)); PVR_UNREFERENCED_PARAMETER(ui32BridgeID); - + /* find the device cookie */ psExportDeviceMemOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, @@ -854,7 +999,7 @@ PVRSRVExportDeviceMemBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* find the kernel meminfo from the process handle list */ psExportDeviceMemOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, (IMG_PVOID *)&psKernelMemInfo, @@ -871,7 +1016,7 @@ PVRSRVExportDeviceMemBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* see if it's already exported */ psExportDeviceMemOUT->eError = PVRSRVFindHandle(KERNEL_HANDLE_BASE, &psExportDeviceMemOUT->hMemInfo, @@ -879,12 +1024,12 @@ PVRSRVExportDeviceMemBW(IMG_UINT32 ui32BridgeID, PVRSRV_HANDLE_TYPE_MEM_INFO); if(psExportDeviceMemOUT->eError == PVRSRV_OK) { - + /* it's already exported */ PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVExportDeviceMemBW: allocation is already exported")); return 0; } - + /* export the allocation */ psExportDeviceMemOUT->eError = PVRSRVAllocHandle(KERNEL_HANDLE_BASE, &psExportDeviceMemOUT->hMemInfo, psKernelMemInfo, @@ -896,7 +1041,7 @@ PVRSRVExportDeviceMemBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* mark the meminfo as 'exported' */ psKernelMemInfo->ui32Flags |= PVRSRV_MEM_EXPORTED; return 0; @@ -919,7 +1064,7 @@ PVRSRVMapDeviceMemoryBW(IMG_UINT32 ui32BridgeID, NEW_HANDLE_BATCH_OR_ERROR(psMapDevMemOUT->eError, psPerProc, 2) - + /* lookup srcmeminfo handle */ psMapDevMemOUT->eError = PVRSRVLookupHandle(KERNEL_HANDLE_BASE, (IMG_VOID**)&psSrcKernelMemInfo, psMapDevMemIN->hKernelMemInfo, @@ -929,7 +1074,7 @@ PVRSRVMapDeviceMemoryBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* lookup dev mem heap handle */ psMapDevMemOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDstDevMemHeap, psMapDevMemIN->hDstDevMemHeap, @@ -939,21 +1084,21 @@ PVRSRVMapDeviceMemoryBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* check for workaround */ if (psSrcKernelMemInfo->sShareMemWorkaround.bInUse) { PVR_DPF((PVR_DBG_MESSAGE, "using the mem wrap workaround.")); - - - - - - - - /* Start mutually exclusive region */ - - psMapDevMemOUT->eError = BM_XProcSetShareIndex(psSrcKernelMemInfo->sShareMemWorkaround.pShareDataNode); + /* Ensure we get the same ID for this allocation, such that it + inherits the same physical block. Rather than add a lot of + plumbing to several APIs, we call into buffer manager directly + to set "global" state. This works only if we make + this allocation while holding the bridge mutex and don't + make any other allocations (because the state persists and + would affect other device memory allocations too). It is + important that we bracket the PVRSRVAllocDeviceMemKM() call + with this Set/Unset pair. */ + psMapDevMemOUT->eError = BM_XProcWorkaroundSetShareIndex(psSrcKernelMemInfo->sShareMemWorkaround.ui32ShareIndex); if(psMapDevMemOUT->eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryBW(): failed to recycle shared buffer")); @@ -967,28 +1112,32 @@ PVRSRVMapDeviceMemoryBW(IMG_UINT32 ui32BridgeID, psSrcKernelMemInfo->sShareMemWorkaround.ui32OrigReqAttribs | PVRSRV_MEM_NO_SYNCOBJ, psSrcKernelMemInfo->sShareMemWorkaround.ui32OrigReqSize, psSrcKernelMemInfo->sShareMemWorkaround.ui32OrigReqAlignment, + IMG_NULL, + 0, + /* FIXME: Do we need to be able to export sparse memory? */ + 0,0,0,IMG_NULL, /* No sparse mapping data */ &psDstKernelMemInfo, - "" ); - - - BM_XProcFinishShareIndex(psSrcKernelMemInfo->sShareMemWorkaround.pShareDataNode, IMG_FALSE); + "" /*FIXME: add something meaningful*/); + /* counterpart of the above "SetShareIndex". NB: this must be + done in both the success and failure paths of the + AllocDeviceMemKM() call */ + BM_XProcWorkaroundUnsetShareIndex(psSrcKernelMemInfo->sShareMemWorkaround.ui32ShareIndex); if(psMapDevMemOUT->eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, "lakjgfgewjlrgebhe")); + PVR_DPF((PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryBW: Failed to create allocation for cross-process memory map")); return 0; } - /* End mutually exclusive region */ if(psSrcKernelMemInfo->psKernelSyncInfo) { - psSrcKernelMemInfo->psKernelSyncInfo->ui32RefCount++; + PVRSRVKernelSyncInfoIncRef(psSrcKernelMemInfo->psKernelSyncInfo, psSrcKernelMemInfo); } psDstKernelMemInfo->psKernelSyncInfo = psSrcKernelMemInfo->psKernelSyncInfo; } else { - + /* map the meminfo to the target heap and memory context */ psMapDevMemOUT->eError = PVRSRVMapDeviceMemoryKM(psPerProc, psSrcKernelMemInfo, hDstDevMemHeap, @@ -999,7 +1148,7 @@ PVRSRVMapDeviceMemoryBW(IMG_UINT32 ui32BridgeID, } } - + /* copy the workaround info */ psDstKernelMemInfo->sShareMemWorkaround = psSrcKernelMemInfo->sShareMemWorkaround; OSMemSet(&psMapDevMemOUT->sDstClientMemInfo, @@ -1017,12 +1166,12 @@ PVRSRVMapDeviceMemoryBW(IMG_UINT32 ui32BridgeID, psMapDevMemOUT->sDstClientMemInfo.ui32Flags = psDstKernelMemInfo->ui32Flags; psMapDevMemOUT->sDstClientMemInfo.uAllocSize = psDstKernelMemInfo->uAllocSize; #if defined (SUPPORT_SID_INTERFACE) - + /* see below */ #else psMapDevMemOUT->sDstClientMemInfo.hMappingInfo = psDstKernelMemInfo->sMemBlk.hOSMemHandle; #endif - + /* allocate handle to the DST kernel meminfo */ PVRSRVAllocHandleNR(psPerProc->psHandleBase, &psMapDevMemOUT->sDstClientMemInfo.hKernelMemInfo, psDstKernelMemInfo, @@ -1031,7 +1180,7 @@ PVRSRVMapDeviceMemoryBW(IMG_UINT32 ui32BridgeID, psMapDevMemOUT->sDstClientSyncInfo.hKernelSyncInfo = IMG_NULL; #if defined (SUPPORT_SID_INTERFACE) - + /* alloc subhandle for the mapping info */ if (psDstKernelMemInfo->sMemBlk.hOSMemHandle != IMG_NULL) { PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, @@ -1047,7 +1196,7 @@ PVRSRVMapDeviceMemoryBW(IMG_UINT32 ui32BridgeID, } #endif - + /* and setup the sync info */ if(psDstKernelMemInfo->psKernelSyncInfo) { #if !defined(PVRSRV_DISABLE_UM_SYNCOBJ_MAPPINGS) @@ -1057,9 +1206,11 @@ PVRSRVMapDeviceMemoryBW(IMG_UINT32 ui32BridgeID, psDstKernelMemInfo->psKernelSyncInfo->sWriteOpsCompleteDevVAddr; psMapDevMemOUT->sDstClientSyncInfo.sReadOpsCompleteDevVAddr = psDstKernelMemInfo->psKernelSyncInfo->sReadOpsCompleteDevVAddr; + psMapDevMemOUT->sDstClientSyncInfo.sReadOps2CompleteDevVAddr = + psDstKernelMemInfo->psKernelSyncInfo->sReadOps2CompleteDevVAddr; #if defined (SUPPORT_SID_INTERFACE) - + /* alloc subhandle for the mapping info */ if (psDstKernelMemInfo->psKernelSyncInfo->psSyncDataMemInfoKM->sMemBlk.hOSMemHandle != IMG_NULL) { PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, @@ -1080,7 +1231,11 @@ PVRSRVMapDeviceMemoryBW(IMG_UINT32 ui32BridgeID, #endif psMapDevMemOUT->sDstClientMemInfo.psClientSyncInfo = &psMapDevMemOUT->sDstClientSyncInfo; - + /* + * The sync info is associated with the device buffer, + * and not allocated here. It isn't exported when created, + * hence the handle allocation rather than a lookup. + */ PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, &psMapDevMemOUT->sDstClientSyncInfo.hKernelSyncInfo, psDstKernelMemInfo->psKernelSyncInfo, @@ -1145,7 +1300,7 @@ PVRSRVUnmapDeviceMemoryBW(IMG_UINT32 ui32BridgeID, } else { - psRetOUT->eError = PVRSRVUnmapDeviceMemoryKM(psKernelMemInfo); + psRetOUT->eError = PVRSRVUnmapDeviceMemoryKM(psKernelMemInfo, psPerProc); if(psRetOUT->eError != PVRSRV_OK) { return 0; @@ -1297,7 +1452,11 @@ PVRSRVMapDeviceClassMemoryBW(IMG_UINT32 ui32BridgeID, NEW_HANDLE_BATCH_OR_ERROR(psMapDevClassMemOUT->eError, psPerProc, 2) - + /* + * The buffer to be mapped can belong to a 3rd party display or + * buffer driver, and we don't know which type we have at this + * point. + */ psMapDevClassMemOUT->eError = PVRSRVLookupHandleAnyType(psPerProc->psHandleBase, &hDeviceClassBufferInt, @@ -1309,7 +1468,7 @@ PVRSRVMapDeviceClassMemoryBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* get the device memory context */ psMapDevClassMemOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevMemContextInt, @@ -1321,7 +1480,7 @@ PVRSRVMapDeviceClassMemoryBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* Having looked up the handle, now check its type */ switch(eHandleType) { #if defined(PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE) @@ -1388,7 +1547,7 @@ PVRSRVMapDeviceClassMemoryBW(IMG_UINT32 ui32BridgeID, psMapDevClassMemOUT->sClientSyncInfo.hKernelSyncInfo = IMG_NULL; - + /* and setup the sync info */ if(psMemInfo->psKernelSyncInfo) { #if !defined(PVRSRV_DISABLE_UM_SYNCOBJ_MAPPINGS) @@ -1398,6 +1557,8 @@ PVRSRVMapDeviceClassMemoryBW(IMG_UINT32 ui32BridgeID, psMemInfo->psKernelSyncInfo->sWriteOpsCompleteDevVAddr; psMapDevClassMemOUT->sClientSyncInfo.sReadOpsCompleteDevVAddr = psMemInfo->psKernelSyncInfo->sReadOpsCompleteDevVAddr; + psMapDevClassMemOUT->sClientSyncInfo.sReadOps2CompleteDevVAddr = + psMemInfo->psKernelSyncInfo->sReadOps2CompleteDevVAddr; #if defined (SUPPORT_SID_INTERFACE) if (psMemInfo->psKernelSyncInfo->psSyncDataMemInfoKM->sMemBlk.hOSMemHandle != 0) @@ -1420,7 +1581,12 @@ PVRSRVMapDeviceClassMemoryBW(IMG_UINT32 ui32BridgeID, #endif psMapDevClassMemOUT->sClientMemInfo.psClientSyncInfo = &psMapDevClassMemOUT->sClientSyncInfo; - + /* + * The sync info is associated with the device buffer, + * and not allocated here. It isn't exported when + * created, hence the handle allocation rather than a + * lookup. + */ PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, &psMapDevClassMemOUT->sClientSyncInfo.hKernelSyncInfo, psMemInfo->psKernelSyncInfo, @@ -1483,7 +1649,7 @@ PVRSRVWrapExtMemoryBW(IMG_UINT32 ui32BridgeID, PVRSRV_BRIDGE_IN_WRAP_EXT_MEMORY *psWrapExtMemIN, PVRSRV_BRIDGE_OUT_WRAP_EXT_MEMORY *psWrapExtMemOUT, PVRSRV_PER_PROCESS_DATA *psPerProc); -#else +#else /* OS_PVRSRV_WRAP_EXT_MEM_BW */ static IMG_INT PVRSRVWrapExtMemoryBW(IMG_UINT32 ui32BridgeID, PVRSRV_BRIDGE_IN_WRAP_EXT_MEMORY *psWrapExtMemIN, @@ -1500,7 +1666,10 @@ PVRSRVWrapExtMemoryBW(IMG_UINT32 ui32BridgeID, NEW_HANDLE_BATCH_OR_ERROR(psWrapExtMemOUT->eError, psPerProc, 2) - + /* + * FIXME: This needs reworking - don't use the user supplied page + * table list, get the list from the OS. + */ psWrapExtMemOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevCookieInt, psWrapExtMemIN->hDevCookie, @@ -1510,7 +1679,7 @@ PVRSRVWrapExtMemoryBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* get the device memory context */ psWrapExtMemOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevMemContextInt, psWrapExtMemIN->hDevMemContext, @@ -1539,7 +1708,7 @@ PVRSRVWrapExtMemoryBW(IMG_UINT32 ui32BridgeID, ui32PageTableSize) != PVRSRV_OK) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32PageTableSize, (IMG_VOID *)psSysPAddr, 0); - + /*not nulling pointer, out of scope*/ return -EFAULT; } } @@ -1561,7 +1730,7 @@ PVRSRVWrapExtMemoryBW(IMG_UINT32 ui32BridgeID, OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32PageTableSize, (IMG_VOID *)psSysPAddr, 0); - + /*not nulling pointer, out of scope*/ } if(psWrapExtMemOUT->eError != PVRSRV_OK) @@ -1572,12 +1741,13 @@ PVRSRVWrapExtMemoryBW(IMG_UINT32 ui32BridgeID, psWrapExtMemOUT->sClientMemInfo.pvLinAddrKM = psMemInfo->pvLinAddrKM; - + /* setup the mem info */ psWrapExtMemOUT->sClientMemInfo.pvLinAddr = 0; psWrapExtMemOUT->sClientMemInfo.sDevVAddr = psMemInfo->sDevVAddr; psWrapExtMemOUT->sClientMemInfo.ui32Flags = psMemInfo->ui32Flags; psWrapExtMemOUT->sClientMemInfo.uAllocSize = psMemInfo->uAllocSize; #if defined (SUPPORT_SID_INTERFACE) +/* see below */ #else psWrapExtMemOUT->sClientMemInfo.hMappingInfo = psMemInfo->sMemBlk.hOSMemHandle; #endif @@ -1589,7 +1759,7 @@ PVRSRVWrapExtMemoryBW(IMG_UINT32 ui32BridgeID, PVRSRV_HANDLE_ALLOC_FLAG_NONE); #if defined (SUPPORT_SID_INTERFACE) - + /* alloc subhandle for the mapping info */ if (psMemInfo->sMemBlk.hOSMemHandle != IMG_NULL) { PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, @@ -1605,7 +1775,7 @@ PVRSRVWrapExtMemoryBW(IMG_UINT32 ui32BridgeID, } #endif - + /* setup the sync info */ #if !defined(PVRSRV_DISABLE_UM_SYNCOBJ_MAPPINGS) psWrapExtMemOUT->sClientSyncInfo.psSyncData = psMemInfo->psKernelSyncInfo->psSyncData; @@ -1613,9 +1783,11 @@ PVRSRVWrapExtMemoryBW(IMG_UINT32 ui32BridgeID, psMemInfo->psKernelSyncInfo->sWriteOpsCompleteDevVAddr; psWrapExtMemOUT->sClientSyncInfo.sReadOpsCompleteDevVAddr = psMemInfo->psKernelSyncInfo->sReadOpsCompleteDevVAddr; + psWrapExtMemOUT->sClientSyncInfo.sReadOps2CompleteDevVAddr = + psMemInfo->psKernelSyncInfo->sReadOps2CompleteDevVAddr; #if defined (SUPPORT_SID_INTERFACE) - + /* alloc subhandle for the mapping info */ if (psMemInfo->psKernelSyncInfo->psSyncDataMemInfoKM->sMemBlk.hOSMemHandle != IMG_NULL) { PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, @@ -1648,7 +1820,7 @@ PVRSRVWrapExtMemoryBW(IMG_UINT32 ui32BridgeID, return 0; } -#endif +#endif /* OS_PVRSRV_WRAP_EXT_MEM_BW */ static IMG_INT PVRSRVUnwrapExtMemoryBW(IMG_UINT32 ui32BridgeID, @@ -1685,6 +1857,169 @@ PVRSRVUnwrapExtMemoryBW(IMG_UINT32 ui32BridgeID, return 0; } +#if defined(SUPPORT_ION) +static IMG_INT +PVRSRVMapIonHandleBW(IMG_UINT32 ui32BridgeID, + PVRSRV_BRIDGE_IN_MAP_ION_HANDLE *psMapIonIN, + PVRSRV_BRIDGE_OUT_MAP_ION_HANDLE *psMapIonOUT, + PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + + psMapIonOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &psMapIonIN->hDevCookie, + psMapIonIN->hDevCookie, + PVRSRV_HANDLE_TYPE_DEV_NODE); + if (psMapIonOUT->eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "%s: Failed to lookup device node handle", __FUNCTION__)); + return 0; + } + + psMapIonOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, + &psMapIonIN->hDevMemContext, + psMapIonIN->hDevMemContext, + PVRSRV_HANDLE_TYPE_DEV_MEM_CONTEXT); + if (psMapIonOUT->eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "%s: Failed to lookup memory context handle", __FUNCTION__)); + return 0; + } + + psMapIonOUT->eError = PVRSRVMapIonHandleKM(psPerProc, + psMapIonIN->hDevCookie, + psMapIonIN->hDevMemContext, + psMapIonIN->handle, + psMapIonIN->ui32Attribs, + psMapIonIN->ui32Size, + &psKernelMemInfo); + if (psMapIonOUT->eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "%s: Failed to map ion handle", __FUNCTION__)); + return 0; + } + + OSMemSet(&psMapIonOUT->sClientMemInfo, + 0, + sizeof(psMapIonOUT->sClientMemInfo)); + + psMapIonOUT->sClientMemInfo.pvLinAddrKM = + psKernelMemInfo->pvLinAddrKM; + + psMapIonOUT->sClientMemInfo.pvLinAddr = 0; + psMapIonOUT->sClientMemInfo.sDevVAddr = psKernelMemInfo->sDevVAddr; + psMapIonOUT->sClientMemInfo.ui32Flags = psKernelMemInfo->ui32Flags; + psMapIonOUT->sClientMemInfo.uAllocSize = psKernelMemInfo->uAllocSize; + + /* No mapping info, we map through ion */ + psMapIonOUT->sClientMemInfo.hMappingInfo = IMG_NULL; + + + PVRSRVAllocHandleNR(psPerProc->psHandleBase, + &psMapIonOUT->sClientMemInfo.hKernelMemInfo, + psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_NONE); + + if(psMapIonIN->ui32Attribs & PVRSRV_MEM_NO_SYNCOBJ) + { + /* signal no syncinfo */ + OSMemSet(&psMapIonOUT->sClientSyncInfo, + 0, + sizeof (PVRSRV_CLIENT_SYNC_INFO)); + psMapIonOUT->sClientMemInfo.psClientSyncInfo = IMG_NULL; + } + else + { + /* and setup the sync info */ +#if !defined(PVRSRV_DISABLE_UM_SYNCOBJ_MAPPINGS) + psMapIonOUT->sClientSyncInfo.psSyncData = + psKernelMemInfo->psKernelSyncInfo->psSyncData; + psMapIonOUT->sClientSyncInfo.sWriteOpsCompleteDevVAddr = + psKernelMemInfo->psKernelSyncInfo->sWriteOpsCompleteDevVAddr; + psMapIonOUT->sClientSyncInfo.sReadOpsCompleteDevVAddr = + psKernelMemInfo->psKernelSyncInfo->sReadOpsCompleteDevVAddr; + psMapIonOUT->sClientSyncInfo.sReadOps2CompleteDevVAddr = + psKernelMemInfo->psKernelSyncInfo->sReadOps2CompleteDevVAddr; + +#if defined (SUPPORT_SID_INTERFACE) + if (psKernelMemInfo->psKernelSyncInfo->psSyncDataMemInfoKM->sMemBlk.hOSMemHandle != IMG_NULL) + { + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psMapIonOUT->sClientSyncInfo.hMappingInfo, + psMemInfo->psKernelSyncInfo->psSyncDataMemInfoKM->sMemBlk.hOSMemHandle, + PVRSRV_HANDLE_TYPE_SYNC_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_NONE, + psMapIonOUT->sClientMemInfo.hKernelMemInfo); + } + else + { + psMapIonOUT->sClientSyncInfo.hMappingInfo = 0; + } +#else + psMapIonOUT->sClientSyncInfo.hMappingInfo = + psKernelMemInfo->psKernelSyncInfo->psSyncDataMemInfoKM->sMemBlk.hOSMemHandle; +#endif +#endif + + PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, + &psMapIonOUT->sClientSyncInfo.hKernelSyncInfo, + psKernelMemInfo->psKernelSyncInfo, + PVRSRV_HANDLE_TYPE_SYNC_INFO, + PVRSRV_HANDLE_ALLOC_FLAG_NONE, + psMapIonOUT->sClientMemInfo.hKernelMemInfo); + + psMapIonOUT->sClientMemInfo.psClientSyncInfo = + &psMapIonOUT->sClientSyncInfo; + } + return 0; +} + +static IMG_INT +PVRSRVUnmapIonHandleBW(IMG_UINT32 ui32BridgeID, + PVRSRV_BRIDGE_IN_UNMAP_ION_HANDLE *psUnmapIonIN, + PVRSRV_BRIDGE_RETURN *psUnmapIonOUT, + PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + IMG_VOID *pvKernelMemInfo; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_UNMAP_ION_HANDLE); + + psUnmapIonOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvKernelMemInfo, +#if defined (SUPPORT_SID_INTERFACE) + psUnmapIonIN->hKernelMemInfo, +#else + psUnmapIonIN->psKernelMemInfo, +#endif + PVRSRV_HANDLE_TYPE_MEM_INFO); + + if(psUnmapIonOUT->eError != PVRSRV_OK) + { + return 0; + } + + psUnmapIonOUT->eError = PVRSRVUnmapIonHandleKM(pvKernelMemInfo); + + if(psUnmapIonOUT->eError != PVRSRV_OK) + { + return 0; + } + + psUnmapIonOUT->eError = + PVRSRVReleaseHandle(psPerProc->psHandleBase, +#if defined (SUPPORT_SID_INTERFACE) + psUnmapIonIN->hKernelMemInfo, +#else + psUnmapIonIN->psKernelMemInfo, +#endif + PVRSRV_HANDLE_TYPE_MEM_INFO); + + return 0; +} +#endif /* SUPPORT_ION */ + static IMG_INT PVRSRVGetFreeDeviceMemBW(IMG_UINT32 ui32BridgeID, PVRSRV_BRIDGE_IN_GETFREEDEVICEMEM *psGetFreeDeviceMemIN, @@ -1712,7 +2047,7 @@ PVRMMapOSMemHandleToMMapDataBW(IMG_UINT32 ui32BridgeID, { PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_MHANDLE_TO_MMAP_DATA); -#if defined (__linux__) || defined(__QNXNTO__) +#if defined (__linux__) || defined (__QNXNTO__) psMMapDataOUT->eError = PVRMMapOSMemHandleToMMapData(psPerProc, psMMapDataIN->hMHandle, @@ -1738,7 +2073,7 @@ PVRMMapReleaseMMapDataBW(IMG_UINT32 ui32BridgeID, { PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_RELEASE_MMAP_DATA); -#if defined (__linux__) || defined(__QNXNTO__) +#if defined (__linux__) || defined (__QNXNTO__) psMMapDataOUT->eError = PVRMMapReleaseMMapData(psPerProc, psMMapDataIN->hMHandle, @@ -2168,7 +2503,7 @@ PDumpSyncPolBW(IMG_UINT32 ui32BridgeID, ui32Offset = offsetof(PVRSRV_SYNC_DATA, ui32WriteOpsComplete); } - + /* FIXME: Move this code to somewhere outside of the bridge */ if (psPDumpSyncPolIN->bUseLastOpDumpVal) { if(psPDumpSyncPolIN->bIsRead) @@ -2287,7 +2622,7 @@ PDumpStopInitPhaseBW(IMG_UINT32 ui32BridgeID, return 0; } -#endif +#endif /* PDUMP */ static IMG_INT @@ -2302,6 +2637,7 @@ PVRSRVGetMiscInfoBW(IMG_UINT32 ui32BridgeID, PVRSRV_ERROR eError; PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_GET_MISC_INFO); + #if defined (SUPPORT_SID_INTERFACE) sMiscInfo.ui32StateRequest = psGetMiscInfoIN->sMiscInfo.ui32StateRequest; sMiscInfo.ui32StatePresent = psGetMiscInfoIN->sMiscInfo.ui32StatePresent; @@ -2311,8 +2647,10 @@ PVRSRVGetMiscInfoBW(IMG_UINT32 ui32BridgeID, OSMemCopy(&sMiscInfo.sCacheOpCtl, &psGetMiscInfoIN->sMiscInfo.sCacheOpCtl, sizeof(sMiscInfo.sCacheOpCtl)); + OSMemCopy(&sMiscInfo.sGetRefCountCtl, + &psGetMiscInfoIN->sMiscInfo.sGetRefCountCtl, + sizeof(sMiscInfo.sGetRefCountCtl)); #else - OSMemCopy(&psGetMiscInfoOUT->sMiscInfo, &psGetMiscInfoIN->sMiscInfo, sizeof(PVRSRV_MISC_INFO)); @@ -2322,7 +2660,8 @@ PVRSRVGetMiscInfoBW(IMG_UINT32 ui32BridgeID, ((psGetMiscInfoIN->sMiscInfo.ui32StateRequest & PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0) && ((psGetMiscInfoIN->sMiscInfo.ui32StateRequest & PVRSRV_MISC_INFO_FREEMEM_PRESENT) != 0)) { - + /* Client must choose which of memstats and DDK version will be written to + * kernel side buffer */ psGetMiscInfoOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; return 0; } @@ -2331,7 +2670,7 @@ PVRSRVGetMiscInfoBW(IMG_UINT32 ui32BridgeID, ((psGetMiscInfoIN->sMiscInfo.ui32StateRequest & PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0) || ((psGetMiscInfoIN->sMiscInfo.ui32StateRequest & PVRSRV_MISC_INFO_FREEMEM_PRESENT) != 0)) { - + /* Alloc kernel side buffer to write into */ #if defined (SUPPORT_SID_INTERFACE) ASSIGN_AND_EXIT_ON_ERROR(psGetMiscInfoOUT->eError, OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, @@ -2340,7 +2679,7 @@ PVRSRVGetMiscInfoBW(IMG_UINT32 ui32BridgeID, "Output string buffer")); psGetMiscInfoOUT->eError = PVRSRVGetMiscInfoKM(&sMiscInfo); - + /* Copy result to user */ eError = CopyToUserWrapper(psPerProc, ui32BridgeID, psGetMiscInfoIN->sMiscInfo.pszMemoryStr, sMiscInfo.pszMemoryStr, @@ -2354,14 +2693,14 @@ PVRSRVGetMiscInfoBW(IMG_UINT32 ui32BridgeID, psGetMiscInfoOUT->eError = PVRSRVGetMiscInfoKM(&psGetMiscInfoOUT->sMiscInfo); - + /* Copy result to user */ eError = CopyToUserWrapper(psPerProc, ui32BridgeID, psGetMiscInfoIN->sMiscInfo.pszMemoryStr, psGetMiscInfoOUT->sMiscInfo.pszMemoryStr, psGetMiscInfoOUT->sMiscInfo.ui32MemoryStrLen); #endif - + /* Free kernel side buffer again */ #if defined (SUPPORT_SID_INTERFACE) OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sMiscInfo.ui32MemoryStrLen, @@ -2372,12 +2711,16 @@ PVRSRVGetMiscInfoBW(IMG_UINT32 ui32BridgeID, (IMG_VOID *)psGetMiscInfoOUT->sMiscInfo.pszMemoryStr, 0); #endif - + /* Replace output buffer pointer with input pointer, as both are expected + * to point to the same userspace memory. + */ psGetMiscInfoOUT->sMiscInfo.pszMemoryStr = psGetMiscInfoIN->sMiscInfo.pszMemoryStr; if(eError != PVRSRV_OK) { - + /* Do error check at the end as we always have to free and reset the + * pointer. + */ PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetMiscInfoBW Error copy to user")); return -EFAULT; } @@ -2391,13 +2734,19 @@ PVRSRVGetMiscInfoBW(IMG_UINT32 ui32BridgeID, #endif } - + /* Return on error so exit status of PVRSRVGetMiscInfoKM is propagated to client. + * Don't alloc handles for event object or timer; if error exit status is returned + * the handles should not be used (even if not null) */ if (psGetMiscInfoOUT->eError != PVRSRV_OK) { return 0; } - + /* + * The handles are not allocated in batch mode as they are shared + * (a shared handle is allocated at most once), and there is no + * resource allocation to undo if the handle allocation fails. + */ #if defined (SUPPORT_SID_INTERFACE) if (sMiscInfo.ui32StateRequest & PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT) #else @@ -2423,7 +2772,6 @@ PVRSRVGetMiscInfoBW(IMG_UINT32 ui32BridgeID, OSMemCopy(&psGetMiscInfoOUT->sMiscInfo.sGlobalEventObject.szName, sMiscInfo.sGlobalEventObject.szName, EVENTOBJNAME_MAXLENGTH); - #endif } @@ -2433,7 +2781,7 @@ PVRSRVGetMiscInfoBW(IMG_UINT32 ui32BridgeID, if (psGetMiscInfoOUT->sMiscInfo.hSOCTimerRegisterOSMemHandle) #endif { - + /* Allocate handle for SOC OSMemHandle */ psGetMiscInfoOUT->eError = PVRSRVAllocHandle(psPerProc->psHandleBase, &psGetMiscInfoOUT->sMiscInfo.hSOCTimerRegisterOSMemHandle, #if defined (SUPPORT_SID_INTERFACE) @@ -2455,7 +2803,7 @@ PVRSRVGetMiscInfoBW(IMG_UINT32 ui32BridgeID, psGetMiscInfoOUT->sMiscInfo.hSOCTimerRegisterOSMemHandle = 0; } - + /* copy data from local sMiscInfo to OUT */ psGetMiscInfoOUT->sMiscInfo.ui32StateRequest = sMiscInfo.ui32StateRequest; psGetMiscInfoOUT->sMiscInfo.ui32StatePresent = sMiscInfo.ui32StatePresent; @@ -2471,6 +2819,9 @@ PVRSRVGetMiscInfoBW(IMG_UINT32 ui32BridgeID, OSMemCopy(&psGetMiscInfoOUT->sMiscInfo.sCacheOpCtl, &sMiscInfo.sCacheOpCtl, sizeof(psGetMiscInfoOUT->sMiscInfo.sCacheOpCtl)); + OSMemCopy(&psGetMiscInfoOUT->sMiscInfo.sGetRefCountCtl, + &sMiscInfo.sGetRefCountCtl, + sizeof(psGetMiscInfoOUT->sMiscInfo.sGetRefCountCtl)); #endif return 0; @@ -2485,19 +2836,27 @@ PVRSRVConnectBW(IMG_UINT32 ui32BridgeID, PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_CONNECT_SERVICES); #if defined(PDUMP) - + /* Store the per process connection info. + * The Xserver initially connects via PVR2D which sets the persistent flag. + * But, later the Xserver may connect via SGL which doesn't carry the flag (in + * general SGL clients aren't persistent). So we OR in the flag so if it was set + * before it remains set. + */ if ((psConnectServicesIN->ui32Flags & SRV_FLAGS_PERSIST) != 0) { psPerProc->bPDumpPersistent = IMG_TRUE; } #if defined(SUPPORT_PDUMP_MULTI_PROCESS) - + /* Select whether this client is our 'active' target for pdumping in a + * multi-process environment. + * NOTE: only 1 active target is supported at present. + */ if ((psConnectServicesIN->ui32Flags & SRV_FLAGS_PDUMP_ACTIVE) != 0) { psPerProc->bPDumpActive = IMG_TRUE; } -#endif +#endif /* SUPPORT_PDUMP_MULTI_PROCESS */ #else PVR_UNREFERENCED_PARAMETER(psConnectServicesIN); #endif @@ -2518,7 +2877,7 @@ PVRSRVDisconnectBW(IMG_UINT32 ui32BridgeID, PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_DISCONNECT_SERVICES); - + /* just return OK, per-process data is cleaned up by resmgr */ psRetOUT->eError = PVRSRV_OK; return 0; @@ -2526,18 +2885,18 @@ PVRSRVDisconnectBW(IMG_UINT32 ui32BridgeID, static IMG_INT PVRSRVEnumerateDCBW(IMG_UINT32 ui32BridgeID, - PVRSRV_BRIDGE_IN_ENUMCLASS *psEnumDispClassIN, - PVRSRV_BRIDGE_OUT_ENUMCLASS *psEnumDispClassOUT, - PVRSRV_PER_PROCESS_DATA *psPerProc) + PVRSRV_BRIDGE_IN_ENUMCLASS *psEnumDispClassIN, + PVRSRV_BRIDGE_OUT_ENUMCLASS *psEnumDispClassOUT, + PVRSRV_PER_PROCESS_DATA *psPerProc) { PVR_UNREFERENCED_PARAMETER(psPerProc); PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_ENUM_CLASS); - psEnumDispClassOUT->eError = - PVRSRVEnumerateDCKM(psEnumDispClassIN->sDeviceClass, - &psEnumDispClassOUT->ui32NumDevices, - &psEnumDispClassOUT->ui32DevID[0]); + psEnumDispClassOUT->eError = + PVRSRVEnumerateDCKM(psEnumDispClassIN->sDeviceClass, + &psEnumDispClassOUT->ui32NumDevices, + &psEnumDispClassOUT->ui32DevID[0]); return 0; } @@ -2607,7 +2966,7 @@ PVRSRVCloseDCDeviceBW(IMG_UINT32 ui32BridgeID, return 0; } - psRetOUT->eError = PVRSRVCloseDCDeviceKM(pvDispClassInfoInt, IMG_FALSE); + psRetOUT->eError = PVRSRVCloseDCDeviceKM(pvDispClassInfoInt); if(psRetOUT->eError != PVRSRV_OK) { return 0; @@ -2678,9 +3037,10 @@ PVRSRVEnumDCDimsBW(IMG_UINT32 ui32BridgeID, return 0; } +#if defined(SUPPORT_PVRSRV_GET_DC_SYSTEM_BUFFER) static IMG_INT PVRSRVGetDCSystemBufferBW(IMG_UINT32 ui32BridgeID, - PVRSRV_BRIDGE_IN_GET_DISPCLASS_SYSBUFFER *psGetDispClassSysBufferIN, + PVRSRV_BRIDGE_IN_GET_DISPCLASS_SYSBUFFER *psGetDispClassSysBufferIN, //IMG_HANDLE *phGetDispClassSysBufferIN, PVRSRV_BRIDGE_OUT_GET_DISPCLASS_SYSBUFFER *psGetDispClassSysBufferOUT, PVRSRV_PER_PROCESS_DATA *psPerProc) { @@ -2710,7 +3070,7 @@ PVRSRVGetDCSystemBufferBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* PRQA S 1461 6 */ /* ignore warning about enum type being converted */ PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, &psGetDispClassSysBufferOUT->hBuffer, hBufferInt, @@ -2722,6 +3082,7 @@ PVRSRVGetDCSystemBufferBW(IMG_UINT32 ui32BridgeID, return 0; } +#endif static IMG_INT PVRSRVGetDCInfoBW(IMG_UINT32 ui32BridgeID, @@ -2775,7 +3136,7 @@ PVRSRVCreateDCSwapChainBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* Get ui32SwapChainID from input */ ui32SwapChainID = psCreateDispClassSwapChainIN->ui32SwapChainID; psCreateDispClassSwapChainOUT->eError = @@ -2793,7 +3154,7 @@ PVRSRVCreateDCSwapChainBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* Pass ui32SwapChainID to output */ psCreateDispClassSwapChainOUT->ui32SwapChainID = ui32SwapChainID; PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, @@ -3054,10 +3415,11 @@ PVRSRVGetDCBuffersBW(IMG_UINT32 ui32BridgeID, pvSwapChain, &psGetDispClassBuffersOUT->ui32BufferCount, #if defined (SUPPORT_SID_INTERFACE) - pahBuffer); + pahBuffer, #else - psGetDispClassBuffersOUT->ahBuffer); + psGetDispClassBuffersOUT->ahBuffer, #endif + psGetDispClassBuffersOUT->asPhyAddr); if (psGetDispClassBuffersOUT->eError != PVRSRV_OK) { return 0; @@ -3073,7 +3435,7 @@ PVRSRVGetDCBuffersBW(IMG_UINT32 ui32BridgeID, IMG_HANDLE hBufferExt; #endif - + /* PRQA S 1461 15 */ /* ignore warning about enum type being converted */ #if defined (SUPPORT_SID_INTERFACE) PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, &hBufferExt, @@ -3159,7 +3521,6 @@ PVRSRVSwapToDCBufferBW(IMG_UINT32 ui32BridgeID, } #endif - psRetOUT->eError = PVRSRVSwapToDCBufferKM(pvDispClassInfo, pvSwapChainBuf, @@ -3176,6 +3537,136 @@ PVRSRVSwapToDCBufferBW(IMG_UINT32 ui32BridgeID, } static IMG_INT +PVRSRVSwapToDCBuffer2BW(IMG_UINT32 ui32BridgeID, + PVRSRV_BRIDGE_IN_SWAP_DISPCLASS_TO_BUFFER2 *psSwapDispClassBufferIN, + PVRSRV_BRIDGE_RETURN *psRetOUT, + PVRSRV_PER_PROCESS_DATA *psPerProc) +{ + IMG_VOID *pvPrivData = IMG_NULL; + IMG_VOID *pvDispClassInfo; + IMG_VOID *pvSwapChain; + IMG_UINT32 i; + + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_SWAP_DISPCLASS_TO_BUFFER2); + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + &pvDispClassInfo, + psSwapDispClassBufferIN->hDeviceKM, + PVRSRV_HANDLE_TYPE_DISP_INFO); + if(psRetOUT->eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVSwapToDCBuffer2BW: Failed to look up DISP_INFO handle")); + return 0; + } + + psRetOUT->eError = + PVRSRVLookupSubHandle(psPerProc->psHandleBase, + &pvSwapChain, + psSwapDispClassBufferIN->hSwapChain, + PVRSRV_HANDLE_TYPE_DISP_SWAP_CHAIN, + psSwapDispClassBufferIN->hDeviceKM); + if(psRetOUT->eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVSwapToDCBuffer2BW: Failed to look up DISP_BUFFER handle")); + return 0; + } + + if(!OSAccessOK(PVR_VERIFY_WRITE, + psSwapDispClassBufferIN->ppsKernelMemInfos, + sizeof(IMG_HANDLE) * psSwapDispClassBufferIN->ui32NumMemInfos)) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVSwapToDCBuffer2BW: Access check failed for ppsKernelMemInfos")); + return -EFAULT; + } + + if(!OSAccessOK(PVR_VERIFY_WRITE, + psSwapDispClassBufferIN->ppsKernelSyncInfos, + sizeof(IMG_HANDLE) * psSwapDispClassBufferIN->ui32NumMemInfos)) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVSwapToDCBuffer2BW: Access check failed for ppsKernelSyncInfos")); + return -EFAULT; + } + + for (i = 0; i < psSwapDispClassBufferIN->ui32NumMemInfos; i++) + { + PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo; + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + (IMG_PVOID *)&psKernelMemInfo, + psSwapDispClassBufferIN->ppsKernelMemInfos[i], + PVRSRV_HANDLE_TYPE_MEM_INFO); + if(psRetOUT->eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVSwapToDCBuffer2BW: Failed to look up MEM_INFO handle")); + return 0; + } + + psRetOUT->eError = + PVRSRVLookupHandle(psPerProc->psHandleBase, + (IMG_PVOID *)&psKernelSyncInfo, + psSwapDispClassBufferIN->ppsKernelSyncInfos[i], + PVRSRV_HANDLE_TYPE_SYNC_INFO); + if(psRetOUT->eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVSwapToDCBuffer2BW: Failed to look up SYNC_INFO handle")); + return 0; + } + + psSwapDispClassBufferIN->ppsKernelMemInfos[i] = psKernelMemInfo; + psSwapDispClassBufferIN->ppsKernelSyncInfos[i] = psKernelSyncInfo; + } + + if(psSwapDispClassBufferIN->ui32PrivDataLength > 0) + { + if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + psSwapDispClassBufferIN->ui32PrivDataLength, + (IMG_VOID **)&pvPrivData, IMG_NULL, + "Swap Command Private Data") != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2BW: Failed to allocate private data space")); + return -ENOMEM; + } + + if(CopyFromUserWrapper(psPerProc, + ui32BridgeID, + pvPrivData, + psSwapDispClassBufferIN->pvPrivData, + psSwapDispClassBufferIN->ui32PrivDataLength) != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVSwapToDCBuffer2BW: Failed to copy private data")); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + psSwapDispClassBufferIN->ui32PrivDataLength, + pvPrivData, IMG_NULL); + return -EFAULT; + } + } + + psRetOUT->eError = + PVRSRVSwapToDCBuffer2KM(pvDispClassInfo, + pvSwapChain, + psSwapDispClassBufferIN->ui32SwapInterval, + psSwapDispClassBufferIN->ppsKernelMemInfos, + psSwapDispClassBufferIN->ppsKernelSyncInfos, + psSwapDispClassBufferIN->ui32NumMemInfos, + pvPrivData, + psSwapDispClassBufferIN->ui32PrivDataLength); + + if(psRetOUT->eError != PVRSRV_OK) + { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + psSwapDispClassBufferIN->ui32PrivDataLength, + pvPrivData, IMG_NULL); + } + + return 0; +} + + + +static IMG_INT PVRSRVSwapToDCSystemBW(IMG_UINT32 ui32BridgeID, PVRSRV_BRIDGE_IN_SWAP_DISPCLASS_TO_SYSTEM *psSwapDispClassSystemIN, PVRSRV_BRIDGE_RETURN *psRetOUT, @@ -3278,7 +3769,7 @@ PVRSRVCloseBCDeviceBW(IMG_UINT32 ui32BridgeID, } psRetOUT->eError = - PVRSRVCloseBCDeviceKM(pvBufClassInfo, IMG_FALSE); + PVRSRVCloseBCDeviceKM(pvBufClassInfo); if(psRetOUT->eError != PVRSRV_OK) { @@ -3351,7 +3842,7 @@ PVRSRVGetBCBufferBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* PRQA S 1461 6 */ /* ignore warning about enum type being converted */ PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, &psGetBufferClassBufferOUT->hBuffer, hBufferInt, @@ -3521,7 +4012,11 @@ PVRSRVMapMemInfoMemBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* + * To prevent the building up of deep chains of subhandles, parent + * the new meminfo off the parent of the input meminfo, if it has + * a parent. + */ psMapMemInfoMemOUT->eError = PVRSRVGetParentHandle(psPerProc->psHandleBase, &hParent, @@ -3581,14 +4076,14 @@ PVRSRVMapMemInfoMemBW(IMG_UINT32 ui32BridgeID, if(psKernelMemInfo->ui32Flags & PVRSRV_MEM_NO_SYNCOBJ) { - + /* signal no syncinfo */ OSMemSet(&psMapMemInfoMemOUT->sClientSyncInfo, 0, sizeof (PVRSRV_CLIENT_SYNC_INFO)); } else { - + /* and setup the sync info */ #if !defined(PVRSRV_DISABLE_UM_SYNCOBJ_MAPPINGS) psMapMemInfoMemOUT->sClientSyncInfo.psSyncData = psKernelMemInfo->psKernelSyncInfo->psSyncData; @@ -3596,6 +4091,8 @@ PVRSRVMapMemInfoMemBW(IMG_UINT32 ui32BridgeID, psKernelMemInfo->psKernelSyncInfo->sWriteOpsCompleteDevVAddr; psMapMemInfoMemOUT->sClientSyncInfo.sReadOpsCompleteDevVAddr = psKernelMemInfo->psKernelSyncInfo->sReadOpsCompleteDevVAddr; + psMapMemInfoMemOUT->sClientSyncInfo.sReadOps2CompleteDevVAddr = + psKernelMemInfo->psKernelSyncInfo->sReadOps2CompleteDevVAddr; #if defined (SUPPORT_SID_INTERFACE) if (psKernelMemInfo->psKernelSyncInfo->psSyncDataMemInfoKM->sMemBlk.hOSMemHandle != IMG_NULL) @@ -3660,13 +4157,25 @@ DummyBW(IMG_UINT32 ui32BridgeID, } +/*! + * ***************************************************************************** + * @brief A wrapper for filling in the g_BridgeDispatchTable array that does + * error checking. + * + * @param ui32Index + * @param pszIOCName + * @param pfFunction + * @param pszFunctionName + * + * @return + ********************************************************************************/ IMG_VOID _SetDispatchTableEntry(IMG_UINT32 ui32Index, const IMG_CHAR *pszIOCName, BridgeWrapperFunction pfFunction, const IMG_CHAR *pszFunctionName) { - static IMG_UINT32 ui32PrevIndex = ~0UL; + static IMG_UINT32 ui32PrevIndex = ~0UL; /* -1 */ #if !defined(DEBUG) PVR_UNREFERENCED_PARAMETER(pszIOCName); #endif @@ -3675,11 +4184,16 @@ _SetDispatchTableEntry(IMG_UINT32 ui32Index, #endif #if defined(DEBUG_BRIDGE_KM_DISPATCH_TABLE) - + /* INTEGRATION_POINT: Enable this to dump out the dispatch table entries */ PVR_DPF((PVR_DBG_WARNING, "%s: %d %s %s", __FUNCTION__, ui32Index, pszIOCName, pszFunctionName)); #endif - + /* We should never be over-writing a previous entry. + * If we are, tell the world about it. + * NOTE: This shouldn't be debug only since switching from debug->release + * etc is likly to modify the available ioctls and thus be a point where + * mistakes are exposed. This isn't run at at a performance critical time. + */ if(g_BridgeDispatchTable[ui32Index].pfFunction) { #if defined(DEBUG_BRIDGE_KM) @@ -3694,7 +4208,17 @@ _SetDispatchTableEntry(IMG_UINT32 ui32Index, PVR_DPF((PVR_DBG_ERROR, "NOTE: Enabling DEBUG_BRIDGE_KM_DISPATCH_TABLE may help debug this issue.")); } - + /* Any gaps are sub-optimal in-terms of memory usage, but we are mainly + * interested in spotting any large gap of wasted memory that could be + * accidentally introduced. + * + * This will currently flag up any gaps > 5 entries. + * + * NOTE: This shouldn't be debug only since switching from debug->release + * etc is likly to modify the available ioctls and thus be a point where + * mistakes are exposed. This isn't run at at a performance critical time. + */ +// if((ui32PrevIndex != (IMG_UINT32)-1) && if((ui32PrevIndex != ~0UL) && ((ui32Index >= ui32PrevIndex + DISPATCH_TABLE_GAP_THRESHOLD) || (ui32Index <= ui32PrevIndex))) @@ -3734,14 +4258,14 @@ PVRSRVInitSrvConnectBW(IMG_UINT32 ui32BridgeID, PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_INITSRV_CONNECT); PVR_UNREFERENCED_PARAMETER(psBridgeIn); - + /* PRQA S 3415 1 */ /* side effects needed - if any step fails */ if((OSProcHasPrivSrvInit() == IMG_FALSE) || PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_RUNNING) || PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_RAN)) { psRetOUT->eError = PVRSRV_ERROR_SRV_CONNECT_FAILED; return 0; } -#if defined (__linux__) || defined(__QNXNTO__) +#if defined (__linux__) || defined (__QNXNTO__) PVRSRVSetInitServerState(PVRSRV_INIT_SERVER_RUNNING, IMG_TRUE); #endif psPerProc->bInitProcess = IMG_TRUE; @@ -3853,6 +4377,8 @@ PVRSRVEventObjectOpenBW(IMG_UINT32 ui32BridgeID, } #if defined (SUPPORT_SID_INTERFACE) +/* Windows7, WinXP and Vista already use an Index type handle which the client glue uses directly */ +/* Linux requires a SID handle */ #if !defined (WINXP) && !defined(SUPPORT_VISTA) PVRSRVAllocHandleNR(psPerProc->psHandleBase, &psEventObjectOpenOUT->hOSEvent, @@ -3917,7 +4443,7 @@ PVRSRVEventObjectCloseBW(IMG_UINT32 ui32BridgeID, &psEventObjectCloseIN->sEventObject.szName, EVENTOBJNAME_MAXLENGTH) != PVRSRV_OK) { - + /*not nulling pointer, out of scope*/ return -EFAULT; } @@ -3937,42 +4463,55 @@ typedef struct _MODIFY_SYNC_OP_INFO IMG_UINT32 ui32ModifyFlags; IMG_UINT32 ui32ReadOpsPendingSnapShot; IMG_UINT32 ui32WriteOpsPendingSnapShot; + IMG_UINT32 ui32ReadOps2PendingSnapShot; } MODIFY_SYNC_OP_INFO; static PVRSRV_ERROR DoQuerySyncOpsSatisfied(PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo, IMG_UINT32 ui32ReadOpsPendingSnapShot, - IMG_UINT32 ui32WriteOpsPendingSnapShot) + IMG_UINT32 ui32WriteOpsPendingSnapShot, + IMG_UINT32 ui32ReadOps2PendingSnapShot) { IMG_UINT32 ui32WriteOpsPending; IMG_UINT32 ui32ReadOpsPending; + IMG_UINT32 ui32ReadOps2Pending; + + /* + * + * We wait until the complete count reaches _or_moves_past_ the + * snapshot value. + * + */ - if (!psKernelSyncInfo) { return PVRSRV_ERROR_INVALID_PARAMS; } - - - - - - - - + /* + let p be the pending ops count + let c be the complete ops count + let p' be the previously taken snapshot + if p exceeds c by an amount greater than that by which + p exceeds p', then the condition is not yet satisfied. + Note that (p - c) can never be negative, and neither can (p - p') + so we can do the comparison using unsigned arithmetic + */ ui32WriteOpsPending = psKernelSyncInfo->psSyncData->ui32WriteOpsPending; ui32ReadOpsPending = psKernelSyncInfo->psSyncData->ui32ReadOpsPending; + ui32ReadOps2Pending = psKernelSyncInfo->psSyncData->ui32ReadOps2Pending; if((ui32WriteOpsPending - ui32WriteOpsPendingSnapShot >= ui32WriteOpsPending - psKernelSyncInfo->psSyncData->ui32WriteOpsComplete) && (ui32ReadOpsPending - ui32ReadOpsPendingSnapShot >= - ui32ReadOpsPending - psKernelSyncInfo->psSyncData->ui32ReadOpsComplete)) + ui32ReadOpsPending - psKernelSyncInfo->psSyncData->ui32ReadOpsComplete) && + (ui32ReadOps2Pending - ui32ReadOps2PendingSnapShot >= + ui32ReadOps2Pending - psKernelSyncInfo->psSyncData->ui32ReadOps2Complete)) { #if defined(PDUMP) && !defined(SUPPORT_VGX) - + /* pdump the sync pol: reads */ PDumpComment("Poll for read ops complete to reach value (pdump: %u, actual snapshot: %u)", psKernelSyncInfo->psSyncData->ui32LastReadOpDumpVal, ui32ReadOpsPendingSnapShot); @@ -3980,11 +4519,11 @@ static PVRSRV_ERROR DoQuerySyncOpsSatisfied(PVRSRV_KERNEL_SYNC_INFO *psKernelSyn offsetof(PVRSRV_SYNC_DATA, ui32ReadOpsComplete), psKernelSyncInfo->psSyncData->ui32LastReadOpDumpVal, 0xFFFFFFFF, - PDUMP_POLL_OPERATOR_EQUAL, + PDUMP_POLL_OPERATOR_EQUAL, /* * see "NB" below */ 0, MAKEUNIQUETAG(psKernelSyncInfo->psSyncDataMemInfoKM)); - + /* pdump the sync pol: writes */ PDumpComment("Poll for write ops complete to reach value (pdump: %u, actual snapshot: %u)", psKernelSyncInfo->psSyncData->ui32LastOpDumpVal, ui32WriteOpsPendingSnapShot); @@ -3992,11 +4531,12 @@ static PVRSRV_ERROR DoQuerySyncOpsSatisfied(PVRSRV_KERNEL_SYNC_INFO *psKernelSyn offsetof(PVRSRV_SYNC_DATA, ui32WriteOpsComplete), psKernelSyncInfo->psSyncData->ui32LastOpDumpVal, 0xFFFFFFFF, - PDUMP_POLL_OPERATOR_EQUAL, + PDUMP_POLL_OPERATOR_EQUAL, /* * see "NB" below */ 0, MAKEUNIQUETAG(psKernelSyncInfo->psSyncDataMemInfoKM)); - - + /* NB: FIXME -- really need to POL on an expression to + accurately reflect the condition we need to check. How to + do this in PDUMP? */ #endif return PVRSRV_OK; } @@ -4018,20 +4558,21 @@ static PVRSRV_ERROR DoModifyCompleteSyncOps(MODIFY_SYNC_OP_INFO *psModSyncOpInfo return PVRSRV_ERROR_INVALID_PARAMS; } - + /* If user has used the API correctly, we will always have reached the pending snapshot. + We should catch this error on the client side of the bridge and report it in an obvious way */ if((psModSyncOpInfo->ui32WriteOpsPendingSnapShot != psKernelSyncInfo->psSyncData->ui32WriteOpsComplete) || (psModSyncOpInfo->ui32ReadOpsPendingSnapShot != psKernelSyncInfo->psSyncData->ui32ReadOpsComplete)) { return PVRSRV_ERROR_BAD_SYNC_STATE; } - + /* update the WOpComplete */ if(psModSyncOpInfo->ui32ModifyFlags & PVRSRV_MODIFYSYNCOPS_FLAGS_WO_INC) { psKernelSyncInfo->psSyncData->ui32WriteOpsComplete++; } - + /* update the ROpComplete */ if(psModSyncOpInfo->ui32ModifyFlags & PVRSRV_MODIFYSYNCOPS_FLAGS_RO_INC) { psKernelSyncInfo->psSyncData->ui32ReadOpsComplete++; @@ -4060,12 +4601,12 @@ static PVRSRV_ERROR ModifyCompleteSyncOpsCallBack(IMG_PVOID pvParam, if (psModSyncOpInfo->psKernelSyncInfo) { - LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { if (DoQuerySyncOpsSatisfied(psModSyncOpInfo->psKernelSyncInfo, psModSyncOpInfo->ui32ReadOpsPendingSnapShot, - psModSyncOpInfo->ui32WriteOpsPendingSnapShot) == PVRSRV_OK) + psModSyncOpInfo->ui32WriteOpsPendingSnapShot, + psModSyncOpInfo->ui32ReadOps2PendingSnapShot) == PVRSRV_OK) { goto OpFlushedComplete; } @@ -4077,21 +4618,22 @@ static PVRSRV_ERROR ModifyCompleteSyncOpsCallBack(IMG_PVOID pvParam, PVR_DPF((PVR_DBG_ERROR, " Write ops pending snapshot = %d, write ops complete = %d", psModSyncOpInfo->ui32WriteOpsPendingSnapShot, psModSyncOpInfo->psKernelSyncInfo->psSyncData->ui32WriteOpsComplete)); - PVR_DPF((PVR_DBG_ERROR, " Read ops pending snapshot = %d, write ops complete = %d", + PVR_DPF((PVR_DBG_ERROR, " Read ops pending snapshot = %d, read ops complete = %d", psModSyncOpInfo->ui32ReadOpsPendingSnapShot, psModSyncOpInfo->psKernelSyncInfo->psSyncData->ui32ReadOpsComplete)); - + PVR_DPF((PVR_DBG_ERROR, " Read ops pending snapshot = %d, read ops2 complete = %d", + psModSyncOpInfo->ui32ReadOps2PendingSnapShot, + psModSyncOpInfo->psKernelSyncInfo->psSyncData->ui32ReadOps2Complete)); return PVRSRV_ERROR_TIMEOUT; OpFlushedComplete: - DoModifyCompleteSyncOps(psModSyncOpInfo); + PVRSRVKernelSyncInfoDecRef(psModSyncOpInfo->psKernelSyncInfo, IMG_NULL); } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(MODIFY_SYNC_OP_INFO), (IMG_VOID *)psModSyncOpInfo, 0); - - + /* re-kick all services managed devices */ PVRSRVScheduleDeviceCallbacks(); return PVRSRV_OK; @@ -4118,7 +4660,7 @@ PVRSRVCreateSyncInfoModObjBW(IMG_UINT32 (IMG_VOID **)&psModSyncOpInfo, 0, "ModSyncOpInfo (MODIFY_SYNC_OP_INFO)")); - psModSyncOpInfo->psKernelSyncInfo = IMG_NULL; + psModSyncOpInfo->psKernelSyncInfo = IMG_NULL; /* mark it as empty */ psCreateSyncInfoModObjOUT->eError = PVRSRVAllocHandle(psPerProc->psHandleBase, &psCreateSyncInfoModObjOUT->hKernelSyncInfoModObj, @@ -4165,11 +4707,13 @@ PVRSRVDestroySyncInfoModObjBW(IMG_UINT32 if(psModSyncOpInfo->psKernelSyncInfo != IMG_NULL) { - + /* Not empty */ psDestroySyncInfoModObjOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; return 0; } + PVRSRVKernelSyncInfoDecRef(psModSyncOpInfo->psKernelSyncInfo, IMG_NULL); + psDestroySyncInfoModObjOUT->eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, psDestroySyncInfoModObjIN->hKernelSyncInfoModObj, PVRSRV_HANDLE_TYPE_SYNC_INFO_MOD_OBJ); @@ -4224,22 +4768,33 @@ PVRSRVModifyPendingSyncOpsBW(IMG_UINT32 ui32BridgeID, if(psModSyncOpInfo->psKernelSyncInfo) { - + /* SyncInfoModification is not empty */ psModifySyncOpsOUT->eError = PVRSRV_ERROR_RETRY; PVR_DPF((PVR_DBG_VERBOSE, "PVRSRVModifyPendingSyncOpsBW: SyncInfo Modification object is not empty")); return 0; } - + /* Should never happen, but check to be sure */ + if (psKernelSyncInfo == IMG_NULL) + { + psModifySyncOpsOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; + PVR_DPF((PVR_DBG_VERBOSE, "PVRSRVModifyPendingSyncOpsBW: SyncInfo bad handle")); + return 0; + } + + PVRSRVKernelSyncInfoIncRef(psKernelSyncInfo, IMG_NULL); + /* setup info to store in resman */ psModSyncOpInfo->psKernelSyncInfo = psKernelSyncInfo; psModSyncOpInfo->ui32ModifyFlags = psModifySyncOpsIN->ui32ModifyFlags; psModSyncOpInfo->ui32ReadOpsPendingSnapShot = psKernelSyncInfo->psSyncData->ui32ReadOpsPending; psModSyncOpInfo->ui32WriteOpsPendingSnapShot = psKernelSyncInfo->psSyncData->ui32WriteOpsPending; + psModSyncOpInfo->ui32ReadOps2PendingSnapShot = psKernelSyncInfo->psSyncData->ui32ReadOps2Pending; - + /* We return PRE-INCREMENTED versions of all sync Op Values */ psModifySyncOpsOUT->ui32ReadOpsPending = psKernelSyncInfo->psSyncData->ui32ReadOpsPending; psModifySyncOpsOUT->ui32WriteOpsPending = psKernelSyncInfo->psSyncData->ui32WriteOpsPending; + psModifySyncOpsOUT->ui32ReadOps2Pending = psKernelSyncInfo->psSyncData->ui32ReadOps2Pending; if(psModifySyncOpsIN->ui32ModifyFlags & PVRSRV_MODIFYSYNCOPS_FLAGS_WO_INC) { @@ -4251,7 +4806,7 @@ PVRSRVModifyPendingSyncOpsBW(IMG_UINT32 ui32BridgeID, psKernelSyncInfo->psSyncData->ui32ReadOpsPending++; } - + /* pull the resman item to the front of the list */ psModifySyncOpsOUT->eError = ResManDissociateRes(psModSyncOpInfo->hResItem, psPerProc->hResManContext); @@ -4287,7 +4842,7 @@ PVRSRVModifyCompleteSyncOpsBW(IMG_UINT32 ui32BridgeID, if(psModSyncOpInfo->psKernelSyncInfo == IMG_NULL) { - + /* Empty */ psModifySyncOpsOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; return 0; } @@ -4300,9 +4855,10 @@ PVRSRVModifyCompleteSyncOpsBW(IMG_UINT32 ui32BridgeID, return 0; } + PVRSRVKernelSyncInfoDecRef(psModSyncOpInfo->psKernelSyncInfo, IMG_NULL); psModSyncOpInfo->psKernelSyncInfo = IMG_NULL; - + /* re-kick all services managed devices */ PVRSRVScheduleDeviceCallbacks(); return 0; @@ -4329,10 +4885,11 @@ PVRSRVSyncOpsTakeTokenBW(IMG_UINT32 ui32BridgeID, return 0; } - + /* We return PRE-INCREMENTED versions of all sync Op Values */ psSyncOpsTakeTokenOUT->ui32ReadOpsPending = psKernelSyncInfo->psSyncData->ui32ReadOpsPending; psSyncOpsTakeTokenOUT->ui32WriteOpsPending = psKernelSyncInfo->psSyncData->ui32WriteOpsPending; + psSyncOpsTakeTokenOUT->ui32ReadOps2Pending = psKernelSyncInfo->psSyncData->ui32ReadOps2Pending; return 0; } @@ -4347,6 +4904,7 @@ PVRSRVSyncOpsFlushToTokenBW(IMG_UINT32 u PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo; IMG_UINT32 ui32ReadOpsPendingSnapshot; IMG_UINT32 ui32WriteOpsPendingSnapshot; + IMG_UINT32 ui32ReadOps2PendingSnapshot; PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_SYNC_OPS_FLUSH_TO_TOKEN); @@ -4362,10 +4920,12 @@ PVRSRVSyncOpsFlushToTokenBW(IMG_UINT32 u ui32ReadOpsPendingSnapshot = psSyncOpsFlushToTokenIN->ui32ReadOpsPendingSnapshot; ui32WriteOpsPendingSnapshot = psSyncOpsFlushToTokenIN->ui32WriteOpsPendingSnapshot; + ui32ReadOps2PendingSnapshot = psSyncOpsFlushToTokenIN->ui32ReadOps2PendingSnapshot; psSyncOpsFlushToTokenOUT->eError = DoQuerySyncOpsSatisfied(psKernelSyncInfo, ui32ReadOpsPendingSnapshot, - ui32WriteOpsPendingSnapshot); + ui32WriteOpsPendingSnapshot, + ui32ReadOps2PendingSnapshot); if (psSyncOpsFlushToTokenOUT->eError != PVRSRV_OK && psSyncOpsFlushToTokenOUT->eError != PVRSRV_ERROR_RETRY) { @@ -4399,14 +4959,15 @@ PVRSRVSyncOpsFlushToModObjBW(IMG_UINT32 if(psModSyncOpInfo->psKernelSyncInfo == IMG_NULL) { - + /* Empty */ psSyncOpsFlushToModObjOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; return 0; } psSyncOpsFlushToModObjOUT->eError = DoQuerySyncOpsSatisfied(psModSyncOpInfo->psKernelSyncInfo, psModSyncOpInfo->ui32ReadOpsPendingSnapShot, - psModSyncOpInfo->ui32WriteOpsPendingSnapShot); + psModSyncOpInfo->ui32WriteOpsPendingSnapShot, + psModSyncOpInfo->ui32ReadOps2PendingSnapShot); if (psSyncOpsFlushToModObjOUT->eError != PVRSRV_OK && psSyncOpsFlushToModObjOUT->eError != PVRSRV_ERROR_RETRY) { @@ -4440,14 +5001,16 @@ PVRSRVSyncOpsFlushToDeltaBW(IMG_UINT32 u return 0; } - + /* FIXME: there's logic here in the bridge-wrapper - this needs to be moved to + a better place */ + ui32DeltaRead = psSyncInfo->psSyncData->ui32ReadOpsPending - psSyncInfo->psSyncData->ui32ReadOpsComplete; ui32DeltaWrite = psSyncInfo->psSyncData->ui32WriteOpsPending - psSyncInfo->psSyncData->ui32WriteOpsComplete; if (ui32DeltaRead <= psSyncOpsFlushToDeltaIN->ui32Delta && ui32DeltaWrite <= psSyncOpsFlushToDeltaIN->ui32Delta) { #if defined(PDUMP) && !defined(SUPPORT_VGX) - + /* pdump the sync pol: reads */ PDumpComment("Poll for read ops complete to delta (%u)", psSyncOpsFlushToDeltaIN->ui32Delta); psSyncOpsFlushToDeltaOUT->eError = @@ -4459,7 +5022,7 @@ PVRSRVSyncOpsFlushToDeltaBW(IMG_UINT32 u 0, MAKEUNIQUETAG(psSyncInfo->psSyncDataMemInfoKM)); - + /* pdump the sync pol: writes */ PDumpComment("Poll for write ops complete to delta (%u)", psSyncOpsFlushToDeltaIN->ui32Delta); psSyncOpsFlushToDeltaOUT->eError = @@ -4489,18 +5052,13 @@ FreeSyncInfoCallback(IMG_PVOID pvParam, IMG_BOOL bDummy) { PVRSRV_KERNEL_SYNC_INFO *psSyncInfo; - PVRSRV_ERROR eError; PVR_UNREFERENCED_PARAMETER(ui32Param); PVR_UNREFERENCED_PARAMETER(bDummy); psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *)pvParam; - eError = PVRSRVFreeSyncInfoKM(psSyncInfo); - if (eError != PVRSRV_OK) - { - return eError; - } + PVRSRVKernelSyncInfoDecRef(psSyncInfo, IMG_NULL); return PVRSRV_OK; } @@ -4558,16 +5116,16 @@ PVRSRVAllocSyncInfoBW(IMG_UINT32 ui32Bri 0, FreeSyncInfoCallback); - + /* Success */ goto allocsyncinfo_commit; - + /* Error handling */ allocsyncinfo_errorexit_freesyncinfo: - PVRSRVFreeSyncInfoKM(psSyncInfo); + PVRSRVKernelSyncInfoDecRef(psSyncInfo, IMG_NULL); allocsyncinfo_errorexit: - + /* Common exit */ allocsyncinfo_commit: psAllocSyncInfoOUT->eError = eError; COMMIT_HANDLE_BATCH_OR_ERROR(eError, psPerProc); @@ -4662,30 +5220,35 @@ CommonBridgeInit(IMG_VOID) #if defined(SUPPORT_DRI_DRM_EXTERNAL) SetDispatchTableEntry(PVRSRV_BRIDGE_IMPORT_GEM, PVRSRVImportGEMBW); #endif /* SUPPORT_DRI_DRM_EXTERNAL */ - - SetDispatchTableEntry(PVRSRV_BRIDGE_PROCESS_SIMISR_EVENT, DummyBW); - SetDispatchTableEntry(PVRSRV_BRIDGE_REGISTER_SIM_PROCESS, DummyBW); - SetDispatchTableEntry(PVRSRV_BRIDGE_UNREGISTER_SIM_PROCESS, DummyBW); +#if defined(SUPPORT_ION) + SetDispatchTableEntry(PVRSRV_BRIDGE_MAP_ION_HANDLE, PVRSRVMapIonHandleBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_UNMAP_ION_HANDLE, PVRSRVUnmapIonHandleBW); +#endif - + /* SIM */ + SetDispatchTableEntry(PVRSRV_BRIDGE_PROCESS_SIMISR_EVENT, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_REGISTER_SIM_PROCESS, DummyBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_UNREGISTER_SIM_PROCESS, DummyBW); + + /* User Mapping */ SetDispatchTableEntry(PVRSRV_BRIDGE_MAPPHYSTOUSERSPACE, DummyBW); SetDispatchTableEntry(PVRSRV_BRIDGE_UNMAPPHYSTOUSERSPACE, DummyBW); SetDispatchTableEntry(PVRSRV_BRIDGE_GETPHYSTOUSERSPACEMAP, DummyBW); SetDispatchTableEntry(PVRSRV_BRIDGE_GET_FB_STATS, DummyBW); - + /* API to retrieve misc. info. from services */ SetDispatchTableEntry(PVRSRV_BRIDGE_GET_MISC_INFO, PVRSRVGetMiscInfoBW); SetDispatchTableEntry(PVRSRV_BRIDGE_RELEASE_MISC_INFO, DummyBW); - + /* Overlay ioctls */ #if defined (SUPPORT_OVERLAY_ROTATE_BLIT) SetDispatchTableEntry(PVRSRV_BRIDGE_INIT_3D_OVL_BLT_RES, DummyBW); SetDispatchTableEntry(PVRSRV_BRIDGE_DEINIT_3D_OVL_BLT_RES, DummyBW); #endif - + /* PDUMP */ #if defined(PDUMP) SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_INIT, DummyBW); SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_MEMPOL, PDumpMemPolBW); @@ -4705,20 +5268,24 @@ CommonBridgeInit(IMG_VOID) SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_CYCLE_COUNT_REG_READ, PDumpCycleCountRegReadBW); SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_STARTINITPHASE, PDumpStartInitPhaseBW); SetDispatchTableEntry(PVRSRV_BRIDGE_PDUMP_STOPINITPHASE, PDumpStopInitPhaseBW); -#endif +#endif /* defined(PDUMP) */ - + /* DisplayClass APIs */ SetDispatchTableEntry(PVRSRV_BRIDGE_GET_OEMJTABLE, DummyBW); - + /* device class enum */ SetDispatchTableEntry(PVRSRV_BRIDGE_ENUM_CLASS, PVRSRVEnumerateDCBW); - + /* display class API */ SetDispatchTableEntry(PVRSRV_BRIDGE_OPEN_DISPCLASS_DEVICE, PVRSRVOpenDCDeviceBW); SetDispatchTableEntry(PVRSRV_BRIDGE_CLOSE_DISPCLASS_DEVICE, PVRSRVCloseDCDeviceBW); SetDispatchTableEntry(PVRSRV_BRIDGE_ENUM_DISPCLASS_FORMATS, PVRSRVEnumDCFormatsBW); SetDispatchTableEntry(PVRSRV_BRIDGE_ENUM_DISPCLASS_DIMS, PVRSRVEnumDCDimsBW); +#if defined(SUPPORT_PVRSRV_GET_DC_SYSTEM_BUFFER) SetDispatchTableEntry(PVRSRV_BRIDGE_GET_DISPCLASS_SYSBUFFER, PVRSRVGetDCSystemBufferBW); +#else + SetDispatchTableEntry(PVRSRV_BRIDGE_GET_DISPCLASS_SYSBUFFER, DummyBW); +#endif SetDispatchTableEntry(PVRSRV_BRIDGE_GET_DISPCLASS_INFO, PVRSRVGetDCInfoBW); SetDispatchTableEntry(PVRSRV_BRIDGE_CREATE_DISPCLASS_SWAPCHAIN, PVRSRVCreateDCSwapChainBW); SetDispatchTableEntry(PVRSRV_BRIDGE_DESTROY_DISPCLASS_SWAPCHAIN, PVRSRVDestroyDCSwapChainBW); @@ -4728,28 +5295,29 @@ CommonBridgeInit(IMG_VOID) SetDispatchTableEntry(PVRSRV_BRIDGE_SET_DISPCLASS_SRCCOLOURKEY, PVRSRVSetDCSrcColourKeyBW); SetDispatchTableEntry(PVRSRV_BRIDGE_GET_DISPCLASS_BUFFERS, PVRSRVGetDCBuffersBW); SetDispatchTableEntry(PVRSRV_BRIDGE_SWAP_DISPCLASS_TO_BUFFER, PVRSRVSwapToDCBufferBW); + SetDispatchTableEntry(PVRSRV_BRIDGE_SWAP_DISPCLASS_TO_BUFFER2, PVRSRVSwapToDCBuffer2BW); SetDispatchTableEntry(PVRSRV_BRIDGE_SWAP_DISPCLASS_TO_SYSTEM, PVRSRVSwapToDCSystemBW); - + /* buffer class API */ SetDispatchTableEntry(PVRSRV_BRIDGE_OPEN_BUFFERCLASS_DEVICE, PVRSRVOpenBCDeviceBW); SetDispatchTableEntry(PVRSRV_BRIDGE_CLOSE_BUFFERCLASS_DEVICE, PVRSRVCloseBCDeviceBW); SetDispatchTableEntry(PVRSRV_BRIDGE_GET_BUFFERCLASS_INFO, PVRSRVGetBCInfoBW); SetDispatchTableEntry(PVRSRV_BRIDGE_GET_BUFFERCLASS_BUFFER, PVRSRVGetBCBufferBW); - + /* Wrap/Unwrap external memory */ SetDispatchTableEntry(PVRSRV_BRIDGE_WRAP_EXT_MEMORY, PVRSRVWrapExtMemoryBW); SetDispatchTableEntry(PVRSRV_BRIDGE_UNWRAP_EXT_MEMORY, PVRSRVUnwrapExtMemoryBW); - + /* Shared memory */ SetDispatchTableEntry(PVRSRV_BRIDGE_ALLOC_SHARED_SYS_MEM, PVRSRVAllocSharedSysMemoryBW); SetDispatchTableEntry(PVRSRV_BRIDGE_FREE_SHARED_SYS_MEM, PVRSRVFreeSharedSysMemoryBW); SetDispatchTableEntry(PVRSRV_BRIDGE_MAP_MEMINFO_MEM, PVRSRVMapMemInfoMemBW); - + /* Intialisation Service support */ SetDispatchTableEntry(PVRSRV_BRIDGE_INITSRV_CONNECT, &PVRSRVInitSrvConnectBW); SetDispatchTableEntry(PVRSRV_BRIDGE_INITSRV_DISCONNECT, &PVRSRVInitSrvDisconnectBW); - + /* Event Object */ SetDispatchTableEntry(PVRSRV_BRIDGE_EVENT_OBJECT_WAIT, &PVRSRVEventObjectWaitBW); SetDispatchTableEntry(PVRSRV_BRIDGE_EVENT_OBJECT_OPEN, &PVRSRVEventObjectOpenBW); SetDispatchTableEntry(PVRSRV_BRIDGE_EVENT_OBJECT_CLOSE, &PVRSRVEventObjectCloseBW); @@ -4775,9 +5343,11 @@ CommonBridgeInit(IMG_VOID) SetMSVDXDispatchTableEntry(); #endif - - - + /* A safety net to help ensure there won't be any un-initialised dispatch + * table entries... */ + /* Note: This is specifically done _after_ setting all the dispatch entries + * so that SetDispatchTableEntry can detect mistakes where entries + * overlap */ for(i=0;i<BRIDGE_DISPATCH_TABLE_ENTRY_COUNT;i++) { if(!g_BridgeDispatchTable[i].pfFunction) @@ -4797,9 +5367,8 @@ CommonBridgeInit(IMG_VOID) } IMG_INT BridgedDispatchKM(PVRSRV_PER_PROCESS_DATA * psPerProc, - PVRSRV_BRIDGE_PACKAGE * psBridgePackageKM) + PVRSRV_BRIDGE_PACKAGE * psBridgePackageKM) { - IMG_VOID * psBridgeIn; IMG_VOID * psBridgeOut; BridgeWrapperFunction pfBridgeHandler; @@ -4838,7 +5407,7 @@ IMG_INT BridgedDispatchKM(PVRSRV_PER_PROCESS_DATA * psPerProc, } else { - + /* Only certain operations are allowed */ switch(ui32BridgeID) { case PVRSRV_GET_BRIDGE_ID(PVRSRV_BRIDGE_CONNECT_SERVICES): @@ -4855,20 +5424,18 @@ IMG_INT BridgedDispatchKM(PVRSRV_PER_PROCESS_DATA * psPerProc, } } - - #if defined(__linux__) { - + /* This should be moved into the linux specific code */ SYS_DATA *psSysData; SysAcquireData(&psSysData); - + /* We have already set up some static buffers to store our ioctl data... */ psBridgeIn = ((ENV_DATA *)psSysData->pvEnvSpecificData)->pvBridgeData; psBridgeOut = (IMG_PVOID)((IMG_PBYTE)psBridgeIn + PVRSRV_MAX_BRIDGE_IN_SIZE); - + /* check we are not using a bigger bridge than allocated */ if((psBridgePackageKM->ui32InBufferSize > PVRSRV_MAX_BRIDGE_IN_SIZE) || (psBridgePackageKM->ui32OutBufferSize > PVRSRV_MAX_BRIDGE_OUT_SIZE)) { @@ -4909,26 +5476,17 @@ IMG_INT BridgedDispatchKM(PVRSRV_PER_PROCESS_DATA * psPerProc, } pfBridgeHandler = (BridgeWrapperFunction)g_BridgeDispatchTable[ui32BridgeID].pfFunction; - if(ui32BridgeID >= (BRIDGE_DISPATCH_TABLE_ENTRY_COUNT)) - { - PVR_DPF((PVR_DBG_ERROR, "%s: ui32BridgeID = %d is out if range!", - __FUNCTION__, ui32BridgeID)); - goto return_fault; - } - pfBridgeHandler = - (BridgeWrapperFunction)g_BridgeDispatchTable[ui32BridgeID].pfFunction; - err = pfBridgeHandler(ui32BridgeID, - psBridgeIn, - psBridgeOut, - psPerProc); - if(err < 0) - { - goto return_fault; - } - + err = pfBridgeHandler(ui32BridgeID, + psBridgeIn, + psBridgeOut, + psPerProc); + if(err < 0) + { + goto return_fault; + } #if defined(__linux__) - + /* This should be moved into the linux specific code */ if(CopyToUserWrapper(psPerProc, ui32BridgeID, psBridgePackageKM->pvParamOut, @@ -4947,3 +5505,6 @@ return_fault: return err; } +/****************************************************************************** + End of file (bridged_pvr_bridge.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/bridged/bridged_pvr_bridge.h b/sgx/services4/srvkm/bridged/bridged_pvr_bridge.h index 6b0dd88..131cecd 100644 --- a/sgx/services4/srvkm/bridged/bridged_pvr_bridge.h +++ b/sgx/services4/srvkm/bridged/bridged_pvr_bridge.h @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title PVR Bridge Functionality +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Header for the PVR Bridge code +@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. + +*/ /**************************************************************************/ #ifndef __BRIDGED_PVR_BRIDGE_H__ #define __BRIDGED_PVR_BRIDGE_H__ @@ -138,11 +155,11 @@ ReleaseHandleBatch(PVRSRV_PER_PROCESS_DATA *psPerProc) PVRSRVReleaseHandleBatch(psPerProc->psHandleBase); } } -#else +#else /* defined(PVR_SECURE_HANDLES) */ #define NEW_HANDLE_BATCH_OR_ERROR(error, psPerProc, ui32BatchSize) #define COMMIT_HANDLE_BATCH_OR_ERROR(error, psPerProc) #define ReleaseHandleBatch(psPerProc) -#endif +#endif /* defined(PVR_SECURE_HANDLES) */ IMG_INT DummyBW(IMG_UINT32 ui32BridgeID, @@ -157,13 +174,16 @@ typedef IMG_INT (*BridgeWrapperFunction)(IMG_UINT32 ui32BridgeID, typedef struct _PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY { - BridgeWrapperFunction pfFunction; + BridgeWrapperFunction pfFunction; /*!< The wrapper function that validates the ioctl + arguments before calling into srvkm proper */ #if defined(DEBUG_BRIDGE_KM) - const IMG_CHAR *pszIOCName; - const IMG_CHAR *pszFunctionName; - IMG_UINT32 ui32CallCount; - IMG_UINT32 ui32CopyFromUserTotalBytes; - IMG_UINT32 ui32CopyToUserTotalBytes; + const IMG_CHAR *pszIOCName; /*!< Name of the ioctl: e.g. "PVRSRV_BRIDGE_CONNECT_SERVICES" */ + const IMG_CHAR *pszFunctionName; /*!< Name of the wrapper function: e.g. "PVRSRVConnectBW" */ + IMG_UINT32 ui32CallCount; /*!< The total number of times the ioctl has been called */ + IMG_UINT32 ui32CopyFromUserTotalBytes; /*!< The total number of bytes copied from + userspace within this ioctl */ + IMG_UINT32 ui32CopyToUserTotalBytes; /*!< The total number of bytes copied from + userspace within this ioctl */ #endif }PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY; @@ -194,7 +214,7 @@ _SetDispatchTableEntry(IMG_UINT32 ui32Index, const IMG_CHAR *pszFunctionName); - +/* PRQA S 0884,3410 2*/ /* macro relies on the lack of brackets */ #define SetDispatchTableEntry(ui32Index, pfFunction) \ _SetDispatchTableEntry(PVRSRV_GET_BRIDGE_ID(ui32Index), #ui32Index, (BridgeWrapperFunction)pfFunction, #pfFunction) @@ -215,6 +235,9 @@ typedef struct _PVRSRV_BRIDGE_GLOBAL_STATS IMG_UINT32 ui32TotalCopyToUserBytes; }PVRSRV_BRIDGE_GLOBAL_STATS; +/* OS specific code way want to report the stats held here and within the + * BRIDGE_DISPATCH_TABLE_ENTRYs (E.g. on Linux we report these via a + * proc entry /proc/pvr/bridge_stats. Ref printLinuxBridgeStats()) */ extern PVRSRV_BRIDGE_GLOBAL_STATS g_BridgeGlobalStats; #endif @@ -228,5 +251,8 @@ IMG_INT BridgedDispatchKM(PVRSRV_PER_PROCESS_DATA * psPerProc, } #endif -#endif +#endif /* __BRIDGED_PVR_BRIDGE_H__ */ +/****************************************************************************** + End of file (bridged_pvr_bridge.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/bridged/bridged_support.c b/sgx/services4/srvkm/bridged/bridged_support.c index dad0800..bd17e91 100644 --- a/sgx/services4/srvkm/bridged/bridged_support.c +++ b/sgx/services4/srvkm/bridged/bridged_support.c @@ -1,34 +1,57 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title PVR Bridge Support Functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description User/kernel mode bridge support. The functions in here + may be used beyond the bridge code proper (e.g. Linux + mmap interface). +@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 "img_defs.h" #include "servicesint.h" #include "bridged_support.h" +/* + * Derive the internal OS specific memory handle from a secure + * handle. + */ PVRSRV_ERROR #if defined (SUPPORT_SID_INTERFACE) PVRSRVLookupOSMemHandle(PVRSRV_HANDLE_BASE *psHandleBase, IMG_HANDLE *phOSMemHandle, IMG_SID hMHandle) @@ -40,7 +63,10 @@ PVRSRVLookupOSMemHandle(PVRSRV_HANDLE_BASE *psHandleBase, IMG_HANDLE *phOSMemHan PVRSRV_HANDLE_TYPE eHandleType; PVRSRV_ERROR eError; - + /* + * We don't know the type of the handle at this point, so we use + * PVRSRVLookupHandleAnyType to look it up. + */ eError = PVRSRVLookupHandleAnyType(psHandleBase, &hMHandleInt, &eHandleType, hMHandle); @@ -87,3 +113,6 @@ PVRSRVLookupOSMemHandle(PVRSRV_HANDLE_BASE *psHandleBase, IMG_HANDLE *phOSMemHan return PVRSRV_OK; } +/****************************************************************************** + End of file (bridged_support.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/bridged/bridged_support.h b/sgx/services4/srvkm/bridged/bridged_support.h index d027290..9cd80f5 100644 --- a/sgx/services4/srvkm/bridged/bridged_support.h +++ b/sgx/services4/srvkm/bridged/bridged_support.h @@ -1,28 +1,47 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title PVR Bridge Support +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description User/kernel mode bridge support. The functions in here + may be used beyond the bridge code proper (e.g. Linux + mmap interface). +@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. + +*/ /**************************************************************************/ #ifndef __BRIDGED_SUPPORT_H__ #define __BRIDGED_SUPPORT_H__ @@ -33,6 +52,10 @@ extern "C" { #endif +/* + * Derive the internal OS specific memory handle from a secure + * handle. + */ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR PVRSRVLookupOSMemHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phOSMemHandle, IMG_SID hMHandle); #else @@ -43,5 +66,8 @@ PVRSRV_ERROR PVRSRVLookupOSMemHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phO } #endif -#endif +#endif /* __BRIDGED_SUPPORT_H__ */ +/****************************************************************************** + End of file (bridged_support.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/bridged/sgx/bridged_sgx_bridge.c b/sgx/services4/srvkm/bridged/sgx/bridged_sgx_bridge.c index c7472f0..625705b 100644 --- a/sgx/services4/srvkm/bridged/sgx/bridged_sgx_bridge.c +++ b/sgx/services4/srvkm/bridged/sgx/bridged_sgx_bridge.c @@ -1,28 +1,46 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title SGX Common Bridge Module (kernel side) +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Receives calls from the user portion of services and + despatches them to functions in the kernel portion. +@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. + +*/ /**************************************************************************/ @@ -103,7 +121,9 @@ SGXReleaseClientInfoBW(IMG_UINT32 ui32BridgeID, PVR_ASSERT(psDevInfo->ui32ClientRefCount > 0); - + /* + * psDevInfo->ui32ClientRefCount can be zero if an error occurred before SGXGetClientInfo is called + */ if (psDevInfo->ui32ClientRefCount > 0) { psDevInfo->ui32ClientRefCount--; @@ -146,7 +166,10 @@ SGXGetInternalDevInfoBW(IMG_UINT32 ui32BridgeID, &psSGXGetInternalDevInfoOUT->sSGXInternalDevInfo); #endif - + /* + * Handle is not allocated in batch mode, as there is no resource + * allocation to undo if the handle allocation fails. + */ psSGXGetInternalDevInfoOUT->eError = PVRSRVAllocHandle(psPerProc->psHandleBase, &psSGXGetInternalDevInfoOUT->sSGXInternalDevInfo.hHostCtlKernelMemInfoHandle, @@ -259,7 +282,7 @@ SGXDoKickBW(IMG_UINT32 ui32BridgeID, } #if defined(FIX_HW_BRN_31620) - + /* We need to lookup the mem context and pass it through */ psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &psDoKickIN->sCCBKick.hDevMemContext, @@ -296,7 +319,7 @@ SGXDoKickBW(IMG_UINT32 ui32BridgeID, #if defined(SUPPORT_SGX_GENERALISED_SYNCOBJECTS) - + /* SRC and DST sync details */ if (psDoKickIN->sCCBKick.ui32NumTASrcSyncs > SGX_MAX_TA_SRC_SYNCS) { psRetOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; @@ -377,9 +400,9 @@ SGXDoKickBW(IMG_UINT32 ui32BridgeID, return 0; } } -#else - - if (psDoKickIN->sCCBKick.ui32NumSrcSyncs > SGX_MAX_SRC_SYNCS) +#else/* #if defined(SUPPORT_SGX_GENERALISED_SYNCOBJECTS) */ + /* texture dependency details */ + if (psDoKickIN->sCCBKick.ui32NumSrcSyncs > SGX_MAX_SRC_SYNCS_TA) { psRetOUT->eError = PVRSRV_ERROR_INVALID_PARAMS; return 0; @@ -405,7 +428,7 @@ SGXDoKickBW(IMG_UINT32 ui32BridgeID, return 0; } } -#endif +#endif/* #if defined(SUPPORT_SGX_GENERALISED_SYNCOBJECTS) */ if (psDoKickIN->sCCBKick.ui32NumTAStatusVals > SGX_MAX_TA_STATUS_VALS) { @@ -519,7 +542,7 @@ SGXDoKickBW(IMG_UINT32 ui32BridgeID, goto PVRSRV_BRIDGE_SGX_DOKICK_RETURN_RESULT; } - + /* Set sCCBKick.pahDstSyncHandles to point to the local memory */ psDoKickIN->sCCBKick.pahDstSyncHandles = phKernelSyncInfoHandles; #endif @@ -578,7 +601,7 @@ SGXDoKickBW(IMG_UINT32 ui32BridgeID, #if defined(NO_HARDWARE) sCCBKickKM.ui32WriteOpsPendingVal = psDoKickIN->sCCBKick.ui32WriteOpsPendingVal; #endif -#endif +#endif /* #if defined (SUPPORT_SID_INTERFACE) */ psRetOUT->eError = SGXDoKickKM(hDevCookieInt, #if defined (SUPPORT_SID_INTERFACE) @@ -589,13 +612,14 @@ SGXDoKickBW(IMG_UINT32 ui32BridgeID, PVRSRV_BRIDGE_SGX_DOKICK_RETURN_RESULT: +//#if (!defined(_UITRON_) && !defined(UNDER_VISTA)) || defined (SUPPORT_SID_INTERFACE) if(phKernelSyncInfoHandles) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32NumDstSyncs * sizeof(IMG_HANDLE), (IMG_VOID *)phKernelSyncInfoHandles, 0); - + /*not nulling pointer, out of scope*/ } return ret; } @@ -648,7 +672,7 @@ SGXSubmitTransferBW(IMG_UINT32 ui32BridgeID, psKick = &psSubmitTransferIN->sKick; #if defined(FIX_HW_BRN_31620) - + /* We need to lookup the mem context and pass it through */ psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &psKick->hDevMemContext, @@ -887,7 +911,7 @@ SGXSubmit2DBW(IMG_UINT32 ui32BridgeID, psKick = &psSubmit2DIN->sKick; #if defined(FIX_HW_BRN_31620) - + /* We need to lookup the mem context and pass it through */ psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &psKick->hDevMemContext, @@ -1039,7 +1063,7 @@ SGXSubmit2DBW(IMG_UINT32 ui32BridgeID, sKickKM.hDstSyncInfo = IMG_NULL; } - + /* copy common members across */ sKickKM.ui32SharedCmdCCBOffset = psKick->ui32SharedCmdCCBOffset; sKickKM.ui32NumSrcSync = psKick->ui32NumSrcSync; sKickKM.ui32PDumpFlags = psKick->ui32PDumpFlags; @@ -1058,8 +1082,8 @@ SGXSubmit2DBW(IMG_UINT32 ui32BridgeID, return 0; } -#endif -#endif +#endif /* #if defined(SGX_FEATURE_2D_HARDWARE) */ +#endif /* #if defined(TRANSFER_QUEUE) */ static IMG_INT @@ -1088,7 +1112,7 @@ SGXGetMiscInfoBW(IMG_UINT32 ui32BridgeID, } #if defined(SUPPORT_SGX_EDM_MEMORY_DEBUG) - + /* Lookup handle for dev mem context */ if (psSGXGetMiscInfoIN->psMiscInfo->eRequest == SGX_MISC_INFO_REQUEST_MEMREAD) { psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, @@ -1102,7 +1126,7 @@ SGXGetMiscInfoBW(IMG_UINT32 ui32BridgeID, } } #endif - + /* device node is required for scheduling a CCB command */ psDeviceNode = hDevCookieInt; PVR_ASSERT(psDeviceNode != IMG_NULL); if (psDeviceNode == IMG_NULL) @@ -1112,7 +1136,7 @@ SGXGetMiscInfoBW(IMG_UINT32 ui32BridgeID, psDevInfo = psDeviceNode->pvDevice; - + /* Copy psMiscInfo to kernel space */ psRetOUT->eError = CopyFromUserWrapper(psPerProc, ui32BridgeID, &sMiscInfo, @@ -1132,7 +1156,7 @@ SGXGetMiscInfoBW(IMG_UINT32 ui32BridgeID, } } - + /* Copy back misc info to user address space */ psRetOUT->eError = CopyToUserWrapper(psPerProc, ui32BridgeID, psSGXGetMiscInfoIN->psMiscInfo, @@ -1197,7 +1221,7 @@ SGXReadHWPerfCBBW(IMG_UINT32 ui32BridgeID, ui32AllocatedSize, psAllocated, hAllocatedHandle); - + /*not nulling pointer, out of scope*/ return 0; } @@ -1226,7 +1250,7 @@ SGXDevInitPart2BW(IMG_UINT32 ui32BridgeID, PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_SGX_DEVINITPART2); - + /* Report the kernel-side build options to UM */ psSGXDevInitPart2OUT->ui32KMBuildOptions = SGX_BUILD_OPTIONS; if(!psPerProc->bInitProcess) @@ -1245,7 +1269,7 @@ SGXDevInitPart2BW(IMG_UINT32 ui32BridgeID, return 0; } - + /* Check all the meminfo handles */ eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDummy, psSGXDevInitPart2IN->sInitInfo.hKernelCCBMemInfo, @@ -1374,7 +1398,7 @@ SGXDevInitPart2BW(IMG_UINT32 ui32BridgeID, #endif -#if defined(FIX_HW_BRN_31542) +#if defined(FIX_HW_BRN_31542) || defined(FIX_HW_BRN_36513) eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDummy, psSGXDevInitPart2IN->sInitInfo.hKernelClearClipWAVDMStreamMemInfo, @@ -1442,7 +1466,7 @@ SGXDevInitPart2BW(IMG_UINT32 ui32BridgeID, } #endif -#if defined(SGX_FEATURE_VDM_CONTEXT_SWITCH) && defined(FIX_HW_BRN_31425) +#if defined(SGX_FEATURE_VDM_CONTEXT_SWITCH) && defined(FIX_HW_BRN_31559) eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDummy, psSGXDevInitPart2IN->sInitInfo.hKernelVDMSnapShotBufferMemInfo, @@ -1518,7 +1542,7 @@ SGXDevInitPart2BW(IMG_UINT32 ui32BridgeID, return 0; } - + /* Lookup and release the device memory handles */ eError = PVRSRVLookupAndReleaseHandle(psPerProc->psHandleBase, #if defined (SUPPORT_SID_INTERFACE) &asInitInfoKM.hKernelCCBMemInfo, @@ -1701,7 +1725,7 @@ SGXDevInitPart2BW(IMG_UINT32 ui32BridgeID, #endif -#if defined(FIX_HW_BRN_31542) +#if defined(FIX_HW_BRN_31542) || defined(FIX_HW_BRN_36513) eError = PVRSRVLookupAndReleaseHandle(psPerProc->psHandleBase, #if defined (SUPPORT_SID_INTERFACE) &asInitInfoKM.hKernelClearClipWAVDMStreamMemInfo, @@ -1799,7 +1823,7 @@ SGXDevInitPart2BW(IMG_UINT32 ui32BridgeID, bReleaseFailed = IMG_TRUE; } #endif -#if defined(SGX_FEATURE_VDM_CONTEXT_SWITCH) && defined(FIX_HW_BRN_31425) +#if defined(SGX_FEATURE_VDM_CONTEXT_SWITCH) && defined(FIX_HW_BRN_31559) eError = PVRSRVLookupAndReleaseHandle(psPerProc->psHandleBase, &psSGXDevInitPart2IN->sInitInfo.hKernelVDMSnapShotBufferMemInfo, psSGXDevInitPart2IN->sInitInfo.hKernelVDMSnapShotBufferMemInfo, @@ -1878,12 +1902,15 @@ SGXDevInitPart2BW(IMG_UINT32 ui32BridgeID, { PVR_DPF((PVR_DBG_ERROR, "DevInitSGXPart2BW: A handle release failed")); psSGXDevInitPart2OUT->eError = PVRSRV_ERROR_INIT2_PHASE_FAILED; - + /* + * Given that we checked the handles before release, a release + * failure is unexpected. + */ PVR_DBG_BREAK; return 0; } - + /* Dissociate device memory from caller */ #if defined (SUPPORT_SID_INTERFACE) eError = PVRSRVDissociateDeviceMemKM(hDevCookieInt, asInitInfoKM.hKernelCCBMemInfo); #else @@ -1946,7 +1973,7 @@ SGXDevInitPart2BW(IMG_UINT32 ui32BridgeID, } #endif - + /* Dissociate SGX MiscInfo buffer from user space */ #if defined (SUPPORT_SID_INTERFACE) eError = PVRSRVDissociateDeviceMemKM(hDevCookieInt, asInitInfoKM.hKernelSGXMiscMemInfo); #else @@ -2029,7 +2056,7 @@ SGXDevInitPart2BW(IMG_UINT32 ui32BridgeID, #endif #endif -#if defined(FIX_HW_BRN_31542) +#if defined(FIX_HW_BRN_31542) || defined(FIX_HW_BRN_36513) #if defined (SUPPORT_SID_INTERFACE) eError = PVRSRVDissociateDeviceMemKM(hDevCookieInt, asInitInfoKM.hKernelClearClipWAVDMStreamMemInfo); if (eError != PVRSRV_OK) @@ -2112,7 +2139,7 @@ SGXDevInitPart2BW(IMG_UINT32 ui32BridgeID, #endif #endif -#if defined(SGX_FEATURE_VDM_CONTEXT_SWITCH) && defined(FIX_HW_BRN_31425) +#if defined(SGX_FEATURE_VDM_CONTEXT_SWITCH) && defined(FIX_HW_BRN_31559) eError = PVRSRVDissociateDeviceMemKM(hDevCookieInt, psSGXDevInitPart2IN->sInitInfo.hKernelVDMSnapShotBufferMemInfo); bDissociateFailed |= (IMG_BOOL)(eError != PVRSRV_OK); @@ -2156,7 +2183,7 @@ SGXDevInitPart2BW(IMG_UINT32 ui32BridgeID, } } - + /* If any dissociations failed, free all the device memory passed in */ if(bDissociateFailed) { #if defined (SUPPORT_SID_INTERFACE) @@ -2200,7 +2227,7 @@ SGXDevInitPart2BW(IMG_UINT32 ui32BridgeID, psSGXDevInitPart2OUT->eError = PVRSRV_ERROR_INIT2_PHASE_FAILED; - + /* A dissociation failure is unexpected */ PVR_DBG_BREAK; return 0; } @@ -2244,6 +2271,7 @@ SGXRegisterHWRenderContextBW(IMG_UINT32 ui32BridgeID, PVRSRV_PER_PROCESS_DATA *psPerProc) { IMG_HANDLE hDevCookieInt; +// PVRSRV_SGXDEV_INFO *psDevInfo; IMG_HANDLE hHWRenderContextInt; PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_SGX_REGISTER_HW_RENDER_CONTEXT); @@ -2498,7 +2526,7 @@ SGXUnregisterHW2DContextBW(IMG_UINT32 ui32BridgeID, return 0; } -#endif +#endif /* #if defined(SGX_FEATURE_2D_HARDWARE) */ static IMG_INT SGXFlushHWRenderTargetBW(IMG_UINT32 ui32BridgeID, @@ -2507,6 +2535,8 @@ SGXFlushHWRenderTargetBW(IMG_UINT32 ui32BridgeID, PVRSRV_PER_PROCESS_DATA *psPerProc) { IMG_HANDLE hDevCookieInt; +// PVRSRV_SGXDEV_INFO *psDevInfo; + PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_SGX_FLUSH_HW_RENDER_TARGET); psRetOUT->eError = @@ -2519,6 +2549,8 @@ SGXFlushHWRenderTargetBW(IMG_UINT32 ui32BridgeID, return 0; } +// psDevInfo = (PVRSRV_SGXDEV_INFO *)((PVRSRV_DEVICE_NODE *)hDevCookieInt)->pvDevice; + psRetOUT->eError = SGXFlushHWRenderTargetKM(hDevCookieInt, psSGXFlushHWRenderTargetIN->sHWRTDataSetDevVAddr, IMG_FALSE); return 0; @@ -2621,7 +2653,8 @@ SGXFindSharedPBDescBW(IMG_UINT32 ui32BridgeID, if(hSharedPBDesc == IMG_NULL) { psSGXFindSharedPBDescOUT->hSharedPBDescKernelMemInfoHandle = 0; - + /* It's not an error if we don't find a buffer, + * we just return NULL */ goto PVRSRV_BRIDGE_SGX_FINDSHAREDPBDESC_EXIT; } @@ -2631,7 +2664,12 @@ SGXFindSharedPBDescBW(IMG_UINT32 ui32BridgeID, PVRSRV_HANDLE_TYPE_SHARED_PB_DESC, PVRSRV_HANDLE_ALLOC_FLAG_NONE); - + /* + * We allocate handles of type PVRSRV_HANDLE_TYPE_MEM_INFO_REF here, + * as the process doesn't own the underlying memory, and so should + * only be allowed a restricted set of operations on it, such as + * mapping it into its address space. + */ PVRSRVAllocSubHandleNR(psPerProc->psHandleBase, &psSGXFindSharedPBDescOUT->hSharedPBDescKernelMemInfoHandle, psSharedPBDescKernelMemInfo, @@ -2868,26 +2906,30 @@ SGXAddSharedPBDescBW(IMG_UINT32 ui32BridgeID, } } - - + /* + * Release all the handles we've just looked up, as none + * of the associated resources will be valid for access via + * those handles once we return from SGXAddSharedPBDesc. + */ + /* PRQA S 3198 2 */ /* override redundant warning as PVR_ASSERT is ignored by QAC */ eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, psSGXAddSharedPBDescIN->hSharedPBDescKernelMemInfo, PVRSRV_HANDLE_TYPE_SHARED_SYS_MEM_INFO); PVR_ASSERT(eError == PVRSRV_OK); - + /* PRQA S 3198 2 */ /* override redundant warning as PVR_ASSERT is ignored by QAC */ eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, psSGXAddSharedPBDescIN->hHWPBDescKernelMemInfo, PVRSRV_HANDLE_TYPE_MEM_INFO); PVR_ASSERT(eError == PVRSRV_OK); - + /* PRQA S 3198 2 */ /* override redundant warning as PVR_ASSERT is ignored by QAC */ eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, psSGXAddSharedPBDescIN->hBlockKernelMemInfo, PVRSRV_HANDLE_TYPE_SHARED_SYS_MEM_INFO); PVR_ASSERT(eError == PVRSRV_OK); - + /* PRQA S 3198 2 */ /* override redundant warning as PVR_ASSERT is ignored by QAC */ eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, psSGXAddSharedPBDescIN->hHWBlockKernelMemInfo, PVRSRV_HANDLE_TYPE_MEM_INFO); @@ -2895,7 +2937,7 @@ SGXAddSharedPBDescBW(IMG_UINT32 ui32BridgeID, for(i=0; i<ui32KernelMemInfoHandlesCount; i++) { - + /* PRQA S 3198 2 */ /* override redundant warning as PVR_ASSERT is ignored by QAC */ eError = PVRSRVReleaseHandle(psPerProc->psHandleBase, phKernelMemInfoHandles[i], PVRSRV_HANDLE_TYPE_MEM_INFO); @@ -3007,7 +3049,7 @@ SGXGetInfoForSrvinitBW(IMG_UINT32 ui32BridgeID, if ((asHeapInfo[i].ui32HeapID != (IMG_UINT32)SGX_UNDEFINED_HEAP_ID) && (asHeapInfo[i].hDevMemHeap != IMG_NULL)) { - + /* Allocate heap handle */ PVRSRVAllocHandleNR(psPerProc->psHandleBase, &psHeapInfo->hDevMemHeap, asHeapInfo[i].hDevMemHeap, @@ -3031,7 +3073,7 @@ SGXGetInfoForSrvinitBW(IMG_UINT32 ui32BridgeID, if (psHeapInfo->hDevMemHeap != IMG_NULL) { - + /* Allocate heap handle */ PVRSRVAllocHandleNR(psPerProc->psHandleBase, &hDevMemHeapExt, psHeapInfo->hDevMemHeap, @@ -3049,6 +3091,13 @@ SGXGetInfoForSrvinitBW(IMG_UINT32 ui32BridgeID, } #if defined(PDUMP) +// PRQA S 5120++ +/***************************************************************************** + FUNCTION : DumpBufferArray + PURPOSE : PDUMP information in stored buffer array + PARAMETERS : + RETURNS : +*****************************************************************************/ static IMG_VOID DumpBufferArray(PVRSRV_PER_PROCESS_DATA *psPerProc, #if defined (SUPPORT_SID_INTERFACE) @@ -3116,7 +3165,9 @@ DumpBufferArray(PVRSRV_PER_PROCESS_DATA *psPerProc, } else { - + /* + Range of data wraps the end of the buffer so it needs to be dumped in two sections + */ if (bDumpPolls) { @@ -3181,6 +3232,11 @@ SGXPDumpBufferArrayBW(IMG_UINT32 ui32BridgeID, SGX_KICKTA_DUMP_BUFFER *psUMPtr; SGX_KICKTA_DUMP_BUFFER_KM *psKickTADumpBufferKM, *psKMPtr; #else +#if defined(__QNXNTO__) + const IMG_UINT32 NAME_BUFFER_SIZE = 30; + IMG_PCHAR pszNameBuffer, pszName; + IMG_UINT32 ui32NameBufferArraySize, ui32NameLength; +#endif SGX_KICKTA_DUMP_BUFFER *psKickTADumpBuffer; #endif IMG_UINT32 ui32BufferArrayLength = @@ -3189,12 +3245,6 @@ SGXPDumpBufferArrayBW(IMG_UINT32 ui32BridgeID, ui32BufferArrayLength * sizeof(SGX_KICKTA_DUMP_BUFFER); PVRSRV_ERROR eError = PVRSRV_ERROR_TOO_FEW_BUFFERS; -#if defined (__QNXNTO__) - const IMG_UINT32 MAX_BUFFER_NAME_SIZE = 30; - IMG_PCHAR pszNamesBuffer, pszName; - IMG_UINT32 ui32NameBufferArraySize; -#endif - PVR_UNREFERENCED_PARAMETER(psBridgeOut); PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_SGX_PDUMP_BUFFER_ARRAY); @@ -3222,39 +3272,49 @@ SGXPDumpBufferArrayBW(IMG_UINT32 ui32BridgeID, ui32BufferArraySize) != PVRSRV_OK) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32BufferArraySize, psKickTADumpBuffer, 0); - + /*not nulling pointer, out of scope*/ return -EFAULT; } -#endif #if defined (__QNXNTO__) - ui32NameBufferArraySize = ui32BufferArrayLength * MAX_BUFFER_NAME_SIZE; + ui32NameBufferArraySize = ui32BufferArrayLength * NAME_BUFFER_SIZE; if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, ui32NameBufferArraySize, - (IMG_PVOID *)&pszNamesBuffer, 0, + (IMG_PVOID *)&pszNameBuffer, 0, "Kick Tile Accelerator Dump Buffer names") != PVRSRV_OK) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32BufferArraySize, psKickTADumpBuffer, 0); return -ENOMEM; } - pszName = pszNamesBuffer; + pszName = pszNameBuffer; + for (i=0; i<ui32BufferArrayLength; i++) { - if (CopyFromUserWrapper(psPerProc, ui32BridgeID, - pszName, psKickTADumpBuffer[i].pszName, - MAX_BUFFER_NAME_SIZE) != PVRSRV_OK) + if (psKickTADumpBuffer[i].pszName) { - PVR_DPF((PVR_DBG_WARNING, "Failed to read pdump buffer name")); - psKickTADumpBuffer[i].pszName = 0; + ui32NameLength = psKickTADumpBuffer[i].ui32NameLength; + if (ui32NameLength >= NAME_BUFFER_SIZE) + { + ui32NameLength = NAME_BUFFER_SIZE - 1; + } + + if (ui32NameLength && + (CopyFromUserWrapper(psPerProc, ui32BridgeID, pszName, + psKickTADumpBuffer[i].pszName, ui32NameLength + 1) == PVRSRV_OK)) + { + pszName[NAME_BUFFER_SIZE - 1] = 0; + psKickTADumpBuffer[i].pszName = pszName; + pszName += NAME_BUFFER_SIZE; + } + else + { + PVR_DPF((PVR_DBG_WARNING, "Failed to read PDUMP buffer name")); + psKickTADumpBuffer[i].pszName = 0; + } } - else - { - pszName[MAX_BUFFER_NAME_SIZE-1] = 0; - psKickTADumpBuffer[i].pszName = pszName; - } - pszName += MAX_BUFFER_NAME_SIZE; } #endif +#endif for(i = 0; i < ui32BufferArrayLength; i++) { @@ -3339,12 +3399,11 @@ SGXPDumpBufferArrayBW(IMG_UINT32 ui32BridgeID, OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32BufferArraySize, psKickTADumpBufferKM, 0); #else OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32BufferArraySize, psKickTADumpBuffer, 0); -#endif - - #if defined (__QNXNTO__) - OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32NameBufferArraySize, pszNamesBuffer, 0); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32NameBufferArraySize, pszNameBuffer, 0); #endif +#endif + /*not nulling pointer, out of scope*/ return 0; } @@ -3389,7 +3448,7 @@ SGXPDump3DSignatureRegistersBW(IMG_UINT32 ui32BridgeID, psDevInfo = (PVRSRV_SGXDEV_INFO*)psDeviceNode->pvDevice; #if defined(SGX_FEATURE_MP) && defined(FIX_HW_BRN_27270) - + /* Enable all cores available */ ui32RegVal = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_CORE); OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_CORE, (SGX_FEATURE_MP_CORE_COUNT - 1) << EUR_CR_MASTER_CORE_ENABLE_SHIFT); #if defined(PDUMP) @@ -3433,8 +3492,8 @@ SGXPDump3DSignatureRegistersBW(IMG_UINT32 ui32BridgeID, return 0; } - - PVR_ASSERT(psDeviceNode->pfnMMUGetContextID != IMG_NULL) + /* look up the MMU context ID */ + PVR_ASSERT(psDeviceNode->pfnMMUGetContextID != IMG_NULL); ui32MMUContextID = psDeviceNode->pfnMMUGetContextID((IMG_HANDLE)psDeviceNode->sDevMemoryInfo.pBMKernelContext); PDumpSignatureBuffer(&psDeviceNode->sDevId, @@ -3442,13 +3501,13 @@ SGXPDump3DSignatureRegistersBW(IMG_UINT32 ui32BridgeID, psDevInfo->psKernelTASigBufferMemInfo->sDevVAddr, (IMG_UINT32)psDevInfo->psKernelTASigBufferMemInfo->uAllocSize, ui32MMUContextID, - 0 ); + 0 /*ui32PDumpFlags*/); PDumpSignatureBuffer(&psDeviceNode->sDevId, "out.3dsig", "3D", 0, psDevInfo->psKernel3DSigBufferMemInfo->sDevVAddr, (IMG_UINT32)psDevInfo->psKernel3DSigBufferMemInfo->uAllocSize, ui32MMUContextID, - 0 ); + 0 /*ui32PDumpFlags*/); ExitNoError: psRetOUT->eError = PVRSRV_OK; @@ -3578,7 +3637,7 @@ SGXPDumpTASignatureRegistersBW(IMG_UINT32 ui32BridgeID, psDevInfo = (PVRSRV_SGXDEV_INFO*)psDeviceNode->pvDevice; - + /* Enable all cores available */ ui32RegVal = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_CORE); OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_CORE, (SGX_FEATURE_MP_CORE_COUNT - 1) << EUR_CR_MASTER_CORE_ENABLE_SHIFT); #if defined(PDUMP) @@ -3636,6 +3695,9 @@ Exit: return ret; } +//PRQA S 5120-- + + static IMG_INT SGXPDumpHWPerfCBBW(IMG_UINT32 ui32BridgeID, PVRSRV_BRIDGE_IN_PDUMP_HWPERFCB *psPDumpHWPerfCBIN, @@ -3672,8 +3734,8 @@ SGXPDumpHWPerfCBBW(IMG_UINT32 ui32BridgeID, return 0; } - - PVR_ASSERT(psDeviceNode->pfnMMUGetContextID != IMG_NULL) + /* look up the MMU context ID */ + PVR_ASSERT(psDeviceNode->pfnMMUGetContextID != IMG_NULL); ui32MMUContextID = psDeviceNode->pfnMMUGetContextID(hDevMemContextInt); PDumpHWPerfCBKM(&psDeviceNode->sDevId, @@ -3691,14 +3753,14 @@ SGXPDumpHWPerfCBBW(IMG_UINT32 ui32BridgeID, PVR_UNREFERENCED_PARAMETER(psRetOUT); PVR_UNREFERENCED_PARAMETER(psPerProc); return 0; -#endif +#endif /* defined(LINUX) || defined(UNDER_XP) */ #else PVR_UNREFERENCED_PARAMETER(ui32BridgeID); PVR_UNREFERENCED_PARAMETER(psPDumpHWPerfCBIN); PVR_UNREFERENCED_PARAMETER(psRetOUT); PVR_UNREFERENCED_PARAMETER(psPerProc); return -EFAULT; -#endif +#endif /* defined(SUPPORT_SGX_HWPERF) */ } @@ -3734,8 +3796,8 @@ SGXPDumpSaveMemBW(IMG_UINT32 ui32BridgeID, return 0; } - - PVR_ASSERT(psDeviceNode->pfnMMUGetContextID != IMG_NULL) + /* look up the MMU context ID */ + PVR_ASSERT(psDeviceNode->pfnMMUGetContextID != IMG_NULL); ui32MMUContextID = psDeviceNode->pfnMMUGetContextID(hDevMemContextInt); PDumpSaveMemKM(&psDeviceNode->sDevId, @@ -3748,10 +3810,10 @@ SGXPDumpSaveMemBW(IMG_UINT32 ui32BridgeID, return 0; } -#endif +#endif /* PDUMP */ - +/* PRQA S 0313,3635 END_SET_SGX */ /* function macro required this format */ IMG_VOID SetSGXDispatchTableEntry(IMG_VOID) { @@ -3800,6 +3862,6 @@ IMG_VOID SetSGXDispatchTableEntry(IMG_VOID) SetDispatchTableEntry(PVRSRV_BRIDGE_SGX_PDUMP_SAVEMEM, SGXPDumpSaveMemBW); #endif } - +/* PRQA L:END_SET_SGX */ /* end of setup overrides */ -#endif +#endif /* SUPPORT_SGX */ diff --git a/sgx/services4/srvkm/bridged/sgx/bridged_sgx_bridge.h b/sgx/services4/srvkm/bridged/sgx/bridged_sgx_bridge.h index 204450c..02ea7c4 100644 --- a/sgx/services4/srvkm/bridged/sgx/bridged_sgx_bridge.h +++ b/sgx/services4/srvkm/bridged/sgx/bridged_sgx_bridge.h @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title SGX Bridge Functionality +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Header for the PVR Bridge code +@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. + +*/ /**************************************************************************/ #ifndef __BRIDGED_SGX_BRIDGE_H__ #define __BRIDGED_SGX_BRIDGE_H__ @@ -38,5 +55,8 @@ IMG_VOID SetSGXDispatchTableEntry(IMG_VOID); } #endif -#endif +#endif /* __BRIDGED_SGX_BRIDGE_H__ */ +/****************************************************************************** + End of file (bridged_sgx_bridge.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/common/buffer_manager.c b/sgx/services4/srvkm/common/buffer_manager.c index e92fa6c..45d63b4 100644 --- a/sgx/services4/srvkm/common/buffer_manager.c +++ b/sgx/services4/srvkm/common/buffer_manager.c @@ -1,28 +1,46 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Buffer management functions for Linux +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Manages buffers mapped into two memory spaces - cpu and device, + either of which can be virtual or physical. +@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 "services_headers.h" @@ -38,8 +56,9 @@ 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_UINTPTR_T *pBase); + 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, @@ -51,14 +70,53 @@ DevMemoryAlloc (BM_CONTEXT *pBMContext, static IMG_VOID DevMemoryFree (BM_MAPPING *pMapping); +/*! +****************************************************************************** + + @Function AllocMemory + + @Description Allocate a buffer mapped into both cpu and device virtual + address spaces. This is now quite simple: + + 1. Choose whence to get the memory; + 2. Obtain memory from that source; + 3. Work out the actual buffer addresses in other spaces. + + In choosing whence to get the memory we work like this: + + 1. If an import arena exists, use unless BP_CONTIGUOUS is set; + 2. Use a contiguous pool. + + @Input pBMContext - BM context + @Input psBMHeap - BM heap + @Input psDevVAddr - device virtual address (optional) + @Input uSize - requested buffer size in bytes. + @Input uFlags - property flags for the buffer. + @Input uDevVAddrAlignment - required device virtual address + alignment, or 0. + @Input pvPrivData - opaque private data passed through to allocator + @Input ui32PrivDataLength - length of opaque private data + + @Output pBuf - receives a pointer to a descriptor of the allocated + buffer. + @Return IMG_TRUE - Success + IMG_FALSE - Failed. + + *****************************************************************************/ static IMG_BOOL -AllocMemory (BM_CONTEXT *pBMContext, - BM_HEAP *psBMHeap, - IMG_DEV_VIRTADDR *psDevVAddr, - IMG_SIZE_T uSize, - IMG_UINT32 uFlags, - IMG_UINT32 uDevVAddrAlignment, - BM_BUF *pBuf) +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, + IMG_UINT32 ui32ChunkSize, + IMG_UINT32 ui32NumVirtChunks, + IMG_UINT32 ui32NumPhysChunks, + IMG_BOOL *pabMapChunk, + BM_BUF *pBuf) { BM_MAPPING *pMapping; IMG_UINTPTR_T uOffset; @@ -68,16 +126,18 @@ AllocMemory (BM_CONTEXT *pBMContext, "AllocMemory (uSize=0x%x, uFlags=0x%x, align=0x%x)", uSize, uFlags, uDevVAddrAlignment)); - - - + /* + what to do depends on combination of DevVaddr generation + and backing RAM requirement + */ if (uFlags & PVRSRV_HAP_GPU_PAGEABLE) { /* in case of a pageable buffer, we must bypass RA which could * combine/split individual mappings between buffers: */ if (!BM_ImportMemory(psBMHeap, uSize, IMG_NULL, &pMapping, - uFlags, (IMG_UINTPTR_T *)&(pBuf->DevVAddr.uiAddr))) + uFlags, NULL, 0, + (IMG_UINTPTR_T *)&(pBuf->DevVAddr.uiAddr))) { PVR_DPF ((PVR_DBG_ERROR, "AllocMemory: failed")); return IMG_FALSE; @@ -88,19 +148,19 @@ AllocMemory (BM_CONTEXT *pBMContext, { if(uFlags & PVRSRV_MEM_USER_SUPPLIED_DEVVADDR) { - + /* user supplied DevVAddr, RAM backing */ PVR_DPF ((PVR_DBG_ERROR, "AllocMemory: combination of DevVAddr management and RAM backing mode unsupported")); return IMG_FALSE; } - + /* BM supplied DevVAddr, RAM Backing */ - + /* check heap attributes */ if(psBMHeap->ui32Attribs & (PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG |PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG)) { - + /* specify arena (VM+RAM)*/ pArena = psBMHeap->pImportArena; PVR_ASSERT(psBMHeap->sDevArena.psDeviceMemoryHeapInfo->ui32Attribs & PVRSRV_MEM_RAM_BACKED_ALLOCATION); } @@ -110,18 +170,76 @@ AllocMemory (BM_CONTEXT *pBMContext, return IMG_FALSE; } + /* Now allocate from the arena we chose above. */ + if (uFlags & PVRSRV_MEM_SPARSE) + { + IMG_BOOL bSuccess; + IMG_SIZE_T puiActualSize; + + /* Allocate physcial memory */ + bSuccess = BM_ImportMemory(psBMHeap, + ui32ChunkSize * ui32NumPhysChunks, + &puiActualSize, + &pMapping, + uFlags, + pvPrivData, + ui32PrivDataLength, + IMG_NULL); /* We allocate VM space */ + + if (puiActualSize != ui32ChunkSize * ui32NumPhysChunks) + { + /* + Most likley the chunksize was not host page multiple so + return with an error + */ + PVR_DPF((PVR_DBG_ERROR, "AllocMemory: Failed to allocate memory for sparse allocation")); + BM_FreeMemory(pArena, IMG_NULL, pMapping); + return IMG_FALSE; + } + + pMapping->uSizeVM = ui32ChunkSize * ui32NumVirtChunks; + uSize = pMapping->uSizeVM; + pMapping->ui32ChunkSize = ui32ChunkSize; + pMapping->ui32NumVirtChunks = ui32NumVirtChunks; + pMapping->ui32NumPhysChunks = ui32NumPhysChunks; + pMapping->pabMapChunk = pabMapChunk; + + /* Allocate VA space and map in the physical memory */ + bSuccess = DevMemoryAlloc (pBMContext, + pMapping, + IMG_NULL, + uFlags, + (IMG_UINT32)uDevVAddrAlignment, + &pMapping->DevVAddr); + if (!bSuccess) + { + PVR_DPF((PVR_DBG_ERROR, + "AllocMemory: Failed to allocate device memory")); + BM_FreeMemory(pArena, IMG_NULL, pMapping); + return IMG_FALSE; + } - if (!RA_Alloc(pArena, - uSize, - IMG_NULL, - (IMG_VOID*) &pMapping, - uFlags, - uDevVAddrAlignment, - 0, - (IMG_UINTPTR_T *)&(pBuf->DevVAddr.uiAddr))) - { - PVR_DPF((PVR_DBG_ERROR, "AllocMemory: RA_Alloc(0x%x) FAILED", uSize)); - return IMG_FALSE; + /* uDevVAddrAlignment is currently set to zero so QAC generates warning which we override */ + /* PRQA S 3356,3358 1 */ + PVR_ASSERT (uDevVAddrAlignment>1?(pMapping->DevVAddr.uiAddr%uDevVAddrAlignment)==0:1); + pBuf->DevVAddr.uiAddr = pMapping->DevVAddr.uiAddr; + } + else + { + 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; @@ -134,7 +252,7 @@ AllocMemory (BM_CONTEXT *pBMContext, pBuf->CpuVAddr = IMG_NULL; } - if(uSize == pMapping->uSize) + if(uSize == pMapping->uSizeVM) { pBuf->hOSMemHandle = pMapping->hOSMemHandle; } @@ -151,7 +269,8 @@ AllocMemory (BM_CONTEXT *pBMContext, } } - + /* for hm_contiguous and hm_wrapped memory, the pMapping + * will have a physical address, else 0 */ pBuf->CpuPAddr.uiAddr = pMapping->CpuPAddr.uiAddr + uOffset; if(uFlags & PVRSRV_MEM_ZERO) @@ -166,7 +285,7 @@ AllocMemory (BM_CONTEXT *pBMContext, { if(uFlags & PVRSRV_MEM_USER_SUPPLIED_DEVVADDR) { - + /* user supplied DevVAddr, no RAM backing */ PVR_ASSERT(psDevVAddr != IMG_NULL); if (psDevVAddr == IMG_NULL) @@ -175,7 +294,7 @@ AllocMemory (BM_CONTEXT *pBMContext, return IMG_FALSE; } - + /* just make space in the pagetables */ pBMContext->psDeviceNode->pfnMMUAlloc (psBMHeap->pMMUHeap, uSize, IMG_NULL, @@ -183,22 +302,30 @@ AllocMemory (BM_CONTEXT *pBMContext, uDevVAddrAlignment, psDevVAddr); - + /* setup buf */ pBuf->DevVAddr = *psDevVAddr; } else { - + IMG_BOOL bResult; + /* BM supplied DevVAddr, no RAM Backing */ - - pBMContext->psDeviceNode->pfnMMUAlloc (psBMHeap->pMMUHeap, + /* just make space in the pagetables */ + 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; + } } - + + /* allocate a mocked-up mapping */ if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (struct _BM_MAPPING_), (IMG_PVOID *)&pMapping, IMG_NULL, @@ -208,11 +335,12 @@ AllocMemory (BM_CONTEXT *pBMContext, return IMG_FALSE; } - + /* setup buf */ pBuf->CpuVAddr = IMG_NULL; pBuf->hOSMemHandle = 0; pBuf->CpuPAddr.uiAddr = 0; + /* setup mapping */ pMapping->CpuVAddr = IMG_NULL; pMapping->CpuPAddr.uiAddr = 0; pMapping->DevVAddr = pBuf->DevVAddr; @@ -221,16 +349,16 @@ AllocMemory (BM_CONTEXT *pBMContext, pMapping->hOSMemHandle = 0; } - + /* Record the arena pointer in the mapping. */ pMapping->pArena = pArena; pMapping->ui32DevVAddrAlignment = uDevVAddrAlignment; pMapping->bUnmapped = IMG_FALSE; - + /* record the heap */ pMapping->pBMHeap = psBMHeap; pBuf->pMapping = pMapping; - + /* output some stats */ PVR_DPF ((PVR_DBG_MESSAGE, "AllocMemory: pMapping=%08x: DevV=%08X CpuV=%08x CpuP=%08X uSize=0x%x", (IMG_UINTPTR_T)pMapping, @@ -247,13 +375,34 @@ AllocMemory (BM_CONTEXT *pBMContext, pBuf->CpuPAddr.uiAddr, uSize)); - + /* Verify virtual device address alignment */ PVR_ASSERT(((pBuf->DevVAddr.uiAddr) & (uDevVAddrAlignment - 1)) == 0); return IMG_TRUE; } +/*! +****************************************************************************** + + @Function WrapMemory + + @Description Allocate a buffer mapped into both cpu and device virtual + address spaces. + + @Input psBMHeap - BM heap + @Input uSize - requested buffer size in bytes. + @Input ui32BaseOffset - Offset from page of wrap. + @Input bPhysContig - Is the wrap physically contiguous. + @Input psAddr - List of pages to wrap. + @Input pvCPUVAddr - Optional CPU Kernel virtual address (page aligned) of memory to wrap + @Input uFlags - property flags for the buffer. + @Output Buf - receives a pointer to a descriptor of the allocated + buffer. + @Return IMG_TRUE - Success + IMG_FALSE - Failed. + + *****************************************************************************/ static IMG_BOOL WrapMemory (BM_HEAP *psBMHeap, IMG_SIZE_T uSize, @@ -274,13 +423,13 @@ WrapMemory (BM_HEAP *psBMHeap, (IMG_UINTPTR_T)psBMHeap, uSize, ui32BaseOffset, bPhysContig, (IMG_UINTPTR_T)pvCPUVAddr, uFlags)); PVR_ASSERT((psAddr->uiAddr & (ui32PageSize - 1)) == 0); - + /* Only need lower 12 bits of the cpu addr - don't care what size a void* is */ PVR_ASSERT(((IMG_UINTPTR_T)pvCPUVAddr & (ui32PageSize - 1)) == 0); uSize += ui32BaseOffset; uSize = HOST_PAGEALIGN (uSize); - + /* allocate a mocked-up mapping */ if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*pMapping), (IMG_PVOID *)&pMapping, IMG_NULL, @@ -293,6 +442,7 @@ WrapMemory (BM_HEAP *psBMHeap, OSMemSet(pMapping, 0, sizeof (*pMapping)); pMapping->uSize = uSize; + pMapping->uSizeVM = uSize; pMapping->pBMHeap = psBMHeap; pMapping->bUnmapped = IMG_FALSE; @@ -343,6 +493,7 @@ WrapMemory (BM_HEAP *psBMHeap, if(OSReservePhys(pMapping->CpuPAddr, pMapping->uSize, uFlags, + IMG_NULL, &pMapping->CpuVAddr, &pMapping->hOSMemHandle) != PVRSRV_OK) { @@ -369,7 +520,9 @@ WrapMemory (BM_HEAP *psBMHeap, } } - + /* + * Allocate device memory for this buffer. Map wrapped pages as read/write + */ bResult = DevMemoryAlloc(psBMHeap->pBMContext, pMapping, IMG_NULL, @@ -384,7 +537,12 @@ WrapMemory (BM_HEAP *psBMHeap, goto fail_cleanup; } - + /* + * Determine the offset of this allocation within the underlying + * dual mapped chunk of memory, we can assume that all three + * addresses associated with this allocation are placed at the same + * offset within the underlying chunk. + */ pBuf->CpuPAddr.uiAddr = pMapping->CpuPAddr.uiAddr + ui32BaseOffset; if(!ui32BaseOffset) { @@ -456,7 +614,7 @@ fail_cleanup: } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_MAPPING), pMapping, IMG_NULL); - + /*not nulling pointer, out of scope*/ return IMG_FALSE; } @@ -497,14 +655,18 @@ ZeroBuf(BM_BUF *pBuf, BM_MAPPING *pMapping, IMG_SIZE_T ui32Bytes, IMG_UINT32 ui3 IMG_SIZE_T ui32CurrentOffset = 0; IMG_CPU_PHYADDR CpuPAddr; - + /* Walk through the pBuf one page at a time and use + * transient mappings to zero the memory */ + PVR_ASSERT(pBuf->hOSMemHandle); while(ui32BytesRemaining > 0) { IMG_SIZE_T ui32BlockBytes = MIN(ui32BytesRemaining, HOST_PAGESIZE()); CpuPAddr = OSMemHandleToCpuPAddr(pBuf->hOSMemHandle, ui32CurrentOffset); - + /* If the CpuPAddr isn't page aligned then start by writing up to the next page + * boundary (or ui32BytesRemaining if less), so that subsequent iterations can + * copy full physical pages. */ if(CpuPAddr.uiAddr & (HOST_PAGESIZE() -1)) { ui32BlockBytes = @@ -536,6 +698,26 @@ ZeroBuf(BM_BUF *pBuf, BM_MAPPING *pMapping, IMG_SIZE_T ui32Bytes, IMG_UINT32 ui3 return IMG_TRUE; } +/*! +****************************************************************************** + + @Function FreeBuf + + @Description Free a buffer previously allocated with BM_Alloc() or unwrap + one previous wrapped with BM_Wrap(). + The buffer is identified by the buffer descriptor pBuf + returned at allocation. Note the double indirection when + passing the buffer. + + + @Input pBuf - buffer descriptor to free. + @Input ui32Flags - flags + @Input bFromAllocator - Is this being called by the + allocator? + + @Return None. + + *****************************************************************************/ static IMG_VOID FreeBuf (BM_BUF *pBuf, IMG_UINT32 ui32Flags, IMG_BOOL bFromAllocator) { @@ -547,7 +729,7 @@ FreeBuf (BM_BUF *pBuf, IMG_UINT32 ui32Flags, IMG_BOOL bFromAllocator) (IMG_UINTPTR_T)pBuf, pBuf->DevVAddr.uiAddr, (IMG_UINTPTR_T)pBuf->CpuVAddr, pBuf->CpuPAddr.uiAddr)); - + /* record mapping */ pMapping = pBuf->pMapping; psDeviceNode = pMapping->pBMHeap->pBMContext->psDeviceNode; @@ -558,32 +740,31 @@ FreeBuf (BM_BUF *pBuf, IMG_UINT32 ui32Flags, IMG_BOOL bFromAllocator) if(ui32Flags & PVRSRV_MEM_USER_SUPPLIED_DEVVADDR) { - + /* Submemhandle is required by exported mappings */ if ((pBuf->ui32ExportCount == 0) && (pBuf->ui32RefCount == 0)) { - + /* user supplied Device Virtual Address */ if(ui32Flags & PVRSRV_MEM_RAM_BACKED_ALLOCATION) { - + /* RAM backed allocation */ PVR_DPF ((PVR_DBG_ERROR, "FreeBuf: combination of DevVAddr management and RAM backing mode unsupported")); } else { - + /* free the mocked-up mapping */ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_MAPPING), pMapping, IMG_NULL); - pBuf->pMapping = IMG_NULL; + pBuf->pMapping = IMG_NULL; /*nulling pointer alias*/ } } } else { - + /* BM supplied Device Virtual Address */ if(pBuf->hOSMemHandle != pMapping->hOSMemHandle) { - + /* Submemhandle is required by exported mappings */ if ((pBuf->ui32ExportCount == 0) && (pBuf->ui32RefCount == 0)) { - OSReleaseSubMemHandle(pBuf->hOSMemHandle, ui32Flags); } } @@ -592,7 +773,7 @@ FreeBuf (BM_BUF *pBuf, IMG_UINT32 ui32Flags, IMG_BOOL bFromAllocator) /* see comment below */ if ((pBuf->ui32ExportCount == 0) && (pBuf->ui32RefCount == 0)) { - PVR_ASSERT(pBuf->ui32ExportCount == 0) + PVR_ASSERT(pBuf->ui32ExportCount == 0); BM_FreeMemory(pMapping->pBMHeap, 0, pMapping); } } @@ -602,13 +783,30 @@ FreeBuf (BM_BUF *pBuf, IMG_UINT32 ui32Flags, IMG_BOOL bFromAllocator) * need to change the one above in PVRSRV_HAP_GPU_PAGEABLE * case.. see comments in unstripped driver */ + /* Submemhandle is required by exported mappings */ if ((pBuf->ui32ExportCount == 0) && (pBuf->ui32RefCount == 0)) { - - - - PVR_ASSERT(pBuf->ui32ExportCount == 0) - RA_Free (pBuf->pMapping->pArena, pBuf->DevVAddr.uiAddr, IMG_FALSE); + /* + RAM backed allocation + Note: currently no need to distinguish between hm_env and hm_contiguous + */ + PVR_ASSERT(pBuf->ui32ExportCount == 0); + if (pBuf->pMapping->ui32Flags & PVRSRV_MEM_SPARSE) + { + IMG_UINT32 ui32FreeSize = sizeof(IMG_BOOL) * pBuf->pMapping->ui32NumVirtChunks; + IMG_PVOID pvFreePtr = pBuf->pMapping->pabMapChunk; + + /* With sparse allocations we don't go through the sub-alloc RA */ + BM_FreeMemory(pBuf->pMapping->pBMHeap, pBuf->DevVAddr.uiAddr, pBuf->pMapping); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + ui32FreeSize, + pvFreePtr, + IMG_NULL); + } + else + { + RA_Free (pBuf->pMapping->pArena, pBuf->DevVAddr.uiAddr, IMG_FALSE); + } } } else @@ -638,9 +836,9 @@ FreeBuf (BM_BUF *pBuf, IMG_UINT32 ui32Flags, IMG_BOOL bFromAllocator) if ((pBuf->ui32ExportCount == 0) && (pBuf->ui32RefCount == 0)) { - + /* free the mocked-up mapping */ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_MAPPING), pMapping, IMG_NULL); - pBuf->pMapping = IMG_NULL; + pBuf->pMapping = IMG_NULL; /*nulling pointer alias*/ } } } @@ -649,10 +847,22 @@ FreeBuf (BM_BUF *pBuf, IMG_UINT32 ui32Flags, IMG_BOOL bFromAllocator) if ((pBuf->ui32ExportCount == 0) && (pBuf->ui32RefCount == 0)) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_BUF), pBuf, IMG_NULL); - + /*not nulling pointer, copy on stack*/ } } +/*! +****************************************************************************** + + @Function BM_DestroyContext_AnyCb + + @Description Destroy a buffer manager heap. + + @Input psBMHeap + + @Return PVRSRV_ERROR + + *****************************************************************************/ static PVRSRV_ERROR BM_DestroyContext_AnyCb(BM_HEAP *psBMHeap) { if(psBMHeap->ui32Attribs @@ -673,6 +883,20 @@ static PVRSRV_ERROR BM_DestroyContext_AnyCb(BM_HEAP *psBMHeap) } +/*! +****************************************************************************** + + @Function BM_DestroyContext + + @Description Destroy a buffer manager context. All allocated buffers must be + free'd before calling this function. This function is called + also to perform cleanup during aborted initialisations so it's + fairly careful not to assume any given resource has really been + created/allocated. + + @Return PVRSRV_ERROR + + *****************************************************************************/ PVRSRV_ERROR BM_DestroyContext(IMG_HANDLE hBMContext, IMG_BOOL *pbDestroyed) @@ -687,8 +911,9 @@ BM_DestroyContext(IMG_HANDLE hBMContext, *pbDestroyed = IMG_FALSE; } - - + /* + Exit straight away if it's an invalid context handle + */ if (pBMContext == IMG_NULL) { PVR_DPF ((PVR_DBG_ERROR, "BM_DestroyContext: Invalid handle")); @@ -699,34 +924,23 @@ BM_DestroyContext(IMG_HANDLE hBMContext, if (pBMContext->ui32RefCount > 0) { - + /* Just return if there are more references to this context */ return PVRSRV_OK; } - - - + /* + Check whether there is a bug in the client which brought it here before + all the allocations have been freed. + */ 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 { - + /* free the device memory context */ eError = ResManFreeResByPtr(pBMContext->hResItem, CLEANUP_WITH_POLL); if(eError != PVRSRV_OK) { @@ -734,7 +948,7 @@ BM_DestroyContext(IMG_HANDLE hBMContext, return eError; } - + /* mark context as destroyed */ if (pbDestroyed != IMG_NULL) { *pbDestroyed = IMG_TRUE; @@ -745,12 +959,25 @@ BM_DestroyContext(IMG_HANDLE hBMContext, } +/*! +****************************************************************************** + + @Function BM_DestroyContextCallBack_AnyVaCb + + @Description Destroy Device memory context + + @Input psBMHeap - heap to be freed. + @Input va - list of variable arguments with the following contents: + - psDeviceNode + @Return PVRSRV_ERROR + + *****************************************************************************/ static PVRSRV_ERROR BM_DestroyContextCallBack_AnyVaCb(BM_HEAP *psBMHeap, va_list va) { PVRSRV_DEVICE_NODE *psDeviceNode; psDeviceNode = va_arg(va, PVRSRV_DEVICE_NODE*); - + /* Free up the import arenas */ if(psBMHeap->ui32Attribs & (PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG |PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG)) @@ -766,17 +993,30 @@ static PVRSRV_ERROR BM_DestroyContextCallBack_AnyVaCb(BM_HEAP *psBMHeap, va_list return PVRSRV_ERROR_UNSUPPORTED_BACKING_STORE; } - + /* Free up the MMU Heaps */ psDeviceNode->pfnMMUDelete(psBMHeap->pMMUHeap); - + /* Free Heap memory */ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_HEAP), psBMHeap, IMG_NULL); - + /*not nulling pointer, copy on stack*/ return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function BM_DestroyContextCallBack + + @Description Destroy Device memory context + + @Input pvParam - opaque void ptr param + @Input ui32Param - opaque unsigned long param + + @Return PVRSRV_ERROR + + *****************************************************************************/ static PVRSRV_ERROR BM_DestroyContextCallBack(IMG_PVOID pvParam, IMG_UINT32 ui32Param, IMG_BOOL bDummy) @@ -784,15 +1024,20 @@ static PVRSRV_ERROR BM_DestroyContextCallBack(IMG_PVOID pvParam, BM_CONTEXT *pBMContext = pvParam; PVRSRV_DEVICE_NODE *psDeviceNode; PVRSRV_ERROR eError; +/* BM_CONTEXT **ppBMContext; + BM_HEAP *psBMHeap, *psTmpBMHeap;*/ + PVR_UNREFERENCED_PARAMETER(ui32Param); PVR_UNREFERENCED_PARAMETER(bDummy); - - + /* + Get DeviceNode from BMcontext + */ psDeviceNode = pBMContext->psDeviceNode; - - + /* + Free the import arenas and heaps + */ eError = List_BM_HEAP_PVRSRV_ERROR_Any_va(pBMContext->psBMHeap, &BM_DestroyContextCallBack_AnyVaCb, psDeviceNode); @@ -800,15 +1045,17 @@ static PVRSRV_ERROR BM_DestroyContextCallBack(IMG_PVOID pvParam, { return eError; } - - + /* + 'Finalise' the MMU + */ if (pBMContext->psMMUContext) { psDeviceNode->pfnMMUFinalise(pBMContext->psMMUContext); } - - + /* + Free up generic, useful resources - if they were allocated. + */ if (pBMContext->pBufferHash) { HASH_Delete(pBMContext->pBufferHash); @@ -816,20 +1063,22 @@ static PVRSRV_ERROR BM_DestroyContextCallBack(IMG_PVOID pvParam, if (pBMContext == psDeviceNode->sDevMemoryInfo.pBMKernelContext) { - + /* Freeing the kernel context */ psDeviceNode->sDevMemoryInfo.pBMKernelContext = IMG_NULL; } else { if (pBMContext->ppsThis != IMG_NULL) { - + /* + * Remove context from the linked list + */ List_BM_CONTEXT_Remove(pBMContext); } } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_CONTEXT), pBMContext, IMG_NULL); - + /*not nulling pointer, copy on stack*/ return PVRSRV_OK; } @@ -841,7 +1090,7 @@ static IMG_HANDLE BM_CreateContext_IncRefCount_AnyVaCb(BM_CONTEXT *pBMContext, v hResManContext = va_arg(va, PRESMAN_CONTEXT); if(ResManFindResourceByPtr(hResManContext, pBMContext->hResItem) == PVRSRV_OK) { - + /* just increment the refcount and return the memory context found for this process */ pBMContext->ui32RefCount++; return pBMContext; } @@ -859,13 +1108,25 @@ static IMG_VOID BM_CreateContext_InsertHeap_ForEachVaCb(BM_HEAP *psBMHeap, va_li case DEVICE_MEMORY_HEAP_SHARED: case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: { - + /* insert the heap into the device's MMU page directory/table */ psDeviceNode->pfnMMUInsertHeap(pBMContext->psMMUContext, psBMHeap->pMMUHeap); break; } } } +/*! +****************************************************************************** + + @Function BM_CreateContext + + @Description Creates and initialises a buffer manager context. This function must be called + before any other buffer manager functions. + + @Return valid BM context handle - Success + IMG_NULL - Failed + + *****************************************************************************/ IMG_HANDLE BM_CreateContext(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_DEV_PHYADDR *psPDDevPAddr, @@ -873,6 +1134,7 @@ BM_CreateContext(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_BOOL *pbCreated) { BM_CONTEXT *pBMContext; +/* BM_HEAP *psBMHeap;*/ DEVICE_MEMORY_INFO *psDevMemoryInfo; IMG_BOOL bKernelContext; PRESMAN_CONTEXT hResManContext; @@ -895,7 +1157,7 @@ BM_CreateContext(PVRSRV_DEVICE_NODE *psDeviceNode, *pbCreated = IMG_FALSE; } - + /* setup the device memory info. */ psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo; if (bKernelContext == IMG_FALSE) @@ -909,7 +1171,7 @@ BM_CreateContext(PVRSRV_DEVICE_NODE *psDeviceNode, } } - + /* allocate a BM context */ if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (struct _BM_CONTEXT_), (IMG_PVOID *)&pBMContext, IMG_NULL, @@ -920,11 +1182,11 @@ BM_CreateContext(PVRSRV_DEVICE_NODE *psDeviceNode, } OSMemSet(pBMContext, 0, sizeof (BM_CONTEXT)); - + /* store the associated devicenode */ pBMContext->psDeviceNode = psDeviceNode; - - + /* This hash table is used to store BM_Wraps in a global way */ + /* INTEGRATION_POINT: 32 is an abitrary limit on the number of hashed BM_wraps */ pBMContext->pBufferHash = HASH_Create(32); if (pBMContext->pBufferHash==IMG_NULL) { @@ -942,17 +1204,18 @@ BM_CreateContext(PVRSRV_DEVICE_NODE *psDeviceNode, if(bKernelContext) { - + /* just save the kernel context */ PVR_ASSERT(psDevMemoryInfo->pBMKernelContext == IMG_NULL); psDevMemoryInfo->pBMKernelContext = pBMContext; } else { - - - - - + /* + On the creation of each new context we must + insert the kernel context's 'shared' and 'shared_exported' + heaps into the new context + - check the kernel context and heaps exist + */ PVR_ASSERT(psDevMemoryInfo->pBMKernelContext); if (psDevMemoryInfo->pBMKernelContext == IMG_NULL) @@ -963,28 +1226,30 @@ BM_CreateContext(PVRSRV_DEVICE_NODE *psDeviceNode, PVR_ASSERT(psDevMemoryInfo->pBMKernelContext->psBMHeap); - - - - + /* + insert the kernel heaps structures into the new context's shared heap list + Note. this will include the kernel only heaps but these will not actually + be imported into the context nor returned to the client + */ pBMContext->psBMSharedHeap = psDevMemoryInfo->pBMKernelContext->psBMHeap; - - - + /* + insert the shared heaps into the MMU page directory/table + for the new context + */ List_BM_HEAP_ForEach_va(pBMContext->psBMSharedHeap, &BM_CreateContext_InsertHeap_ForEachVaCb, psDeviceNode, pBMContext); - + /* Finally, insert the new context into the list of BM contexts */ List_BM_CONTEXT_Insert(&psDevMemoryInfo->pBMContext, pBMContext); } - + /* Increment the refcount, as creation is successful */ pBMContext->ui32RefCount++; - + /* register with resman */ pBMContext->hResItem = ResManRegisterRes(hResManContext, RESMAN_TYPE_DEVICEMEM_CONTEXT, pBMContext, @@ -1015,7 +1280,7 @@ static IMG_VOID *BM_CreateHeap_AnyVaCb(BM_HEAP *psBMHeap, va_list va) psDevMemHeapInfo = va_arg(va, DEVICE_MEMORY_HEAP_INFO*); if (psBMHeap->sDevArena.ui32HeapID == psDevMemHeapInfo->ui32HeapID) { - + /* Match - just return already created heap */ return psBMHeap; } else @@ -1024,6 +1289,19 @@ static IMG_VOID *BM_CreateHeap_AnyVaCb(BM_HEAP *psBMHeap, va_list va) } } +/*! +****************************************************************************** + + @Function BM_CreateHeap + + @Description Creates and initialises a BM heap for a given BM context. + + @Return + valid heap handle - success + IMG_NULL - failure + + + *****************************************************************************/ IMG_HANDLE BM_CreateHeap (IMG_HANDLE hBMContext, DEVICE_MEMORY_HEAP_INFO *psDevMemHeapInfo) @@ -1042,16 +1320,18 @@ BM_CreateHeap (IMG_HANDLE hBMContext, psDeviceNode = pBMContext->psDeviceNode; - - + /* + * Ensure that the heap size is a multiple of the data page size. + */ PVR_ASSERT((psDevMemHeapInfo->ui32HeapSize & (psDevMemHeapInfo->ui32DataPageSize - 1)) == 0); PVR_ASSERT(psDevMemHeapInfo->ui32HeapSize > 0); - - - - - + /* + We may be being asked to create a heap in a context which already has one. + Test for refcount > 0 because PVRSRVGetDeviceMemHeapInfoKM doesn't increment the refcount. + This does mean that the first call to PVRSRVCreateDeviceMemContextKM will first try to find + heaps that we already know don't exist + */ if(pBMContext->ui32RefCount > 0) { psBMHeap = (BM_HEAP*)List_BM_HEAP_Any_va(pBMContext->psBMHeap, @@ -1084,8 +1364,11 @@ BM_CreateHeap (IMG_HANDLE hBMContext, psBMHeap->sDevArena.ui32DataPageSize = psDevMemHeapInfo->ui32DataPageSize; psBMHeap->sDevArena.psDeviceMemoryHeapInfo = psDevMemHeapInfo; psBMHeap->ui32Attribs = psDevMemHeapInfo->ui32Attribs; +#if defined(SUPPORT_MEMORY_TILING) + psBMHeap->ui32XTileStride = psDevMemHeapInfo->ui32XTileStride; +#endif - + /* tie the heap to the context */ psBMHeap->pBMContext = pBMContext; psBMHeap->pMMUHeap = psDeviceNode->pfnMMUCreate (pBMContext->psMMUContext, @@ -1098,7 +1381,7 @@ BM_CreateHeap (IMG_HANDLE hBMContext, goto ErrorExit; } - + /* memory is allocated from the OS as required */ psBMHeap->pImportArena = RA_Create (psDevMemHeapInfo->pszBSName, 0, 0, IMG_NULL, MAX(HOST_PAGESIZE(), psBMHeap->sDevArena.ui32DataPageSize), @@ -1114,10 +1397,11 @@ BM_CreateHeap (IMG_HANDLE hBMContext, if(psBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG) { - - - - + /* + memory comes from a device memory contiguous allocator (ra) + Note: these arenas are shared across the system so don't delete + as part of heap destroy + */ psBMHeap->pLocalDevMemArena = psDevMemHeapInfo->psLocalDevMemArena; if(psBMHeap->pLocalDevMemArena == IMG_NULL) { @@ -1126,28 +1410,41 @@ BM_CreateHeap (IMG_HANDLE hBMContext, } } - + /* insert heap into head of the heap list */ List_BM_HEAP_Insert(&pBMContext->psBMHeap, psBMHeap); return (IMG_HANDLE)psBMHeap; - + /* handle error case */ ErrorExit: - + /* Free up the MMU if we created one */ if (psBMHeap->pMMUHeap != IMG_NULL) { psDeviceNode->pfnMMUDelete (psBMHeap->pMMUHeap); - + /* don't finalise psMMUContext as we don't own it */ } - + /* Free the Heap memory */ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_HEAP), psBMHeap, IMG_NULL); - + /*not nulling pointer, out of scope*/ return IMG_NULL; } +/*! +****************************************************************************** + + @Function BM_DestroyHeap + + @Description Destroys a BM heap + + @Return + valid heap handle - success + IMG_NULL - failure + + + *****************************************************************************/ IMG_VOID BM_DestroyHeap (IMG_HANDLE hDevMemHeap) { @@ -1158,7 +1455,7 @@ BM_DestroyHeap (IMG_HANDLE hDevMemHeap) if(psBMHeap) { - + /* Free up the import arenas */ if(psBMHeap->ui32Attribs & (PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG |PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG)) @@ -1174,14 +1471,12 @@ BM_DestroyHeap (IMG_HANDLE hDevMemHeap) return; } - + /* Free up the MMU Heap */ psDeviceNode->pfnMMUDelete (psBMHeap->pMMUHeap); - + /* remove from the heap list */ List_BM_HEAP_Remove(psBMHeap); - OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_HEAP), psBMHeap, IMG_NULL); - } else { @@ -1190,6 +1485,17 @@ BM_DestroyHeap (IMG_HANDLE hDevMemHeap) } +/*! +****************************************************************************** + + @Function BM_Reinitialise + + @Description Reinitialise the buffer manager after a power down event. + + @Return IMG_TRUE - Success + IMG_FALSE - Failed + + *****************************************************************************/ IMG_BOOL BM_Reinitialise (PVRSRV_DEVICE_NODE *psDeviceNode) { @@ -1197,16 +1503,48 @@ BM_Reinitialise (PVRSRV_DEVICE_NODE *psDeviceNode) PVR_DPF((PVR_DBG_MESSAGE, "BM_Reinitialise")); PVR_UNREFERENCED_PARAMETER(psDeviceNode); + /* FIXME: Need to reenable all contexts + List_BM_CONTEXT_ForEach(psDeviceNode->sDevMemoryInfo.pBMContext, MMU_Enable); + */ return IMG_TRUE; } +/*! +****************************************************************************** + + @Function BM_Alloc + + @Description Allocate a buffer mapped into both cpu and device virtual + memory maps. + + @Input hDevMemHeap + @Input psDevVAddr - device virtual address specified by caller (optional) + @Input uSize - require size in bytes of the buffer. + @Input pui32Flags - bit mask of buffer property flags. + @Input uDevVAddrAlignment - required alignment in bytes, or 0. + @Input pvPrivData - opaque private data passed through to allocator + @Input ui32PrivDataLength - length of opaque private data + + @Output phBuf - receives buffer handle + @Output pui32Flags - bit mask of heap property flags. + + @Return IMG_TRUE - Success + IMG_FALSE - Failure + + *****************************************************************************/ 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, + IMG_UINT32 ui32ChunkSize, + IMG_UINT32 ui32NumVirtChunks, + IMG_UINT32 ui32NumPhysChunks, + IMG_BOOL *pabMapChunk, BM_HANDLE *phBuf) { BM_BUF *pBuf; @@ -1238,7 +1576,9 @@ BM_Alloc ( IMG_HANDLE hDevMemHeap, uDevVAddrAlignment = 1; } - + /* + * Allocate something in which to record the allocation's details. + */ if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (BM_BUF), (IMG_PVOID *)&pBuf, IMG_NULL, @@ -1249,17 +1589,25 @@ BM_Alloc ( IMG_HANDLE hDevMemHeap, } OSMemSet(pBuf, 0, sizeof (BM_BUF)); - + /* + * Allocate the memory itself now. + */ if (AllocMemory(pBMContext, psBMHeap, psDevVAddr, uSize, uFlags, uDevVAddrAlignment, + pvPrivData, + ui32PrivDataLength, + ui32ChunkSize, + ui32NumVirtChunks, + ui32NumPhysChunks, + pabMapChunk, pBuf) != IMG_TRUE) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (BM_BUF), pBuf, IMG_NULL); - + /* not nulling pointer, out of scope */ PVR_DPF((PVR_DBG_ERROR, "BM_Alloc: AllocMemory FAILED")); return IMG_FALSE; } @@ -1268,12 +1616,17 @@ BM_Alloc ( IMG_HANDLE hDevMemHeap, "BM_Alloc (uSize=0x%x, uFlags=0x%x)", uSize, uFlags)); - + /* + * Assign the handle and return. + */ pBuf->ui32RefCount = 1; *phBuf = (BM_HANDLE)pBuf; *pui32Flags = uFlags | psBMHeap->ui32Attribs; - + /* + * If the user has specified heap CACHETYPE flags themselves, + * override any CACHETYPE flags inherited from the heap. + */ if(uFlags & PVRSRV_HAP_CACHETYPE_MASK) { *pui32Flags &= ~PVRSRV_HAP_CACHETYPE_MASK; @@ -1286,6 +1639,21 @@ BM_Alloc ( IMG_HANDLE hDevMemHeap, #if defined(PVR_LMA) +/*! +****************************************************************************** + + @Function ValidSysPAddrArrayForDev + + @Description Verify the array of system address is accessible + by the given device. + + @Input psDeviceNode + @Input psSysPAddr - system address array + @Input ui32PageSize - size of address array + + @Return IMG_BOOL + + *****************************************************************************/ static IMG_BOOL ValidSysPAddrArrayForDev(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_SYS_PHYADDR *psSysPAddr, IMG_UINT32 ui32PageCount, IMG_SIZE_T ui32PageSize) { @@ -1312,6 +1680,21 @@ ValidSysPAddrArrayForDev(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_SYS_PHYADDR *psSy return IMG_TRUE; } +/*! +****************************************************************************** + + @Function ValidSysPAddrRangeForDev + + @Description Verify a system address range is accessible + by the given device. + + @Input psDeviceNode + @Input sStartSysPAddr - starting system address + @Input ui32Range - length of address range + + @Return IMG_BOOL + + *****************************************************************************/ static IMG_BOOL ValidSysPAddrRangeForDev(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_SYS_PHYADDR sStartSysPAddr, IMG_SIZE_T ui32Range) { @@ -1339,6 +1722,28 @@ ValidSysPAddrRangeForDev(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_SYS_PHYADDR sStar #endif +/*! +****************************************************************************** + + @Function BM_Wrap + + @Description Create a buffer which wraps user provided system physical + memory. + The wrapped memory must be page aligned. BM_Wrap will + roundup the size to a multiple of cpu pages. + + @Input ui32Size - size of memory to wrap. + @Input ui32Offset - Offset into page of memory to wrap. + @Input bPhysContig - Is the wrap physically contiguous. + @Input psSysAddr - list of system physical page addresses of memory to wrap. + @Input pvCPUVAddr - optional CPU kernel virtual address (Page aligned) of memory to wrap. + @Input uFlags - bit mask of buffer property flags. + @output phBuf - receives the buffer handle. + + @Return IMG_TRUE - Success. + IMG_FALSE - Failed + + *****************************************************************************/ IMG_BOOL BM_Wrap ( IMG_HANDLE hDevMemHeap, IMG_SIZE_T ui32Size, @@ -1393,20 +1798,23 @@ BM_Wrap ( IMG_HANDLE hDevMemHeap, } } #endif - + /* + * Insert the System Physical Address of the first page into the hash so we can optimise multiple wraps of the + * same memory. + */ sHashAddress = psSysAddr[0]; - + /* Add the in-page offset to ensure a unique hash */ sHashAddress.uiAddr += ui32Offset; - + /* See if this address has already been wrapped */ pBuf = (BM_BUF *)HASH_Retrieve(psBMContext->pBufferHash, sHashAddress.uiAddr); if(pBuf) { IMG_SIZE_T ui32MappingSize = HOST_PAGEALIGN (ui32Size + ui32Offset); - + /* Check base address, size and contiguity type match */ if(pBuf->pMapping->uSize == ui32MappingSize && (pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped || pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr)) { @@ -1414,7 +1822,7 @@ BM_Wrap ( IMG_HANDLE hDevMemHeap, "BM_Wrap (Matched previous Wrap! uSize=0x%x, uOffset=0x%x, SysAddr=%08X)", ui32Size, ui32Offset, sHashAddress.uiAddr)); - pBuf->ui32RefCount++; + PVRSRVBMBufIncRef(pBuf); *phBuf = (BM_HANDLE)pBuf; if(pui32Flags) *pui32Flags = uFlags; @@ -1423,12 +1831,15 @@ BM_Wrap ( IMG_HANDLE hDevMemHeap, } else { - + /* Otherwise removed that item from the hash table + (a workaround for buffer device class) */ HASH_Remove(psBMContext->pBufferHash, (IMG_UINTPTR_T)sHashAddress.uiAddr); } } - + /* + * Allocate something in which to record the allocation's details. + */ if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (BM_BUF), (IMG_PVOID *)&pBuf, IMG_NULL, @@ -1439,19 +1850,23 @@ BM_Wrap ( IMG_HANDLE hDevMemHeap, } OSMemSet(pBuf, 0, sizeof (BM_BUF)); - + /* + * Actually perform the memory wrap. + */ 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); - + /*not nulling pointer, out of scope*/ return IMG_FALSE; } - + /* Only insert the buffer in the hash table if it is contiguous - allows for optimisation of multiple wraps + * of the same contiguous buffer. + */ if(pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped || pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr) { - + /* Have we calculated the right Hash key ? */ PVR_ASSERT(SysSysPAddrToCpuPAddr(sHashAddress).uiAddr == pBuf->CpuPAddr.uiAddr); if (!HASH_Insert (psBMContext->pBufferHash, sHashAddress.uiAddr, (IMG_UINTPTR_T)pBuf)) @@ -1466,36 +1881,73 @@ BM_Wrap ( IMG_HANDLE hDevMemHeap, "BM_Wrap (uSize=0x%x, uFlags=0x%x, devVAddr=%08X)", ui32Size, uFlags, pBuf->DevVAddr.uiAddr)); - + /* + * Assign the handle and return. + */ pBuf->ui32RefCount = 1; *phBuf = (BM_HANDLE)pBuf; if(pui32Flags) { - + /* need to override the heap attributes SINGLE PROC to MULT_PROC. */ *pui32Flags = (uFlags & ~PVRSRV_HAP_MAPTYPE_MASK) | PVRSRV_HAP_MULTI_PROCESS; } return IMG_TRUE; } +/*! +****************************************************************************** + + @Function BM_Export + + @Description Export a buffer previously allocated via BM_Alloc. + + @Input hBuf - buffer handle. + @Input ui32Flags - flags + + @Return None. + + *****************************************************************************/ + IMG_VOID BM_Export (BM_HANDLE hBuf) { BM_BUF *pBuf = (BM_BUF *)hBuf; - pBuf->ui32ExportCount++; + PVRSRVBMBufIncExport(pBuf); } +/*! +****************************************************************************** + @Function BM_Export + + @Description Export a buffer previously allocated via BM_Alloc. + + @Input hBuf - buffer handle. + + @Return None. +**************************************************************************/ IMG_VOID BM_FreeExport(BM_HANDLE hBuf, IMG_UINT32 ui32Flags) { BM_BUF *pBuf = (BM_BUF *)hBuf; - pBuf->ui32ExportCount--; + PVRSRVBMBufDecExport(pBuf); FreeBuf (pBuf, ui32Flags, IMG_FALSE); } +/*! +****************************************************************************** + @Function BM_FreeExport + + @Description Free a buffer previously exported via BM_Export. + + @Input hBuf - buffer handle. + @Input ui32Flags - flags + + @Return None. +**************************************************************************/ IMG_VOID BM_Free (BM_HANDLE hBuf, IMG_UINT32 ui32Flags) @@ -1515,8 +1967,7 @@ BM_Free (BM_HANDLE hBuf, SysAcquireData(&psSysData); - pBuf->ui32RefCount--; - + PVRSRVBMBufDecRef(pBuf); if(pBuf->ui32RefCount == 0) { if(pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped || pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr) @@ -1530,21 +1981,6 @@ BM_Free (BM_HANDLE hBuf, } -IMG_VOID -BM_RegisterSmart(BM_HANDLE hBuf, IMG_HANDLE hSmartCache) -{ - BM_BUF *pBuf = (BM_BUF *)hBuf; - OSMemHandleRegisterSmart(pBuf->hOSMemHandle, hSmartCache); -} - -IMG_VOID -BM_UnregisterSmart(BM_HANDLE hBuf, IMG_HANDLE hSmartCache) -{ - BM_BUF *pBuf = (BM_BUF *)hBuf; - OSMemHandleUnegisterSmart(pBuf->hOSMemHandle, hSmartCache); -} - - #if defined(SUPPORT_DRI_DRM_EXTERNAL) IMG_VOID BM_SetGEM(BM_HANDLE hBuf, IMG_HANDLE buf) @@ -1561,7 +1997,18 @@ BM_GetGEM(BM_HANDLE hBuf) } #endif /* SUPPORT_DRI_DRM_EXTERNAL */ +/*! +****************************************************************************** + @Function BM_HandleToCpuVaddr + + @Description Retreive the cpu virtual address associated with a buffer. + + @Input buffer handle. + + @Return buffers cpu virtual address, or NULL if none exists + + *****************************************************************************/ IMG_CPU_VIRTADDR BM_HandleToCpuVaddr (BM_HANDLE hBuf) { @@ -1581,6 +2028,18 @@ BM_HandleToCpuVaddr (BM_HANDLE hBuf) } +/*! +****************************************************************************** + + @Function BM_HandleToDevVaddr + + @Description Retreive the device virtual address associated with a buffer. + + @Input hBuf - buffer handle. + + @Return buffers device virtual address. + + *****************************************************************************/ IMG_DEV_VIRTADDR BM_HandleToDevVaddr (BM_HANDLE hBuf) { @@ -1599,6 +2058,18 @@ BM_HandleToDevVaddr (BM_HANDLE hBuf) } +/*! +****************************************************************************** + + @Function BM_HandleToSysPaddr + + @Description Retreive the system physical address associated with a buffer. + + @Input hBuf - buffer handle. + + @Return buffers device virtual address. + + *****************************************************************************/ IMG_SYS_PHYADDR BM_HandleToSysPaddr (BM_HANDLE hBuf) { @@ -1617,6 +2088,18 @@ BM_HandleToSysPaddr (BM_HANDLE hBuf) return SysCpuPAddrToSysPAddr (pBuf->CpuPAddr); } +/*! +****************************************************************************** + + @Function BM_HandleToMemOSHandle + + @Description Retreive the underlying memory handle associated with a buffer. + + @Input hBuf - buffer handle. + + @Return OS Specific memory handle. + + *****************************************************************************/ IMG_HANDLE BM_HandleToOSMemHandle(BM_HANDLE hBuf) { @@ -1742,6 +2225,33 @@ BM_RemapToDev(BM_HANDLE hBuf) } +/*! +****************************************************************************** + + @Function DevMemoryAlloc + + @Description Allocate device memory for a given physical/virtual memory + mapping. We handle the main cases where device MMU mappings + are required - these are the dynamic cases: all wrappings of + host OS memory and host OS imports for SYS_MMU_NORMAL mode. + + If no MMU support is required then we simply map device virtual + space as device physical space. + + @Input pBMContext - the pager to allocate from. + @Output pMapping - the mapping descriptor to be filled in for this + allocation. + @Output pActualSize - the actual size of the block allocated in + bytes. + @Input uFlags - allocation flags + @Input dev_vaddr_alignment - required device virtual address + alignment, or 0. + @Output pDevVAddr - receives the device virtual base address of the + allocated block. + @Return IMG_TRUE - Success + IMG_FALSE - Failed. + + *****************************************************************************/ static IMG_BOOL DevMemoryAlloc (BM_CONTEXT *pBMContext, BM_MAPPING *pMapping, @@ -1771,14 +2281,16 @@ DevMemoryAlloc (BM_CONTEXT *pBMContext, #ifdef PDUMP if(uFlags & PVRSRV_MEM_DUMMY) { - + /* only one page behind a dummy allocation */ ui32PDumpSize = pMapping->pBMHeap->sDevArena.ui32DataPageSize; } #endif - + /* Check we haven't fall through a gap */ + PVR_ASSERT(pMapping->uSizeVM != 0); + /* allocate device linear space */ if (!psDeviceNode->pfnMMUAlloc (pMapping->pBMHeap->pMMUHeap, - pMapping->uSize, + pMapping->uSizeVM, pActualSize, 0, dev_vaddr_alignment, @@ -1793,7 +2305,7 @@ DevMemoryAlloc (BM_CONTEXT *pBMContext, #endif #if defined(PDUMP) - + /* pdump the memory allocate */ PDUMPMALLOCPAGES(&psDeviceNode->sDevId, pMapping->DevVAddr.uiAddr, pMapping->CpuVAddr, @@ -1803,8 +2315,8 @@ DevMemoryAlloc (BM_CONTEXT *pBMContext, #if defined(SUPPORT_PDUMP_MULTI_PROCESS) psDeviceNode->pfnMMUIsHeapShared(pMapping->pBMHeap->pMMUHeap), #else - IMG_FALSE, -#endif + IMG_FALSE, // unused +#endif /* SUPPORT_PDUMP_MULTI_PROCESS */ (IMG_HANDLE)pMapping); #endif @@ -1814,26 +2326,61 @@ DevMemoryAlloc (BM_CONTEXT *pBMContext, case hm_wrapped_virtaddr: case hm_contiguous: { - psDeviceNode->pfnMMUMapPages ( pMapping->pBMHeap->pMMUHeap, - pMapping->DevVAddr, - SysCpuPAddrToSysPAddr (pMapping->CpuPAddr), - pMapping->uSize, - uFlags, - (IMG_HANDLE)pMapping); - + if (uFlags & PVRSRV_MEM_SPARSE) + { + /* Check if this device supports sparse mappings */ + PVR_ASSERT(psDeviceNode->pfnMMUMapPagesSparse != IMG_NULL); + psDeviceNode->pfnMMUMapPagesSparse(pMapping->pBMHeap->pMMUHeap, + pMapping->DevVAddr, + SysCpuPAddrToSysPAddr (pMapping->CpuPAddr), + pMapping->ui32ChunkSize, + pMapping->ui32NumVirtChunks, + pMapping->ui32NumPhysChunks, + pMapping->pabMapChunk, + uFlags, + (IMG_HANDLE)pMapping); + } + else + { + 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); + if (uFlags & PVRSRV_MEM_SPARSE) + { + /* Check if this device supports sparse mappings */ + PVR_ASSERT(psDeviceNode->pfnMMUMapShadowSparse != IMG_NULL); + psDeviceNode->pfnMMUMapShadowSparse(pMapping->pBMHeap->pMMUHeap, + pMapping->DevVAddr, + pMapping->ui32ChunkSize, + pMapping->ui32NumVirtChunks, + pMapping->ui32NumPhysChunks, + pMapping->pabMapChunk, + pMapping->CpuVAddr, + pMapping->hOSMemHandle, + pDevVAddr, + uFlags, + (IMG_HANDLE)pMapping); + } + else + { + psDeviceNode->pfnMMUMapShadow ( pMapping->pBMHeap->pMMUHeap, + pMapping->DevVAddr, + pMapping->uSize, + pMapping->CpuVAddr, + pMapping->hOSMemHandle, + pDevVAddr, + uFlags, + (IMG_HANDLE)pMapping); + } break; } case hm_wrapped_scatter: @@ -1886,10 +2433,10 @@ DevMemoryFree (BM_MAPPING *pMapping) if (sDevPAddr.uiAddr != 0) { #ifdef PDUMP - + /* pdump the memory free */ if(pMapping->ui32Flags & PVRSRV_MEM_DUMMY) { - + /* physical memory size differs in the case of Dummy allocations */ ui32PSize = pMapping->pBMHeap->sDevArena.ui32DataPageSize; } else @@ -1902,286 +2449,170 @@ DevMemoryFree (BM_MAPPING *pMapping) ui32PSize, pMapping->pBMHeap->sDevArena.ui32DataPageSize, (IMG_HANDLE)pMapping, - (pMapping->ui32Flags & PVRSRV_MEM_INTERLEAVED) ? IMG_TRUE : IMG_FALSE); + (pMapping->ui32Flags & PVRSRV_MEM_INTERLEAVED) ? IMG_TRUE : IMG_FALSE, + (pMapping->ui32Flags & PVRSRV_MEM_SPARSE) ? IMG_TRUE : IMG_FALSE); #endif } - psDeviceNode->pfnMMUFree (pMapping->pBMHeap->pMMUHeap, pMapping->DevVAddr, IMG_CAST_TO_DEVVADDR_UINT(pMapping->uSize)); + PVR_ASSERT(pMapping->uSizeVM != 0); + psDeviceNode->pfnMMUFree (pMapping->pBMHeap->pMMUHeap, pMapping->DevVAddr, IMG_CAST_TO_DEVVADDR_UINT(pMapping->uSizeVM)); pMapping->bUnmapped = IMG_TRUE; } -static PXProcShareDataNode gXProcWorkaroundShareDataNode = NULL; - -static const char const* gcXprocId = "Xproc Shared Buffer"; - -typedef struct XProcShareDataNode{ - const char* cXprocId; - 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; - struct list_head list; -}XProcShareDataNodeT; - -LIST_HEAD(gXProcShareList); - -static unsigned int gXProcShareCount = 0; - -static IMG_BOOL IsXprocShareObjectValid(PXProcShareDataNode pShareDataNode) -{ - if(pShareDataNode->cXprocId == gcXprocId) - return IMG_TRUE; - - PVR_DPF((PVR_DBG_ERROR, "Share Data Node Is Invalid!!!")); - return IMG_FALSE; -} - -static void XprocPrintListStats(void) -{ - struct list_head *list_ptr; - PXProcShareDataNode pShareDataNodeIt = NULL; - unsigned used_objects = 0, unused_objects = 0, invalid_objects = 0; - - list_for_each(list_ptr, &gXProcShareList) - { - pShareDataNodeIt = list_entry(list_ptr, XProcShareDataNodeT, list); - if(IMG_TRUE == IsXprocShareObjectValid(pShareDataNodeIt)) - { - if ((pShareDataNodeIt->ui32RefCount > 0)) - { - used_objects++; - } - else - { - unused_objects++; - } - } - else - { - invalid_objects++; - } - } - PVR_DPF((PVR_DBG_ERROR, "Share Data List stats: used %d, unused %d, invalid %d descriptors", - used_objects, unused_objects, invalid_objects)); -} - -static PXProcShareDataNode XprocShareObjectCreate(void) -{ - PXProcShareDataNode pShareDataNode = NULL; - - if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, - sizeof (XProcShareDataNodeT), - (IMG_PVOID *)&pShareDataNode, IMG_NULL, - /* "Xproc Shared Buffer" */ gcXprocId) != PVRSRV_OK) - { - PVR_DPF((PVR_DBG_ERROR, "OSAllocMem: pShareDataNode alloc FAILED")); - return NULL; - } - - if(NULL == pShareDataNode) - { - PVR_DPF((PVR_DBG_ERROR, "XprocShareObjectCreate: pShareDataNode alloc FAILED")); - return NULL; - } - - OSMemSet(pShareDataNode, 0, sizeof (XProcShareDataNodeT)); - - /* Make it valid */ - INIT_LIST_HEAD(&pShareDataNode->list); - pShareDataNode->cXprocId = gcXprocId; - - /* Add it to the list */ - list_add(&pShareDataNode->list, &gXProcShareList); - gXProcShareCount++; - - PVR_DPF ((PVR_DBG_MESSAGE, "Share Object %p created, ref count: %d", pShareDataNode, gXProcShareCount)); +/* If this array grows larger, it might be preferable to use a hashtable rather than an array. */ +#ifndef XPROC_WORKAROUND_NUM_SHAREABLES +#define XPROC_WORKAROUND_NUM_SHAREABLES 200 +#endif - if(gXProcShareCount > 5000) - { - PVR_DPF((PVR_DBG_ERROR, "Too Many Share Data Nodes %d. Potential memory leak!!!", gXProcShareCount)); - XprocPrintListStats(); - } +#define XPROC_WORKAROUND_BAD_SHAREINDEX 0773407734 - return pShareDataNode; -} +#define XPROC_WORKAROUND_UNKNOWN 0 +#define XPROC_WORKAROUND_ALLOC 1 +#define XPROC_WORKAROUND_MAP 2 -static void XprocShareObjectDestroy(PXProcShareDataNode pShareDataNode) -{ - list_del(&pShareDataNode->list); - pShareDataNode->hOSMemHandle = NULL; - pShareDataNode->cXprocId = NULL; - OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof (XProcShareDataNodeT), pShareDataNode, IMG_NULL); - if(gXProcWorkaroundShareDataNode == pShareDataNode) - { - PVR_DPF((PVR_DBG_ERROR, "Share Data Node %p destroyed. Ignore the following error message about it!!!", pShareDataNode)); - gXProcWorkaroundShareDataNode = NULL; - } - gXProcShareCount--; +static IMG_UINT32 gXProcWorkaroundShareIndex = XPROC_WORKAROUND_BAD_SHAREINDEX; +static IMG_UINT32 gXProcWorkaroundState = XPROC_WORKAROUND_UNKNOWN; - PVR_DPF ((PVR_DBG_MESSAGE, "Share Object %p destoyed, ref count: %d", pShareDataNode, gXProcShareCount)); -} +/* PRQA S 0686 10 */ /* force compiler to init structure */ +XPROC_DATA gXProcWorkaroundShareData[XPROC_WORKAROUND_NUM_SHAREABLES] = {{0}}; -PVRSRV_ERROR BM_XProcSetShareIndex(PXProcShareDataNode pShareDataNode) +PVRSRV_ERROR BM_XProcWorkaroundSetShareIndex(IMG_UINT32 ui32Index) { - - if (gXProcWorkaroundShareDataNode != NULL) + /* if you fail this assertion - did you acquire the mutex? + did you call "set" exactly once? + did you call "unset" exactly once per set? + */ + if (gXProcWorkaroundShareIndex != XPROC_WORKAROUND_BAD_SHAREINDEX) { - PVR_DPF((PVR_DBG_ERROR, "Share Data Node already set!")); - return PVRSRV_ERROR_NOT_OWNER; - } - - if(pShareDataNode == NULL) - { - PVR_DPF((PVR_DBG_ERROR, "Trying to set NULL pShareDataNode!")); + PVR_DPF((PVR_DBG_ERROR, "No, it's already set!")); return PVRSRV_ERROR_INVALID_PARAMS; } - if(IMG_TRUE != IsXprocShareObjectValid(pShareDataNode)) - return PVRSRV_ERROR_INVALID_PARAMS; - - gXProcWorkaroundShareDataNode = pShareDataNode; + gXProcWorkaroundShareIndex = ui32Index; + gXProcWorkaroundState = XPROC_WORKAROUND_MAP; return PVRSRV_OK; } -PVRSRV_ERROR BM_XProcFinishShareIndex(PXProcShareDataNode pShareDataNode, IMG_BOOL freeIfNotUsed) +PVRSRV_ERROR BM_XProcWorkaroundUnsetShareIndex(IMG_UINT32 ui32Index) { - if (gXProcWorkaroundShareDataNode == NULL) + /* if you fail this assertion - did you acquire the mutex? + did you call "set" exactly once? + did you call "unset" exactly once per set? + */ + if (gXProcWorkaroundShareIndex == XPROC_WORKAROUND_BAD_SHAREINDEX) { - PVR_DPF((PVR_DBG_ERROR, "Share Data Node is NULL and should of been %p", pShareDataNode)); + PVR_DPF((PVR_DBG_ERROR, "huh? how can it be bad??")); return PVRSRV_ERROR_INVALID_PARAMS; } - - if (gXProcWorkaroundShareDataNode != pShareDataNode) + if (gXProcWorkaroundShareIndex != ui32Index) { - PVR_DPF((PVR_DBG_ERROR, "gXProcWorkaroundShareDataNode == %p != %p == pShareDataNode", gXProcWorkaroundShareDataNode, pShareDataNode)); + PVR_DPF((PVR_DBG_ERROR, "gXProcWorkaroundShareIndex == 0x%08x != 0x%08x == ui32Index", gXProcWorkaroundShareIndex, ui32Index)); return PVRSRV_ERROR_INVALID_PARAMS; } - if (pShareDataNode == NULL) - { - PVR_DPF((PVR_DBG_ERROR, "pShareDataNode == NULL")); - return PVRSRV_ERROR_INVALID_PARAMS; - } - - if((freeIfNotUsed == IMG_TRUE) && - (IMG_TRUE == IsXprocShareObjectValid(pShareDataNode)) && - (pShareDataNode->ui32RefCount == 0x00)) - { - PVR_DPF((PVR_DBG_ERROR, "Explicit free of pShareDataNode")); - XprocShareObjectDestroy(pShareDataNode); - } - - gXProcWorkaroundShareDataNode = NULL; - - PVR_DPF ((PVR_DBG_MESSAGE, "BM_XProcFinishShareIndex for %p", pShareDataNode)); + gXProcWorkaroundShareIndex = XPROC_WORKAROUND_BAD_SHAREINDEX; + gXProcWorkaroundState = XPROC_WORKAROUND_UNKNOWN; return PVRSRV_OK; } -PXProcShareDataNode BM_XProcAllocNewBuffer(void) +PVRSRV_ERROR BM_XProcWorkaroundFindNewBufferAndSetShareIndex(IMG_UINT32 *pui32Index) { - PXProcShareDataNode pShareDataNode; - - if (gXProcWorkaroundShareDataNode != NULL) + /* if you fail this assertion - did you acquire the mutex? + did you call "set" exactly once? + did you call "unset" exactly once per set? + */ + if (gXProcWorkaroundShareIndex != XPROC_WORKAROUND_BAD_SHAREINDEX) { - PVR_DPF((PVR_DBG_ERROR, "Share Data Node already allocated/set!")); - return NULL; + return PVRSRV_ERROR_INVALID_PARAMS; } - pShareDataNode = XprocShareObjectCreate(); - if(NULL == pShareDataNode) - return NULL; - - PVR_DPF ((PVR_DBG_MESSAGE, "BM_XProcAllocNewBuffer and SET %p", pShareDataNode)); - - gXProcWorkaroundShareDataNode = pShareDataNode; - - return pShareDataNode; -} + for (*pui32Index = 0; *pui32Index < XPROC_WORKAROUND_NUM_SHAREABLES; (*pui32Index)++) + { + if (gXProcWorkaroundShareData[*pui32Index].ui32RefCount == 0) + { + gXProcWorkaroundShareIndex = *pui32Index; + gXProcWorkaroundState = XPROC_WORKAROUND_ALLOC; + return PVRSRV_OK; + } + } -IMG_UINT32 BM_XProcWorkaroundGetRefCount(IMG_UINT32 ui32Index) -{ - return gXProcWorkaroundShareDataNode->ui32RefCount; + PVR_DPF((PVR_DBG_ERROR, "ran out of shared buffers")); + return PVRSRV_ERROR_OUT_OF_MEMORY; } static PVRSRV_ERROR -XProcAllocShareable(RA_ARENA *psArena, +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_ERROR, "XProcAllocShareable: bad flags")); + PVR_DPF((PVR_DBG_VERBOSE, "XProcWorkaroundAllocShareable: bad flags")); return PVRSRV_ERROR_INVALID_PARAMS; } - if (gXProcWorkaroundShareDataNode == NULL) - { - PVR_DPF((PVR_DBG_ERROR, "XProcAllocShareable: gXProcWorkaroundShareDataNode == NULL")); - return PVRSRV_ERROR_NOT_OWNER; - } - - if(IMG_TRUE != IsXprocShareObjectValid(gXProcWorkaroundShareDataNode)) - return PVRSRV_ERROR_INVALID_PARAMS; - - if (gXProcWorkaroundShareDataNode->ui32RefCount > 0) + if (gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32RefCount > 0) { PVR_DPF((PVR_DBG_VERBOSE, - "XProcAllocShareable: re-using previously allocated pages %p", gXProcWorkaroundShareDataNode)); + "XProcWorkaroundAllocShareable: re-using previously allocated pages")); ui32AllocFlags &= ~PVRSRV_HAP_MAPTYPE_MASK; ui32AllocFlags |= PVRSRV_HAP_SINGLE_PROCESS; - if (ui32AllocFlags != gXProcWorkaroundShareDataNode->ui32AllocFlags) + if (ui32AllocFlags != gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32AllocFlags) { PVR_DPF((PVR_DBG_ERROR, - "Bucket Flags don't match! (bucket had 0x%08x, new one 0x%08x)", - gXProcWorkaroundShareDataNode->ui32AllocFlags, + "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 != gXProcWorkaroundShareDataNode->ui32Size) + if (ui32Size != gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32Size) { PVR_DPF((PVR_DBG_ERROR, - "Bucket Size doesn't match! (bucket size %d, new size %d )", - gXProcWorkaroundShareDataNode->ui32Size, ui32Size)); + "Can't! Size doesn't match!")); return PVRSRV_ERROR_INVALID_PARAMS; } - if (ui32PageSize != gXProcWorkaroundShareDataNode->ui32PageSize) + if (ui32PageSize != gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32PageSize) { PVR_DPF((PVR_DBG_ERROR, - "Bucket Page Size doesn't match!(bucket size %d, new size %d )", - gXProcWorkaroundShareDataNode->ui32PageSize, ui32PageSize)); + "Can't! Page Size doesn't match!")); return PVRSRV_ERROR_INVALID_PARAMS; } - *ppvCpuVAddr = gXProcWorkaroundShareDataNode->pvCpuVAddr; - *phOSMemHandle = gXProcWorkaroundShareDataNode->hOSMemHandle; + *ppvCpuVAddr = gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].pvCpuVAddr; + *phOSMemHandle = gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].hOSMemHandle; - gXProcWorkaroundShareDataNode->ui32RefCount++; + BM_XProcIndexAcquire(gXProcWorkaroundShareIndex); 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, - "XProcAllocShareable: making a NEW allocation from local mem %p(%d)", - gXProcWorkaroundShareDataNode, gXProcWorkaroundShareDataNode->ui32RefCount)); + "XProcWorkaroundAllocShareable: making a NEW allocation from local mem")); if (!RA_Alloc (psArena, ui32Size, @@ -2190,9 +2621,11 @@ XProcAllocShareable(RA_ARENA *psArena, 0, ui32PageSize, 0, + pvPrivData, + ui32PrivDataLength, (IMG_UINTPTR_T *)&sSysPAddr.uiAddr)) { - PVR_DPF((PVR_DBG_ERROR, "XProcAllocShareable: RA_Alloc(0x%x) FAILED", ui32Size)); + PVR_DPF((PVR_DBG_ERROR, "XProcWorkaroundAllocShareable: RA_Alloc(0x%x) FAILED", ui32Size)); return PVRSRV_ERROR_OUT_OF_MEMORY; } @@ -2200,127 +2633,194 @@ XProcAllocShareable(RA_ARENA *psArena, if(OSReservePhys(sCpuPAddr, ui32Size, ui32AllocFlags, - (IMG_VOID **)&gXProcWorkaroundShareDataNode->pvCpuVAddr, - &gXProcWorkaroundShareDataNode->hOSMemHandle) != PVRSRV_OK) + IMG_NULL, + (IMG_VOID **)&gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].pvCpuVAddr, + &gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].hOSMemHandle) != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, "XProcAllocShareable: OSReservePhys failed")); + PVR_DPF((PVR_DBG_ERROR, "XProcWorkaroundAllocShareable: OSReservePhys failed")); return PVRSRV_ERROR_OUT_OF_MEMORY; } - gXProcWorkaroundShareDataNode->sSysPAddr = sSysPAddr; + gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].sSysPAddr = sSysPAddr; } else { - PVR_DPF((PVR_DBG_VERBOSE, - "XProcAllocShareable: making a NEW allocation from OS %p(%d)", - gXProcWorkaroundShareDataNode, gXProcWorkaroundShareDataNode->ui32RefCount)); + PVR_DPF((PVR_DBG_VERBOSE, + "XProcWorkaroundAllocShareable: making a NEW allocation from OS")); ui32AllocFlags &= ~PVRSRV_HAP_MAPTYPE_MASK; ui32AllocFlags |= PVRSRV_HAP_SINGLE_PROCESS; - + /* allocate pages from the OS RAM */ if (OSAllocPages(ui32AllocFlags, ui32Size, ui32PageSize, - (IMG_VOID **)&gXProcWorkaroundShareDataNode->pvCpuVAddr, - &gXProcWorkaroundShareDataNode->hOSMemHandle) != PVRSRV_OK) + pvPrivData, + ui32PrivDataLength, + IMG_NULL, /* FIXME: to support cross process sparse allocations */ + (IMG_VOID **)&gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].pvCpuVAddr, + &gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].hOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, - "XProcAllocShareable: OSAllocPages(0x%x) failed", + "XProcWorkaroundAllocShareable: OSAllocPages(0x%x) failed", ui32PageSize)); return PVRSRV_ERROR_OUT_OF_MEMORY; } } - gXProcWorkaroundShareDataNode->psArena = psArena; - gXProcWorkaroundShareDataNode->ui32AllocFlags = ui32AllocFlags; - gXProcWorkaroundShareDataNode->ui32Size = ui32Size; - gXProcWorkaroundShareDataNode->ui32PageSize = ui32PageSize; + gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].psArena = psArena; + gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32AllocFlags = ui32AllocFlags; + gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32Size = ui32Size; + gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].ui32PageSize = ui32PageSize; - *ppvCpuVAddr = gXProcWorkaroundShareDataNode->pvCpuVAddr; - *phOSMemHandle = gXProcWorkaroundShareDataNode->hOSMemHandle; + *ppvCpuVAddr = gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].pvCpuVAddr; + *phOSMemHandle = gXProcWorkaroundShareData[gXProcWorkaroundShareIndex].hOSMemHandle; - gXProcWorkaroundShareDataNode->ui32RefCount++; + BM_XProcIndexAcquire(gXProcWorkaroundShareIndex); return PVRSRV_OK; } } -static PXProcShareDataNode XProcHandleToSI(IMG_HANDLE hOSMemHandle) +static PVRSRV_ERROR XProcWorkaroundHandleToSI(IMG_HANDLE hOSMemHandle, IMG_UINT32 *pui32SI) { - - struct list_head *list_ptr; - PXProcShareDataNode pShareDataNode = NULL; + IMG_UINT32 ui32SI; + IMG_BOOL bFound; + IMG_BOOL bErrorDups; - if(hOSMemHandle == NULL) - return NULL; + bFound = IMG_FALSE; + bErrorDups = IMG_FALSE; - list_for_each(list_ptr, &gXProcShareList) + for (ui32SI = 0; ui32SI < XPROC_WORKAROUND_NUM_SHAREABLES; ui32SI++) { - pShareDataNode = list_entry(list_ptr, XProcShareDataNodeT, list); - if(IMG_TRUE == IsXprocShareObjectValid(pShareDataNode)) + if (gXProcWorkaroundShareData[ui32SI].ui32RefCount>0 && gXProcWorkaroundShareData[ui32SI].hOSMemHandle == hOSMemHandle) { - if ((pShareDataNode->ui32RefCount > 0) && (pShareDataNode->hOSMemHandle == hOSMemHandle)) + if (bFound) { - return pShareDataNode; + bErrorDups = IMG_TRUE; + } + else + { + *pui32SI = ui32SI; + bFound = IMG_TRUE; } } } - return NULL; -} - -static IMG_VOID XProcFreeShareable(IMG_HANDLE hOSMemHandle) -{ - PXProcShareDataNode pShareDataNode; - pShareDataNode = XProcHandleToSI(hOSMemHandle); - if (pShareDataNode == NULL) + if (bErrorDups || !bFound) { - PVR_DPF((PVR_DBG_ERROR, "XProcHandleToSI bad handle %p", hOSMemHandle)); - return; + return PVRSRV_ERROR_BM_BAD_SHAREMEM_HANDLE; } - pShareDataNode->ui32RefCount--; + return PVRSRV_OK; +} + +#if defined(PVRSRV_REFCOUNT_DEBUG) +IMG_VOID _BM_XProcIndexAcquireDebug(const IMG_CHAR *pszFile, IMG_INT iLine, IMG_UINT32 ui32Index) +#else +IMG_VOID _BM_XProcIndexAcquire(IMG_UINT32 ui32Index) +#endif +{ +#if defined(PVRSRV_REFCOUNT_DEBUG) + PVRSRVBMXProcIncRef2(pszFile, iLine, ui32Index); +#else + PVRSRVBMXProcIncRef(ui32Index); +#endif +} - PVR_DPF((PVR_DBG_VERBOSE, "Reduced refcount of Node[%p] from %d to %d", - pShareDataNode, pShareDataNode->ui32RefCount+1, pShareDataNode->ui32RefCount)); +#if defined(PVRSRV_REFCOUNT_DEBUG) +IMG_VOID _BM_XProcIndexReleaseDebug(const IMG_CHAR *pszFile, IMG_INT iLine, IMG_UINT32 ui32Index) +#else +IMG_VOID _BM_XProcIndexRelease(IMG_UINT32 ui32Index) +#endif +{ +#if defined(PVRSRV_REFCOUNT_DEBUG) + PVRSRVBMXProcDecRef2(pszFile, iLine, ui32Index); +#else + PVRSRVBMXProcDecRef(ui32Index); +#endif - if (pShareDataNode->ui32RefCount == 0) + PVR_DPF((PVR_DBG_VERBOSE, "Reduced refcount of SI[%d] from %d to %d", + ui32Index, gXProcWorkaroundShareData[ui32Index].ui32RefCount+1, gXProcWorkaroundShareData[ui32Index].ui32RefCount)); + + if (gXProcWorkaroundShareData[ui32Index].ui32RefCount == 0) { - if (pShareDataNode->psArena != IMG_NULL) + if (gXProcWorkaroundShareData[ui32Index].psArena != IMG_NULL) { IMG_SYS_PHYADDR sSysPAddr; - if (pShareDataNode->pvCpuVAddr != IMG_NULL) + if (gXProcWorkaroundShareData[ui32Index].pvCpuVAddr != IMG_NULL) { - OSUnReservePhys(pShareDataNode->pvCpuVAddr, - pShareDataNode->ui32Size, - pShareDataNode->ui32AllocFlags, - pShareDataNode->hOSMemHandle); + OSUnReservePhys(gXProcWorkaroundShareData[ui32Index].pvCpuVAddr, + gXProcWorkaroundShareData[ui32Index].ui32Size, + gXProcWorkaroundShareData[ui32Index].ui32AllocFlags, + gXProcWorkaroundShareData[ui32Index].hOSMemHandle); } - sSysPAddr = pShareDataNode->sSysPAddr; - RA_Free (pShareDataNode->psArena, + sSysPAddr = gXProcWorkaroundShareData[ui32Index].sSysPAddr; + RA_Free (gXProcWorkaroundShareData[ui32Index].psArena, sSysPAddr.uiAddr, IMG_FALSE); } else { PVR_DPF((PVR_DBG_VERBOSE, "freeing OS memory")); - OSFreePages(pShareDataNode->ui32AllocFlags, - pShareDataNode->ui32PageSize, - pShareDataNode->pvCpuVAddr, - pShareDataNode->hOSMemHandle); + OSFreePages(gXProcWorkaroundShareData[ui32Index].ui32AllocFlags, + gXProcWorkaroundShareData[ui32Index].ui32PageSize, + gXProcWorkaroundShareData[ui32Index].pvCpuVAddr, + gXProcWorkaroundShareData[ui32Index].hOSMemHandle); } - XprocShareObjectDestroy(pShareDataNode); } } +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; + } + + BM_XProcIndexRelease(ui32SI); +} + + +/*! +****************************************************************************** + + @Function BM_ImportMemory + + @Description Provide a resource allocator with a source of pages of memory + from the Host OS's own allocation. Allocates a block of pages + larger than requested, allowing the resource allocator to + operate a small cache of pre allocated pages. + + @Input pH - buffer manager handle, not the void type is dictated + by the generic nature of the resource allocator interface. + @Input uRequestSize - requested size in bytes + @Output pActualSize - receives the actual size allocated in bytes + which may be >= requested size + @Output ppsMapping - receives the arbitrary user reference + associated with the underlying storage. + @Input uFlags - bit mask of allocation flags + @Input pvPrivData - opaque private data passed through to allocator + @Input ui32PrivDataLength - length of opaque private data + @Output pBase - receives a pointer to the allocated storage. + + @Return IMG_TRUE - success + IMG_FALSE - failed + + *****************************************************************************/ 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; @@ -2329,7 +2829,7 @@ BM_ImportMemory (IMG_VOID *pH, IMG_BOOL bResult; IMG_SIZE_T uSize; IMG_SIZE_T uPSize; - IMG_SIZE_T uDevVAddrAlignment = 0; + IMG_SIZE_T uDevVAddrAlignment = 0; /* ? */ PVR_DPF ((PVR_DBG_MESSAGE, "BM_ImportMemory (pBMContext=0x%x, uRequestSize=0x%x, uFlags=0x%x, uAlign=0x%x)", @@ -2361,16 +2861,25 @@ BM_ImportMemory (IMG_VOID *pH, pMapping->DevVAddr.uiAddr = 0; pMapping->CpuPAddr.uiAddr = 0; pMapping->uSize = uSize; + if ((uFlags & PVRSRV_MEM_SPARSE) == 0) + { + pMapping->uSizeVM = uSize; + } pMapping->pBMHeap = pBMHeap; pMapping->ui32Flags = uFlags; pMapping->bUnmapped = IMG_FALSE; - + + /* + * If anyone want's to know, pass back the actual size of our allocation. + * There could be up to an extra page's worth of memory which will be marked + * as free in the RA. + */ if (pActualSize) { *pActualSize = uSize; } - + /* if it's a dummy allocation only use one physical page */ if(pMapping->ui32Flags & PVRSRV_MEM_DUMMY) { uPSize = pBMHeap->sDevArena.ui32DataPageSize; @@ -2385,13 +2894,15 @@ BM_ImportMemory (IMG_VOID *pH, IMG_UINT32 ui32Attribs = pBMHeap->ui32Attribs | PVRSRV_MEM_XPROC; IMG_BOOL bBadBackingStoreType; - bBadBackingStoreType = IMG_TRUE; + if(uFlags & PVRSRV_MEM_ION) + { + ui32Attribs |= PVRSRV_MEM_ION; + } + + bBadBackingStoreType = IMG_TRUE; - if ((ui32Attribs & PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG) != 0) + 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()); @@ -2400,70 +2911,81 @@ BM_ImportMemory (IMG_VOID *pH, PVR_DPF((PVR_DBG_ERROR, "Cannot use use this memory sharing workaround with allocations that might be suballocated")); goto fail_mapping_alloc; } - uDevVAddrAlignment = 0; + uDevVAddrAlignment = 0; /* FIXME: find out why it doesn't work if alignment is specified */ - + /* If the user has specified heap CACHETYPE flags, use them to + * override the flags inherited from the heap. + */ if (pMapping->ui32Flags & PVRSRV_HAP_CACHETYPE_MASK) { ui32Attribs &= ~PVRSRV_HAP_CACHETYPE_MASK; ui32Attribs |= (pMapping->ui32Flags & PVRSRV_HAP_CACHETYPE_MASK); } - - if (XProcAllocShareable(IMG_NULL, - ui32Attribs, - (IMG_UINT32)uPSize, - pBMHeap->sDevArena.ui32DataPageSize, - (IMG_VOID **)&pMapping->CpuVAddr, - &pMapping->hOSMemHandle) != PVRSRV_OK) + /* allocate "shared" pages. */ + 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: XProcAllocShareable(0x%x) failed", uPSize)); + "BM_ImportMemory: XProcWorkaroundAllocShareable(0x%x) failed", + uPSize)); goto fail_mapping_alloc; } - - - + /* specify how page addresses are derived */ + /* it works just like "env" now - no need to record + it as shareable, as we use the actual hOSMemHandle + and only divert to our wrapper layer based on Attribs */ pMapping->eCpuMemoryOrigin = hm_env; - bBadBackingStoreType = IMG_FALSE; + bBadBackingStoreType = IMG_FALSE; } - if ((ui32Attribs & PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG) != 0) + if ((ui32Attribs & PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG) != 0) { - uDevVAddrAlignment = pBMHeap->sDevArena.ui32DataPageSize; + 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; + uDevVAddrAlignment = 0; /* FIXME: find out why it doesn't work if alignment is specified */ - + /* If the user has specified heap CACHETYPE flags, use them to + * override the flags inherited from the heap. + */ if (pMapping->ui32Flags & PVRSRV_HAP_CACHETYPE_MASK) { ui32Attribs &= ~PVRSRV_HAP_CACHETYPE_MASK; ui32Attribs |= (pMapping->ui32Flags & PVRSRV_HAP_CACHETYPE_MASK); } - - if (XProcAllocShareable(pBMHeap->pLocalDevMemArena, + /* allocate "shared" pages. */ + 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: XProcAllocShareable(0x%x) failed", + "BM_ImportMemory: XProcWorkaroundAllocShareable(0x%x) failed", uPSize)); goto fail_mapping_alloc; } - - - + /* specify how page addresses are derived */ + /* it works just like "env" now - no need to record + it as shareable, as we use the actual hOSMemHandle + and only divert to our wrapper layer based on Attribs */ pMapping->eCpuMemoryOrigin = hm_env; bBadBackingStoreType = IMG_FALSE; } @@ -2476,23 +2998,41 @@ BM_ImportMemory (IMG_VOID *pH, } else - - + /* + What type of backing store do we have? + */ if(pBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG) { IMG_UINT32 ui32Attribs = pBMHeap->ui32Attribs; - + /* The allocation code needs to know this is a sparse mapping */ + if (pMapping->ui32Flags & PVRSRV_MEM_SPARSE) + { + ui32Attribs |= PVRSRV_MEM_SPARSE; + } + + /* If the user has specified heap CACHETYPE flags, use them to + * override the flags inherited from the heap. + */ 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); + } + + /* allocate pages from the OS RAM */ if (OSAllocPages(ui32Attribs, uPSize, pBMHeap->sDevArena.ui32DataPageSize, + pvPrivData, + ui32PrivDataLength, + pMapping, (IMG_VOID **)&pMapping->CpuVAddr, &pMapping->hOSMemHandle) != PVRSRV_OK) { @@ -2502,7 +3042,7 @@ BM_ImportMemory (IMG_VOID *pH, goto fail_mapping_alloc; } - + /* specify how page addresses are derived */ pMapping->eCpuMemoryOrigin = hm_env; } else if(pBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG) @@ -2510,10 +3050,18 @@ BM_ImportMemory (IMG_VOID *pH, IMG_SYS_PHYADDR sSysPAddr; IMG_UINT32 ui32Attribs = pBMHeap->ui32Attribs; - + /* The allocation code needs to know this is a sparse mapping */ + if (pMapping->ui32Flags & PVRSRV_MEM_SPARSE) + { + ui32Attribs |= PVRSRV_MEM_SPARSE; + } + + /* allocate pages from the local device memory allocator */ PVR_ASSERT(pBMHeap->pLocalDevMemArena != IMG_NULL); - + /* If the user has specified heap CACHETYPE flags, use them to + * override the flags inherited from the heap. + */ if (pMapping->ui32Flags & PVRSRV_HAP_CACHETYPE_MASK) { ui32Attribs &= ~PVRSRV_HAP_CACHETYPE_MASK; @@ -2527,17 +3075,20 @@ BM_ImportMemory (IMG_VOID *pH, 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; } - + /* derive the CPU virtual address */ pMapping->CpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); if(OSReservePhys(pMapping->CpuPAddr, uPSize, ui32Attribs, + pMapping, &pMapping->CpuVAddr, &pMapping->hOSMemHandle) != PVRSRV_OK) { @@ -2545,7 +3096,7 @@ BM_ImportMemory (IMG_VOID *pH, goto fail_dev_mem_alloc; } - + /* specify how page addresses are derived */ pMapping->eCpuMemoryOrigin = hm_contiguous; } else @@ -2554,26 +3105,32 @@ BM_ImportMemory (IMG_VOID *pH, goto fail_mapping_alloc; } - - bResult = DevMemoryAlloc (pBMContext, - pMapping, - IMG_NULL, - uFlags, - (IMG_UINT32)uDevVAddrAlignment, - &pMapping->DevVAddr); - if (!bResult) + /* + * Allocate some device memory for what we just allocated. + */ + if ((uFlags & PVRSRV_MEM_SPARSE) == 0) { - PVR_DPF((PVR_DBG_ERROR, - "BM_ImportMemory: DevMemoryAlloc(0x%x) failed", - pMapping->uSize)); - goto fail_dev_mem_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); + /* uDevVAddrAlignment is currently set to zero so QAC generates warning which we override */ + /* PRQA S 3356,3358 1 */ + PVR_ASSERT (uDevVAddrAlignment>1?(pMapping->DevVAddr.uiAddr%uDevVAddrAlignment)==0:1); + PVR_ASSERT(pBase); + *pBase = pMapping->DevVAddr.uiAddr; + } - *pBase = pMapping->DevVAddr.uiAddr; *ppsMapping = pMapping; PVR_DPF ((PVR_DBG_MESSAGE, "BM_ImportMemory: IMG_TRUE")); @@ -2582,7 +3139,7 @@ BM_ImportMemory (IMG_VOID *pH, fail_dev_mem_alloc: if (pMapping && (pMapping->CpuVAddr || pMapping->hOSMemHandle)) { - + /* the size is double the actual size for interleaved allocations */ if(pMapping->ui32Flags & PVRSRV_MEM_INTERLEAVED) { pMapping->uSize /= 2; @@ -2599,7 +3156,7 @@ fail_dev_mem_alloc: if (uFlags & PVRSRV_MEM_XPROC) { - XProcFreeShareable(pMapping->hOSMemHandle); + XProcWorkaroundFreeShareable(pMapping->hOSMemHandle); } else if(pBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG) @@ -2626,12 +3183,28 @@ fail_dev_mem_alloc: } fail_mapping_alloc: OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_MAPPING), pMapping, IMG_NULL); - + /*not nulling pointer, out of scope*/ fail_exit: return IMG_FALSE; } +/*! +****************************************************************************** + + @Function BM_FreeMemory + + @Description Free a block of pages previously allocated via + BM_ImportMemory. + + @Input h - buffer manager handle, not the void type as dictated by + the generic nature of the resource allocator interface. + @Input _base - base address of blocks to free. + @Input psMapping - arbitrary user reference associated with the + underlying storage provided by BM_ImportMemory + @Return None + + *****************************************************************************/ static IMG_VOID BM_FreeMemory (IMG_VOID *h, IMG_UINTPTR_T _base, BM_MAPPING *psMapping) { @@ -2652,9 +3225,17 @@ BM_FreeMemory (IMG_VOID *h, IMG_UINTPTR_T _base, BM_MAPPING *psMapping) return; } - DevMemoryFree (psMapping); + /* + Only free the virtual memory if we got as far a allocating it. + This NULL check should be safe as we always have a guard page + at virtual address 0x00000000 + */ + if (psMapping->DevVAddr.uiAddr) + { + DevMemoryFree (psMapping); + } - + /* the size is double the actual for interleaved */ if((psMapping->ui32Flags & PVRSRV_MEM_INTERLEAVED) != 0) { psMapping->uSize /= 2; @@ -2671,7 +3252,7 @@ BM_FreeMemory (IMG_VOID *h, IMG_UINTPTR_T _base, BM_MAPPING *psMapping) if (psMapping->ui32Flags & PVRSRV_MEM_XPROC) { - XProcFreeShareable(psMapping->hOSMemHandle); + XProcWorkaroundFreeShareable(psMapping->hOSMemHandle); } else if(pBMHeap->ui32Attribs & PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG) @@ -2697,13 +3278,30 @@ BM_FreeMemory (IMG_VOID *h, IMG_UINTPTR_T _base, BM_MAPPING *psMapping) } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BM_MAPPING), psMapping, IMG_NULL); - + /*not nulling pointer, copy on stack*/ PVR_DPF((PVR_DBG_MESSAGE, "..BM_FreeMemory (h=0x%x, base=0x%x)", (IMG_UINTPTR_T)h, _base)); } +/*! +****************************************************************************** + + @Function BM_GetPhysPageAddr + + @Description + + @Input psMemInfo + + @Input sDevVPageAddr + + @Output psDevPAddr + + @Return IMG_VOID + +******************************************************************************/ + IMG_VOID BM_GetPhysPageAddr(PVRSRV_KERNEL_MEM_INFO *psMemInfo, IMG_DEV_VIRTADDR sDevVPageAddr, IMG_DEV_PHYADDR *psDevPAddr) @@ -2712,12 +3310,12 @@ IMG_VOID BM_GetPhysPageAddr(PVRSRV_KERNEL_MEM_INFO *psMemInfo, PVR_DPF((PVR_DBG_MESSAGE, "BM_GetPhysPageAddr")); - PVR_ASSERT (psMemInfo && psDevPAddr) + PVR_ASSERT(psMemInfo && psDevPAddr); - + /* check it's a page address */ PVR_ASSERT((sDevVPageAddr.uiAddr & 0xFFF) == 0); - + /* PRQA S 0505 4 */ /* PVR_ASSERT should catch NULL ptrs */ psDeviceNode = ((BM_BUF*)psMemInfo->sMemBlk.hBuffer)->pMapping->pBMHeap->pBMContext->psDeviceNode; *psDevPAddr = psDeviceNode->pfnMMUGetPhysPageAddr(((BM_BUF*)psMemInfo->sMemBlk.hBuffer)->pMapping->pBMHeap->pMMUHeap, @@ -2725,6 +3323,16 @@ IMG_VOID BM_GetPhysPageAddr(PVRSRV_KERNEL_MEM_INFO *psMemInfo, } +/*! +****************************************************************************** + @Function BM_GetMMUContext + + @Description utility function to return the MMU context + + @Input hDevMemHeap - the Dev mem heap handle + + @Return MMU context, else NULL +**************************************************************************/ MMU_CONTEXT* BM_GetMMUContext(IMG_HANDLE hDevMemHeap) { BM_HEAP *pBMHeap = (BM_HEAP*)hDevMemHeap; @@ -2734,6 +3342,16 @@ MMU_CONTEXT* BM_GetMMUContext(IMG_HANDLE hDevMemHeap) return pBMHeap->pBMContext->psMMUContext; } +/*! +****************************************************************************** + @Function BM_GetMMUContextFromMemContext + + @Description utility function to return the MMU context + + @Input hDevMemContext - the Dev mem context handle + + @Return MMU context, else NULL +**************************************************************************/ MMU_CONTEXT* BM_GetMMUContextFromMemContext(IMG_HANDLE hDevMemContext) { BM_CONTEXT *pBMContext = (BM_CONTEXT*)hDevMemContext; @@ -2743,6 +3361,16 @@ MMU_CONTEXT* BM_GetMMUContextFromMemContext(IMG_HANDLE hDevMemContext) return pBMContext->psMMUContext; } +/*! +****************************************************************************** + @Function BM_GetMMUHeap + + @Description utility function to return the MMU heap handle + + @Input hDevMemHeap - the Dev mem heap handle + + @Return MMU heap handle, else NULL +**************************************************************************/ IMG_HANDLE BM_GetMMUHeap(IMG_HANDLE hDevMemHeap) { PVR_DPF((PVR_DBG_VERBOSE, "BM_GetMMUHeap")); @@ -2751,6 +3379,16 @@ IMG_HANDLE BM_GetMMUHeap(IMG_HANDLE hDevMemHeap) } +/*! +****************************************************************************** + @Function BM_GetDeviceNode + + @Description utility function to return the devicenode from the BM Context + + @Input hDevMemContext - the Dev Mem Context + + @Return MMU heap handle, else NULL +**************************************************************************/ PVRSRV_DEVICE_NODE* BM_GetDeviceNode(IMG_HANDLE hDevMemContext) { PVR_DPF((PVR_DBG_VERBOSE, "BM_GetDeviceNode")); @@ -2759,6 +3397,16 @@ PVRSRV_DEVICE_NODE* BM_GetDeviceNode(IMG_HANDLE hDevMemContext) } +/*! +****************************************************************************** + @Function BM_GetMappingHandle + + @Description utility function to return the mapping handle from a meminfo + + @Input psMemInfo - kernel meminfo + + @Return mapping handle, else NULL +**************************************************************************/ IMG_HANDLE BM_GetMappingHandle(PVRSRV_KERNEL_MEM_INFO *psMemInfo) { PVR_DPF((PVR_DBG_VERBOSE, "BM_GetMappingHandle")); @@ -2766,3 +3414,115 @@ IMG_HANDLE BM_GetMappingHandle(PVRSRV_KERNEL_MEM_INFO *psMemInfo) return ((BM_BUF*)psMemInfo->sMemBlk.hBuffer)->pMapping->hOSMemHandle; } +/*! +****************************************************************************** + @Function BM_MappingHandleFromBuffer + + @Description utility function to get the BM mapping handle from a BM buffer + + @Input hBuffer - Handle to BM buffer + + @Return BM mapping handle +**************************************************************************/ +IMG_HANDLE BM_MappingHandleFromBuffer(IMG_HANDLE hBuffer) +{ + BM_BUF *psBuffer; + + PVR_ASSERT(hBuffer != IMG_NULL); + psBuffer = hBuffer; + return psBuffer->pMapping; +} + +/*! +****************************************************************************** + @Function BM_GetVirtualSize + + @Description utility function to get the VM size of a BM mapping + + @Input hBMHandle - Handle to BM mapping + + @Return VM size of mapping +**************************************************************************/ +IMG_UINT32 BM_GetVirtualSize(IMG_HANDLE hBMHandle) +{ + BM_MAPPING *psMapping; + + PVR_ASSERT(hBMHandle != IMG_NULL); + psMapping = hBMHandle; + return psMapping->ui32ChunkSize * psMapping->ui32NumVirtChunks; +} + +/*! +****************************************************************************** + @Function BM_MapPageAtOffset + + @Description utility function check if the specificed offset in a BM mapping + is a page that needs tp be mapped + + @Input hBMHandle - Handle to BM mapping + + @Input ui32Offset - Offset into allocation + + @Return IMG_TRUE if the page should be mapped +**************************************************************************/ +IMG_BOOL BM_MapPageAtOffset(IMG_HANDLE hBMHandle, IMG_UINT32 ui32Offset) +{ + BM_MAPPING *psMapping; + IMG_UINT32 ui32ChunkIndex; + + PVR_ASSERT(hBMHandle != IMG_NULL); + psMapping = hBMHandle; + + ui32ChunkIndex = ui32Offset / psMapping->ui32ChunkSize; + /* Check for overrun */ + PVR_ASSERT(ui32ChunkIndex <= psMapping->ui32NumVirtChunks); + return psMapping->pabMapChunk[ui32ChunkIndex]; +} + +/*! +****************************************************************************** + @Function BM_VirtOffsetToPhyscial + + @Description utility function find of physical offset of a sparse allocation + from it's virtual offset. + + @Input hBMHandle - Handle to BM mapping + + @Input ui32VirtOffset - Virtual offset into allocation + + @Output pui32PhysOffset - Physical offset + + @Return IMG_TRUE if the virtual offset is physically backed +**************************************************************************/ +IMG_BOOL BM_VirtOffsetToPhysical(IMG_HANDLE hBMHandle, + IMG_UINT32 ui32VirtOffset, + IMG_UINT32 *pui32PhysOffset) +{ + BM_MAPPING *psMapping; + IMG_UINT32 ui32ChunkOffset; + IMG_UINT32 ui32PhysOffset = 0; + IMG_UINT32 i; + + PVR_ASSERT(hBMHandle != IMG_NULL); + psMapping = hBMHandle; + + ui32ChunkOffset = ui32VirtOffset / psMapping->ui32ChunkSize; + if (!psMapping->pabMapChunk[ui32ChunkOffset]) + { + return IMG_FALSE; + } + + for (i=0;i<ui32ChunkOffset;i++) + { + if (psMapping->pabMapChunk[i]) + { + ui32PhysOffset += psMapping->ui32ChunkSize; + } + } + *pui32PhysOffset = ui32PhysOffset; + + return IMG_TRUE; +} +/****************************************************************************** + End of file (buffer_manager.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/common/deviceclass.c b/sgx/services4/srvkm/common/deviceclass.c index 3882fdf..9ec4570 100644 --- a/sgx/services4/srvkm/common/deviceclass.c +++ b/sgx/services4/srvkm/common/deviceclass.c @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Device class services functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Kernel services functions for device class devices +@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 "services_headers.h" #include "buffer_manager.h" @@ -45,17 +62,26 @@ void OSVSyncMISR(IMG_HANDLE, IMG_BOOL); IMG_VOID PVRSRVFreeCommandCompletePacketKM(IMG_HANDLE hCmdCookie, IMG_BOOL bScheduleMISR); #endif +/*********************************************************************** + Local Display Class Structures +************************************************************************/ typedef struct PVRSRV_DC_SRV2DISP_KMJTABLE_TAG *PPVRSRV_DC_SRV2DISP_KMJTABLE; +/* + Display Class Buffer Info +*/ typedef struct PVRSRV_DC_BUFFER_TAG { - + /* BC/DC common details - THIS MUST BE THE FIRST MEMBER */ PVRSRV_DEVICECLASS_BUFFER sDeviceClassBuffer; struct PVRSRV_DISPLAYCLASS_INFO_TAG *psDCInfo; struct PVRSRV_DC_SWAPCHAIN_TAG *psSwapChain; } PVRSRV_DC_BUFFER; +/* + Display Device Class kernel swapchain information structure +*/ typedef struct PVRSRV_DC_SWAPCHAIN_TAG { IMG_HANDLE hExtSwapChain; @@ -68,11 +94,18 @@ typedef struct PVRSRV_DC_SWAPCHAIN_TAG PVRSRV_DC_BUFFER *psLastFlipBuffer; IMG_UINT32 ui32MinSwapInterval; IMG_UINT32 ui32MaxSwapInterval; +#if !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) + PVRSRV_KERNEL_SYNC_INFO **ppsLastSyncInfos; + IMG_UINT32 ui32LastNumSyncInfos; +#endif /* !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) */ struct PVRSRV_DISPLAYCLASS_INFO_TAG *psDCInfo; struct PVRSRV_DC_SWAPCHAIN_TAG *psNext; } PVRSRV_DC_SWAPCHAIN; +/* + Display Device Class kernel swapchain referecne structure +*/ typedef struct PVRSRV_DC_SWAPCHAIN_REF_TAG { struct PVRSRV_DC_SWAPCHAIN_TAG *psSwapChain; @@ -80,6 +113,9 @@ typedef struct PVRSRV_DC_SWAPCHAIN_REF_TAG } PVRSRV_DC_SWAPCHAIN_REF; +/* + Display Device Class kernel services information structure +*/ typedef struct PVRSRV_DISPLAYCLASS_INFO_TAG { IMG_UINT32 ui32RefCount; @@ -92,6 +128,9 @@ typedef struct PVRSRV_DISPLAYCLASS_INFO_TAG } PVRSRV_DISPLAYCLASS_INFO; +/* + Per-context Display Device Class kernel services information structure +*/ typedef struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO_TAG { PVRSRV_DISPLAYCLASS_INFO *psDCInfo; @@ -99,17 +138,26 @@ typedef struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO_TAG } PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO; +/*********************************************************************** + Local Buffer Class Structures +************************************************************************/ typedef struct PVRSRV_BC_SRV2BUFFER_KMJTABLE_TAG *PPVRSRV_BC_SRV2BUFFER_KMJTABLE; +/* + Buffer Class Buffer Info +*/ typedef struct PVRSRV_BC_BUFFER_TAG { - + /* BC/DC common details - THIS MUST BE THE FIRST MEMBER */ PVRSRV_DEVICECLASS_BUFFER sDeviceClassBuffer; struct PVRSRV_BUFFERCLASS_INFO_TAG *psBCInfo; } PVRSRV_BC_BUFFER; +/* + Buffer Device Class kernel services information structure +*/ typedef struct PVRSRV_BUFFERCLASS_INFO_TAG { IMG_UINT32 ui32RefCount; @@ -117,13 +165,16 @@ typedef struct PVRSRV_BUFFERCLASS_INFO_TAG IMG_HANDLE hExtDevice; PPVRSRV_BC_SRV2BUFFER_KMJTABLE psFuncTable; IMG_HANDLE hDevMemContext; - + /* buffer info returned from 3rd party driver */ IMG_UINT32 ui32BufferCount; PVRSRV_BC_BUFFER *psBuffer; } PVRSRV_BUFFERCLASS_INFO; +/* + Per-context Buffer Device Class kernel services information structure +*/ typedef struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO_TAG { PVRSRV_BUFFERCLASS_INFO *psBCInfo; @@ -131,6 +182,21 @@ typedef struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO_TAG } PVRSRV_BUFFERCLASS_PERCONTEXT_INFO; +/*! +****************************************************************************** + @Function DCDeviceHandleToDCInfo + + @Description + + Convert a client-visible 3rd party device class handle to an internal + PVRSRV_DISPLAYCLASS_INFO pointer. + + @Input hDeviceKM - handle to display class device, returned from OpenDCDevice + + @Return + success: pointer to PVRSRV_DISPLAYCLASS_INFO + failure: IMG_NULL +******************************************************************************/ static PVRSRV_DISPLAYCLASS_INFO* DCDeviceHandleToDCInfo (IMG_HANDLE hDeviceKM) { PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo; @@ -141,6 +207,21 @@ static PVRSRV_DISPLAYCLASS_INFO* DCDeviceHandleToDCInfo (IMG_HANDLE hDeviceKM) } +/*! +****************************************************************************** + @Function BCDeviceHandleToBCInfo + + @Description + + Convert a client-visible 3rd party buffer class handle to an internal + PVRSRV_BUFFERCLASS_INFO pointer. + + @Input hDeviceKM - handle to buffer class device, returned from OpenBCDevice + + @Return + success: pointer to PVRSRV_BUFFERCLASS_INFO + failure: IMG_NULL +******************************************************************************/ static PVRSRV_BUFFERCLASS_INFO* BCDeviceHandleToBCInfo (IMG_HANDLE hDeviceKM) { PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo; @@ -150,6 +231,20 @@ static PVRSRV_BUFFERCLASS_INFO* BCDeviceHandleToBCInfo (IMG_HANDLE hDeviceKM) return psBCPerContextInfo->psBCInfo; } +/*! +****************************************************************************** + @Function PVRSRVEnumerateDCKM_ForEachVaCb + + @Description + + Enumerates the device node (if is of the same class as given). + + @Input psDeviceNode - The device node to be enumerated + va - variable arguments list, with: + pui32DevCount - The device count pointer (to be increased) + ppui32DevID - The pointer to the device IDs pointer (to be updated and increased) + peDeviceClass - The pointer to the device class of the psDeviceNode's to be enumerated. +******************************************************************************/ static IMG_VOID PVRSRVEnumerateDCKM_ForEachVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va) { IMG_UINT *pui32DevCount; @@ -172,18 +267,40 @@ static IMG_VOID PVRSRVEnumerateDCKM_ForEachVaCb(PVRSRV_DEVICE_NODE *psDeviceNode } +/*! +****************************************************************************** + + @Function PVRSRVEnumerateDCKM + + @Description + + Enumerates devices available in a given class. + On first call, pass valid ptr for pui32DevCount and IMG_NULL for pui32DevID, + On second call, pass same ptr for pui32DevCount and client allocated ptr + for pui32DevID device id list + + @Input hServices - handle for services connection + @Input ui32DevClass - device class identifier + @Output pui32DevCount - number of devices available in class + @Output pui32DevID - list of device ids in the device class + + @Return + success: handle to matching display class device + failure: IMG_NULL + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVEnumerateDCKM (PVRSRV_DEVICE_CLASS DeviceClass, IMG_UINT32 *pui32DevCount, IMG_UINT32 *pui32DevID ) { - + /*PVRSRV_DEVICE_NODE *psDeviceNode;*/ IMG_UINT ui32DevCount = 0; SYS_DATA *psSysData; SysAcquireData(&psSysData); - + /* search devonode list for devices in specified class and return the device ids */ List_PVRSRV_DEVICE_NODE_ForEach_va(psSysData->psDeviceNodeList, &PVRSRVEnumerateDCKM_ForEachVaCb, &ui32DevCount, @@ -204,35 +321,55 @@ PVRSRV_ERROR PVRSRVEnumerateDCKM (PVRSRV_DEVICE_CLASS DeviceClass, } -static -PVRSRV_ERROR PVRSRVRegisterDCDeviceKM (PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable, - IMG_UINT32 *pui32DeviceID) -{ - PVRSRV_DISPLAYCLASS_INFO *psDCInfo = IMG_NULL; - PVRSRV_DEVICE_NODE *psDeviceNode; - SYS_DATA *psSysData; - - - - +/*! +****************************************************************************** + @Function PVRSRVRegisterDCDeviceKM + @Description + registers an external device with the system + @Input psFuncTable : device function table + @Output pui32DeviceID : unique device key (for case of multiple identical devices) + @Return PVRSRV_ERROR : +******************************************************************************/ +static +PVRSRV_ERROR PVRSRVRegisterDCDeviceKM (PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable, + IMG_UINT32 *pui32DeviceID) +{ + PVRSRV_DISPLAYCLASS_INFO *psDCInfo = IMG_NULL; + PVRSRV_DEVICE_NODE *psDeviceNode; + SYS_DATA *psSysData; + /* + IN: + - name of client side ext. device driver library for subsequent loading + - predefined list of callbacks into kernel ext. device driver (based on class type) + FUNCTION TASKS: + - allocate display device class info structure + - hang ext.device kernel callbacks on this structure (pfnKSwapToSystem) + OUT: + - DEVICE_ID + - pass back devinfo? no + Q&A: + - DEVICE_ID passed in or allocated - assume allocate + */ SysAcquireData(&psSysData); - - + /* + If we got this far we're doing dynamic enumeration + or first time static registration + */ - + /* Allocate device control block */ if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psDCInfo), (IMG_VOID **)&psDCInfo, IMG_NULL, @@ -243,7 +380,7 @@ PVRSRV_ERROR PVRSRVRegisterDCDeviceKM (PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable, } OSMemSet (psDCInfo, 0, sizeof(*psDCInfo)); - + /* setup the display device information structure */ if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE), (IMG_VOID **)&psDCInfo->psFuncTable, IMG_NULL, @@ -254,10 +391,10 @@ PVRSRV_ERROR PVRSRVRegisterDCDeviceKM (PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable, } OSMemSet (psDCInfo->psFuncTable, 0, sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE)); - + /* copy the jump table */ *psDCInfo->psFuncTable = *psFuncTable; - + /* Allocate device node */ if(OSAllocMem( PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_DEVICE_NODE), (IMG_VOID **)&psDeviceNode, IMG_NULL, @@ -275,7 +412,7 @@ PVRSRV_ERROR PVRSRVRegisterDCDeviceKM (PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable, psDeviceNode->sDevId.eDeviceClass = PVRSRV_DEVICE_CLASS_DISPLAY; psDeviceNode->psSysData = psSysData; - + /* allocate a unique device id */ if (AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVRegisterDCDeviceKM: "\ @@ -288,10 +425,10 @@ PVRSRV_ERROR PVRSRVRegisterDCDeviceKM (PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable, *pui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex; } - + /* Register the device with the system */ SysRegisterExternalDevice(psDeviceNode); - + /* and finally insert the device into the dev-list */ List_PVRSRV_DEVICE_NODE_Insert(&psSysData->psDeviceNodeList, psDeviceNode); return PVRSRV_OK; @@ -305,11 +442,25 @@ ErrorExit: } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DISPLAYCLASS_INFO), psDCInfo, IMG_NULL); - + /*not nulling pointer, out of scope*/ return PVRSRV_ERROR_OUT_OF_MEMORY; } +/*! +****************************************************************************** + + @Function PVRSRVRemoveDCDeviceKM + + @Description + + Removes external device from services system record + + @Input ui32DeviceIndex : unique device key (for case of multiple identical devices) + + @Return PVRSRV_ERROR : + +******************************************************************************/ static PVRSRV_ERROR PVRSRVRemoveDCDeviceKM(IMG_UINT32 ui32DevIndex) { SYS_DATA *psSysData; @@ -318,7 +469,7 @@ static PVRSRV_ERROR PVRSRVRemoveDCDeviceKM(IMG_UINT32 ui32DevIndex) SysAcquireData(&psSysData); - + /*search the node matching the devindex and display class*/ psDeviceNode = (PVRSRV_DEVICE_NODE*) List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, &MatchDeviceKM_AnyVaCb, @@ -327,37 +478,40 @@ static PVRSRV_ERROR PVRSRVRemoveDCDeviceKM(IMG_UINT32 ui32DevIndex) PVRSRV_DEVICE_CLASS_DISPLAY); if (!psDeviceNode) { - + /*device not found*/ PVR_DPF((PVR_DBG_ERROR,"PVRSRVRemoveDCDeviceKM: requested device %d not present", ui32DevIndex)); return PVRSRV_ERROR_NO_DEVICENODE_FOUND; } - + /* setup DCInfo ptr */ psDCInfo = (PVRSRV_DISPLAYCLASS_INFO*)psDeviceNode->pvDevice; - - - + /* + The device can only be removed if there are + no open connections in the Services interface + */ if(psDCInfo->ui32RefCount == 0) { - - + /* + Remove from the device list. + */ List_PVRSRV_DEVICE_NODE_Remove(psDeviceNode); - + /* Unregister the device with the system */ SysRemoveExternalDevice(psDeviceNode); - - - + /* + OK found a device with a matching devindex + remove registration information + */ PVR_ASSERT(psDCInfo->ui32RefCount == 0); (IMG_VOID)FreeDeviceID(psSysData, ui32DevIndex); (IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE), psDCInfo->psFuncTable, IMG_NULL); psDCInfo->psFuncTable = IMG_NULL; (IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DISPLAYCLASS_INFO), psDCInfo, IMG_NULL); - + /*not nulling original pointer, overwritten*/ (IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DEVICE_NODE), psDeviceNode, IMG_NULL); - + /*not nulling pointer, out of scope*/ } else { @@ -369,6 +523,21 @@ static PVRSRV_ERROR PVRSRVRemoveDCDeviceKM(IMG_UINT32 ui32DevIndex) } +/*! +****************************************************************************** + + @Function PVRSRVRegisterBCDeviceKM + + @Description + + registers an external device with the system + + @Input psFuncTable : device function table + @Input ui32DeviceIndex : unique device key (for case of multiple identical devices) + + @Return PVRSRV_ERROR : + +******************************************************************************/ static PVRSRV_ERROR PVRSRVRegisterBCDeviceKM (PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTable, IMG_UINT32 *pui32DeviceID) @@ -376,26 +545,30 @@ PVRSRV_ERROR PVRSRVRegisterBCDeviceKM (PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTabl PVRSRV_BUFFERCLASS_INFO *psBCInfo = IMG_NULL; PVRSRV_DEVICE_NODE *psDeviceNode; SYS_DATA *psSysData; - - - - - - - - - - + /* + IN: + - name of client side ext. device driver library for subsequent loading + - predefined list of callbacks into kernel ext. device driver (based on class type) + FUNCTION TASKS: + - allocate buffer device class info structure + OUT: + - DEVICE_ID + - pass back devinfo? no + Q&A: + - DEVICE_ID passed in or allocated - assume allcoate + */ SysAcquireData(&psSysData); - - + /* + If we got this far we're doing dynamic enumeration + or first time static registration + */ - + /* Allocate device control block */ if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psBCInfo), (IMG_VOID **)&psBCInfo, IMG_NULL, @@ -406,7 +579,7 @@ PVRSRV_ERROR PVRSRVRegisterBCDeviceKM (PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTabl } OSMemSet (psBCInfo, 0, sizeof(*psBCInfo)); - + /* setup the buffer device information structure */ if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BC_SRV2BUFFER_KMJTABLE), (IMG_VOID **)&psBCInfo->psFuncTable, IMG_NULL, @@ -417,10 +590,10 @@ PVRSRV_ERROR PVRSRVRegisterBCDeviceKM (PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTabl } OSMemSet (psBCInfo->psFuncTable, 0, sizeof(PVRSRV_BC_SRV2BUFFER_KMJTABLE)); - + /* copy the jump table */ *psBCInfo->psFuncTable = *psFuncTable; - + /* Allocate device node */ if(OSAllocMem( PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_DEVICE_NODE), (IMG_VOID **)&psDeviceNode, IMG_NULL, @@ -438,7 +611,7 @@ PVRSRV_ERROR PVRSRVRegisterBCDeviceKM (PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTabl psDeviceNode->sDevId.eDeviceClass = PVRSRV_DEVICE_CLASS_BUFFER; psDeviceNode->psSysData = psSysData; - + /* allocate a unique device id */ if (AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterBCDeviceKM: Failed to allocate Device ID")); @@ -450,7 +623,7 @@ PVRSRV_ERROR PVRSRVRegisterBCDeviceKM (PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTabl *pui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex; } - + /* and finally insert the device into the dev-list */ List_PVRSRV_DEVICE_NODE_Insert(&psSysData->psDeviceNodeList, psDeviceNode); return PVRSRV_OK; @@ -464,12 +637,26 @@ ErrorExit: } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BUFFERCLASS_INFO), psBCInfo, IMG_NULL); - + /*not nulling shared pointer, wasn't allocated to this point*/ return PVRSRV_ERROR_OUT_OF_MEMORY; } +/*! +****************************************************************************** + + @Function PVRSRVRemoveBCDeviceKM + + @Description + + Removes external device from services system record + + @Input ui32DeviceIndex : unique device key (for case of multiple identical devices) + + @Return PVRSRV_ERROR : + +******************************************************************************/ static PVRSRV_ERROR PVRSRVRemoveBCDeviceKM(IMG_UINT32 ui32DevIndex) { SYS_DATA *psSysData; @@ -478,7 +665,7 @@ static PVRSRV_ERROR PVRSRVRemoveBCDeviceKM(IMG_UINT32 ui32DevIndex) SysAcquireData(&psSysData); - + /*search the device node with the devindex and buffer class*/ psDevNode = (PVRSRV_DEVICE_NODE*) List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, &MatchDeviceKM_AnyVaCb, @@ -492,31 +679,33 @@ static PVRSRV_ERROR PVRSRVRemoveBCDeviceKM(IMG_UINT32 ui32DevIndex) return PVRSRV_ERROR_NO_DEVICENODE_FOUND; } - - + /* set-up devnode ptr */ +/* psDevNode = *(ppsDevNode); */ + /* setup BCInfo ptr */ psBCInfo = (PVRSRV_BUFFERCLASS_INFO*)psDevNode->pvDevice; - - - + /* + The device can only be removed if there are + no open connections in the Services interface + */ if(psBCInfo->ui32RefCount == 0) { - - + /* + Remove from the device list. + */ List_PVRSRV_DEVICE_NODE_Remove(psDevNode); - - - + /* + OK found a device with a matching devindex + remove registration information + */ (IMG_VOID)FreeDeviceID(psSysData, ui32DevIndex); - - (IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BC_SRV2BUFFER_KMJTABLE), psBCInfo->psFuncTable, IMG_NULL); psBCInfo->psFuncTable = IMG_NULL; (IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BUFFERCLASS_INFO), psBCInfo, IMG_NULL); - + /*not nulling pointer, copy on stack*/ (IMG_VOID)OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DEVICE_NODE), psDevNode, IMG_NULL); - + /*not nulling pointer, out of scope*/ } else { @@ -529,18 +718,29 @@ static PVRSRV_ERROR PVRSRVRemoveBCDeviceKM(IMG_UINT32 ui32DevIndex) +/*! +****************************************************************************** + + @Function PVRSRVCloseDCDeviceKM + + @Description + + Closes a connection to the Display Class device + + @Input hDeviceKM : device handle + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT -PVRSRV_ERROR PVRSRVCloseDCDeviceKM (IMG_HANDLE hDeviceKM, - IMG_BOOL bResManCallback) +PVRSRV_ERROR PVRSRVCloseDCDeviceKM (IMG_HANDLE hDeviceKM) { PVRSRV_ERROR eError; PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo; - PVR_UNREFERENCED_PARAMETER(bResManCallback); - psDCPerContextInfo = (PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *)hDeviceKM; - + /* Remove the item from the resman list and trigger the callback. */ eError = ResManFreeResByPtr(psDCPerContextInfo->hResItem, CLEANUP_WITH_POLL); return eError; @@ -562,38 +762,49 @@ static PVRSRV_ERROR CloseDCDeviceCallBack(IMG_PVOID pvParam, if(psDCInfo->sSystemBuffer.sDeviceClassBuffer.ui32MemMapRefCount != 0) { - PVR_DPF((PVR_DBG_ERROR,"CloseDCDeviceCallBack: system buffer (0x%p) still mapped (refcount = %d)", + PVR_DPF((PVR_DBG_MESSAGE,"CloseDCDeviceCallBack: system buffer (0x%p) still mapped (refcount = %d)", &psDCInfo->sSystemBuffer.sDeviceClassBuffer, psDCInfo->sSystemBuffer.sDeviceClassBuffer.ui32MemMapRefCount)); - -#if 0 - - return PVRSRV_ERROR_STILL_MAPPED; -#endif } psDCInfo->ui32RefCount--; if(psDCInfo->ui32RefCount == 0) { - + /* close the external device */ psDCInfo->psFuncTable->pfnCloseDCDevice(psDCInfo->hExtDevice); - if (--psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo->ui32RefCount == 0) - { - PVRSRVFreeSyncInfoKM(psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo); - } + PVRSRVKernelSyncInfoDecRef(psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL); psDCInfo->hDevMemContext = IMG_NULL; psDCInfo->hExtDevice = IMG_NULL; } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO), psDCPerContextInfo, IMG_NULL); - + /*not nulling pointer, copy on stack*/ return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVOpenDCDeviceKM + + @Description + + Opens a connection to the Display Class device, associating the connection + with a Device Memory Context for a services managed device + + @Input psPerProc : Per-process data + @Input ui32DeviceID : unique device index + @Input hDevCookie : devcookie used to derive the Device Memory + Context into BC surfaces will be mapped into + @Outut phDeviceKM : handle to the DC device + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVOpenDCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, IMG_UINT32 ui32DeviceID, @@ -614,7 +825,7 @@ PVRSRV_ERROR PVRSRVOpenDCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, SysAcquireData(&psSysData); - + /* find the matching devicenode */ psDeviceNode = (PVRSRV_DEVICE_NODE*) List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, &MatchDeviceKM_AnyVaCb, @@ -628,9 +839,10 @@ PVRSRV_ERROR PVRSRVOpenDCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, } psDCInfo = (PVRSRV_DISPLAYCLASS_INFO*)psDeviceNode->pvDevice; - - - + /* + Allocate the per-context DC Info before calling the external device, + to make error handling easier. + */ if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psDCPerContextInfo), (IMG_VOID **)&psDCPerContextInfo, IMG_NULL, @@ -646,10 +858,10 @@ PVRSRV_ERROR PVRSRVOpenDCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, psDeviceNode = (PVRSRV_DEVICE_NODE *)hDevCookie; - + /* store the device kernel context to map into */ psDCInfo->hDevMemContext = (IMG_HANDLE)psDeviceNode->sDevMemoryInfo.pBMKernelContext; - + /* create a syncinfo for the device's system surface */ eError = PVRSRVAllocSyncInfoKM(IMG_NULL, (IMG_HANDLE)psDeviceNode->sDevMemoryInfo.pBMKernelContext, &psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo); @@ -660,7 +872,7 @@ PVRSRV_ERROR PVRSRVOpenDCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, return eError; } - + /* open the external device */ eError = psDCInfo->psFuncTable->pfnOpenDCDevice(ui32DeviceID, &psDCInfo->hExtDevice, (PVRSRV_SYNC_DATA*)psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM); @@ -668,28 +880,55 @@ PVRSRV_ERROR PVRSRVOpenDCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, { PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenDCDeviceKM: Failed to open external DC device")); psDCInfo->ui32RefCount--; - PVRSRVFreeSyncInfoKM(psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo); + PVRSRVKernelSyncInfoDecRef(psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL); return eError; } - psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo->ui32RefCount++; + psDCPerContextInfo->psDCInfo = psDCInfo; + eError = PVRSRVGetDCSystemBufferKM(psDCPerContextInfo, IMG_NULL); + if(eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenDCDeviceKM: Failed to get system buffer")); + psDCInfo->ui32RefCount--; + PVRSRVKernelSyncInfoDecRef(psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL); + return eError; + } psDCInfo->sSystemBuffer.sDeviceClassBuffer.ui32MemMapRefCount = 0; } + else + { + psDCPerContextInfo->psDCInfo = psDCInfo; + } - psDCPerContextInfo->psDCInfo = psDCInfo; psDCPerContextInfo->hResItem = ResManRegisterRes(psPerProc->hResManContext, RESMAN_TYPE_DISPLAYCLASS_DEVICE, psDCPerContextInfo, 0, &CloseDCDeviceCallBack); - + /* return a reference to the DCPerContextInfo */ *phDeviceKM = (IMG_HANDLE)psDCPerContextInfo; return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVEnumDCFormatsKM + + @Description + + Enumerates the devices pixel formats + + @Input hDeviceKM : device handle + @Output pui32Count : number of pixel formats + @Output psFormat : format list + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVEnumDCFormatsKM (IMG_HANDLE hDeviceKM, IMG_UINT32 *pui32Count, @@ -705,12 +944,29 @@ PVRSRV_ERROR PVRSRVEnumDCFormatsKM (IMG_HANDLE hDeviceKM, psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); - + /* call into the display device driver to get info */ return psDCInfo->psFuncTable->pfnEnumDCFormats(psDCInfo->hExtDevice, pui32Count, psFormat); } +/*! +****************************************************************************** + + @Function PVRSRVEnumDCDimsKM + + @Description + + Enumerates the devices mode dimensions for a given pixel format + + @Input hDeviceKM : device handle + @Input psFormat : pixel format + @Output pui32Count : number of dimensions + @Output psDim : dimensions list + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVEnumDCDimsKM (IMG_HANDLE hDeviceKM, DISPLAY_FORMAT *psFormat, @@ -719,7 +975,7 @@ PVRSRV_ERROR PVRSRVEnumDCDimsKM (IMG_HANDLE hDeviceKM, { PVRSRV_DISPLAYCLASS_INFO *psDCInfo; - if(!hDeviceKM || !pui32Count || !psFormat) + if(!hDeviceKM || !pui32Count || !psFormat) // psDim==NULL to query number of dims { PVR_DPF((PVR_DBG_ERROR,"PVRSRVEnumDCDimsKM: Invalid parameters")); return PVRSRV_ERROR_INVALID_PARAMS; @@ -727,11 +983,26 @@ PVRSRV_ERROR PVRSRVEnumDCDimsKM (IMG_HANDLE hDeviceKM, psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); - + /* call into the display device driver to get info */ return psDCInfo->psFuncTable->pfnEnumDCDims(psDCInfo->hExtDevice, psFormat, pui32Count, psDim); } +/*! +****************************************************************************** + + @Function PVRSRVGetDCSystemBufferKM + + @Description + + Get the primary surface and optionally return its buffer handle + + @Input hDeviceKM : device handle + @Output phBuffer : Optional buffer handle + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVGetDCSystemBufferKM (IMG_HANDLE hDeviceKM, IMG_HANDLE *phBuffer) @@ -740,7 +1011,7 @@ PVRSRV_ERROR PVRSRVGetDCSystemBufferKM (IMG_HANDLE hDeviceKM, PVRSRV_DISPLAYCLASS_INFO *psDCInfo; IMG_HANDLE hExtBuffer; - if(!hDeviceKM || !phBuffer) + if(!hDeviceKM) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetDCSystemBufferKM: Invalid parameters")); return PVRSRV_ERROR_INVALID_PARAMS; @@ -748,7 +1019,7 @@ PVRSRV_ERROR PVRSRVGetDCSystemBufferKM (IMG_HANDLE hDeviceKM, psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); - + /* call into the display device driver to get info */ eError = psDCInfo->psFuncTable->pfnGetDCSystemBuffer(psDCInfo->hExtDevice, &hExtBuffer); if(eError != PVRSRV_OK) { @@ -756,7 +1027,7 @@ PVRSRV_ERROR PVRSRVGetDCSystemBufferKM (IMG_HANDLE hDeviceKM, return eError; } - + /* save the new info */ psDCInfo->sSystemBuffer.sDeviceClassBuffer.pfnGetBufferAddr = psDCInfo->psFuncTable->pfnGetBufferAddr; psDCInfo->sSystemBuffer.sDeviceClassBuffer.hDevMemContext = psDCInfo->hDevMemContext; psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtDevice = psDCInfo->hExtDevice; @@ -764,13 +1035,30 @@ PVRSRV_ERROR PVRSRVGetDCSystemBufferKM (IMG_HANDLE hDeviceKM, psDCInfo->sSystemBuffer.psDCInfo = psDCInfo; - - *phBuffer = (IMG_HANDLE)&(psDCInfo->sSystemBuffer); + /* return handle */ + if (phBuffer) + { + *phBuffer = (IMG_HANDLE)&(psDCInfo->sSystemBuffer); + } return PVRSRV_OK; } +/****************************************************************************** + + @Function PVRSRVGetDCInfoKM + + @Description + + Gets Display Class device Info + + @Input hDeviceKM : device handle + @Output psDisplayInfo + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVGetDCInfoKM (IMG_HANDLE hDeviceKM, DISPLAY_INFO *psDisplayInfo) @@ -786,7 +1074,7 @@ PVRSRV_ERROR PVRSRVGetDCInfoKM (IMG_HANDLE hDeviceKM, psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); - + /* call into the display device driver to get info */ eError = psDCInfo->psFuncTable->pfnGetDCInfo(psDCInfo->hExtDevice, psDisplayInfo); if (eError != PVRSRV_OK) { @@ -828,7 +1116,7 @@ static PVRSRV_ERROR DestroyDCSwapChain(PVRSRV_DC_SWAPCHAIN *psSwapChain) PVRSRV_DISPLAYCLASS_INFO *psDCInfo = psSwapChain->psDCInfo; IMG_UINT32 i; - + /* Update shared swapchains list */ if( psDCInfo->psDCSwapChainShared ) { if( psDCInfo->psDCSwapChainShared == psSwapChain ) @@ -852,10 +1140,10 @@ static PVRSRV_ERROR DestroyDCSwapChain(PVRSRV_DC_SWAPCHAIN *psSwapChain) } } - + /* Destroy command queue before swapchain - it may use the swapchain when commands are flushed. */ PVRSRVDestroyCommandQueueKM(psSwapChain->psQueue); - + /* call into the display device driver to destroy a swapchain */ eError = psDCInfo->psFuncTable->pfnDestroyDCSwapChain(psDCInfo->hExtDevice, psSwapChain->hExtSwapChain); @@ -865,20 +1153,25 @@ static PVRSRV_ERROR DestroyDCSwapChain(PVRSRV_DC_SWAPCHAIN *psSwapChain) return eError; } - + /* free the resources */ for(i=0; i<psSwapChain->ui32BufferCount; i++) { if(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo) { - if (--psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->ui32RefCount == 0) - { - PVRSRVFreeSyncInfoKM(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo); - } + PVRSRVKernelSyncInfoDecRef(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL); } } +#if !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) + if (psSwapChain->ppsLastSyncInfos) + { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_KERNEL_SYNC_INFO *) * psSwapChain->ui32LastNumSyncInfos, + psSwapChain->ppsLastSyncInfos, IMG_NULL); + } +#endif /* !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) */ + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SWAPCHAIN), psSwapChain, IMG_NULL); - + /*not nulling pointer, copy on stack*/ return eError; } @@ -902,10 +1195,6 @@ static PVRSRV_ERROR DestroyDCSwapChainRefCallBack(IMG_PVOID pvParam, PVR_DPF((PVR_DBG_ERROR, "DestroyDCSwapChainRefCallBack: swapchain (0x%p) still mapped (ui32MemMapRefCount = %d)", &psSwapChainRef->psSwapChain->asBuffer[i].sDeviceClassBuffer, psSwapChainRef->psSwapChain->asBuffer[i].sDeviceClassBuffer.ui32MemMapRefCount)); -#if 0 - - return PVRSRV_ERROR_STILL_MAPPED; -#endif } } @@ -939,7 +1228,7 @@ static PVRSRV_ERROR PVRSRVCreateDCSwapChainRefKM(PVRSRV_PER_PROCESS_DATA *psPerP { PVRSRV_DC_SWAPCHAIN_REF *psSwapChainRef = IMG_NULL; - + /* Allocate swapchain reference structre*/ if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SWAPCHAIN_REF), (IMG_VOID **)&psSwapChainRef, IMG_NULL, @@ -950,10 +1239,10 @@ static PVRSRV_ERROR PVRSRVCreateDCSwapChainRefKM(PVRSRV_PER_PROCESS_DATA *psPerP } OSMemSet (psSwapChainRef, 0, sizeof(PVRSRV_DC_SWAPCHAIN_REF)); - + /* Bump refcount */ psSwapChain->ui32RefCount++; - + /* Create reference resource */ psSwapChainRef->psSwapChain = psSwapChain; psSwapChainRef->hResItem = ResManRegisterRes(psPerProc->hResManContext, RESMAN_TYPE_DISPLAYCLASS_SWAPCHAIN_REF, @@ -1013,11 +1302,11 @@ PVRSRV_ERROR PVRSRVCreateDCSwapChainKM (PVRSRV_PER_PROCESS_DATA *psPerProc, if( ui32Flags & PVRSRV_CREATE_SWAPCHAIN_QUERY ) { - + /* Query - use pui32SwapChainID as input */ psSwapChain = PVRSRVFindSharedDCSwapChainKM(psDCInfo, *pui32SwapChainID ); if( psSwapChain ) { - + /* Create new reference */ eError = PVRSRVCreateDCSwapChainRefKM(psPerProc, psSwapChain, &psSwapChainRef); @@ -1034,7 +1323,7 @@ PVRSRV_ERROR PVRSRVCreateDCSwapChainKM (PVRSRV_PER_PROCESS_DATA *psPerProc, return PVRSRV_ERROR_FLIP_CHAIN_EXISTS; } - + /* Allocate swapchain control structure for srvkm */ if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SWAPCHAIN), (IMG_VOID **)&psSwapChain, IMG_NULL, @@ -1046,7 +1335,7 @@ PVRSRV_ERROR PVRSRVCreateDCSwapChainKM (PVRSRV_PER_PROCESS_DATA *psPerProc, } OSMemSet (psSwapChain, 0, sizeof(PVRSRV_DC_SWAPCHAIN)); - + /* Create a command queue for the swapchain */ eError = PVRSRVCreateCommandQueueKM(1024, &psQueue); if(eError != PVRSRV_OK) { @@ -1054,10 +1343,10 @@ PVRSRV_ERROR PVRSRVCreateDCSwapChainKM (PVRSRV_PER_PROCESS_DATA *psPerProc, goto ErrorExit; } - + /* store the Queue */ psSwapChain->psQueue = psQueue; - + /* Create a Sync Object for each surface in the swapchain */ for(i=0; i<ui32BufferCount; i++) { eError = PVRSRVAllocSyncInfoKM(IMG_NULL, @@ -1069,18 +1358,16 @@ PVRSRV_ERROR PVRSRVCreateDCSwapChainKM (PVRSRV_PER_PROCESS_DATA *psPerProc, goto ErrorExit; } - psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->ui32RefCount++; - - + /* setup common device class info */ psSwapChain->asBuffer[i].sDeviceClassBuffer.pfnGetBufferAddr = psDCInfo->psFuncTable->pfnGetBufferAddr; psSwapChain->asBuffer[i].sDeviceClassBuffer.hDevMemContext = psDCInfo->hDevMemContext; psSwapChain->asBuffer[i].sDeviceClassBuffer.hExtDevice = psDCInfo->hExtDevice; - + /* save off useful ptrs */ psSwapChain->asBuffer[i].psDCInfo = psDCInfo; psSwapChain->asBuffer[i].psSwapChain = psSwapChain; - + /* syncinfos must be passed as array of syncdata ptrs to the 3rd party driver */ apsSyncData[i] = (PVRSRV_SYNC_DATA*)psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM; } @@ -1109,7 +1396,7 @@ PVRSRV_ERROR PVRSRVCreateDCSwapChainKM (PVRSRV_PER_PROCESS_DATA *psPerProc, psSwapChain->ui32MinSwapInterval = sDisplayInfo.ui32MinSwapInterval; psSwapChain->ui32MaxSwapInterval = sDisplayInfo.ui32MaxSwapInterval; - + /* call into the display device driver to create a swapchain */ eError = psDCInfo->psFuncTable->pfnCreateDCSwapChain(psDCInfo->hExtDevice, ui32Flags, psDstSurfAttrib, @@ -1126,7 +1413,7 @@ PVRSRV_ERROR PVRSRVCreateDCSwapChainKM (PVRSRV_PER_PROCESS_DATA *psPerProc, goto ErrorExit; } - + /* Create new reference */ eError = PVRSRVCreateDCSwapChainRefKM(psPerProc, psSwapChain, &psSwapChainRef); @@ -1140,7 +1427,7 @@ PVRSRV_ERROR PVRSRVCreateDCSwapChainKM (PVRSRV_PER_PROCESS_DATA *psPerProc, psSwapChain->ui32RefCount = 1; psSwapChain->ui32Flags = ui32Flags; - + /* Save pointer in DC structure if ti's shared struct */ if( ui32Flags & PVRSRV_CREATE_SWAPCHAIN_SHARED ) { if(! psDCInfo->psDCSwapChainShared ) @@ -1155,10 +1442,10 @@ PVRSRV_ERROR PVRSRVCreateDCSwapChainKM (PVRSRV_PER_PROCESS_DATA *psPerProc, } } - + /* We create swapchain - pui32SwapChainID is output */ *pui32SwapChainID = psSwapChain->ui32SwapChainID; - + /* return the swapchain reference handle */ *phSwapChainRef= (IMG_HANDLE)psSwapChainRef; return eError; @@ -1169,10 +1456,7 @@ ErrorExit: { if(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo) { - if (--psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->ui32RefCount == 0) - { - PVRSRVFreeSyncInfoKM(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo); - } + PVRSRVKernelSyncInfoDecRef(psSwapChain->asBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL); } } @@ -1184,7 +1468,7 @@ ErrorExit: if(psSwapChain) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_SWAPCHAIN), psSwapChain, IMG_NULL); - + /*not nulling pointer, out of scope*/ } return eError; @@ -1289,7 +1573,8 @@ IMG_EXPORT PVRSRV_ERROR PVRSRVGetDCBuffersKM(IMG_HANDLE hDeviceKM, IMG_HANDLE hSwapChainRef, IMG_UINT32 *pui32BufferCount, - IMG_HANDLE *phBuffer) + IMG_HANDLE *phBuffer, + IMG_SYS_PHYADDR *psPhyAddr) { PVRSRV_DISPLAYCLASS_INFO *psDCInfo; PVRSRV_DC_SWAPCHAIN *psSwapChain; @@ -1297,7 +1582,7 @@ PVRSRV_ERROR PVRSRVGetDCBuffersKM(IMG_HANDLE hDeviceKM, PVRSRV_ERROR eError; IMG_UINT32 i; - if(!hDeviceKM || !hSwapChainRef || !phBuffer) + if(!hDeviceKM || !hSwapChainRef || !phBuffer || !psPhyAddr) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetDCBuffersKM: Invalid parameters")); return PVRSRV_ERROR_INVALID_PARAMS; @@ -1306,7 +1591,7 @@ PVRSRV_ERROR PVRSRVGetDCBuffersKM(IMG_HANDLE hDeviceKM, psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); psSwapChain = ((PVRSRV_DC_SWAPCHAIN_REF*)hSwapChainRef)->psSwapChain; - + /* call into the display device driver to get info */ eError = psDCInfo->psFuncTable->pfnGetDCBuffers(psDCInfo->hExtDevice, psSwapChain->hExtSwapChain, pui32BufferCount, @@ -1314,15 +1599,42 @@ PVRSRV_ERROR PVRSRVGetDCBuffersKM(IMG_HANDLE hDeviceKM, PVR_ASSERT(*pui32BufferCount <= PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS); - - - + /* + populate the srvkm's buffer structure with the 3rd party buffer handles + and return the services buffer handles + */ for(i=0; i<*pui32BufferCount; i++) { psSwapChain->asBuffer[i].sDeviceClassBuffer.hExtBuffer = ahExtBuffer[i]; phBuffer[i] = (IMG_HANDLE)&psSwapChain->asBuffer[i]; } +#if defined(SUPPORT_GET_DC_BUFFERS_SYS_PHYADDRS) + for(i = 0; i < *pui32BufferCount; i++) + { + IMG_UINT32 ui32ByteSize, ui32TilingStride; + IMG_SYS_PHYADDR *pPhyAddr; + IMG_BOOL bIsContiguous; + IMG_HANDLE hOSMapInfo; + IMG_VOID *pvVAddr; + + eError = psDCInfo->psFuncTable->pfnGetBufferAddr(psDCInfo->hExtDevice, + ahExtBuffer[i], + &pPhyAddr, + &ui32ByteSize, + &pvVAddr, + &hOSMapInfo, + &bIsContiguous, + &ui32TilingStride); + if(eError != PVRSRV_OK) + { + break; + } + + psPhyAddr[i] = *pPhyAddr; + } +#endif /* defined(SUPPORT_GET_DC_BUFFERS_SYS_PHYADDRS) */ + return eError; } @@ -1357,7 +1669,7 @@ PVRSRV_ERROR PVRSRVSwapToDCBufferKM(IMG_HANDLE hDeviceKM, psBuffer = (PVRSRV_DC_BUFFER*)hBuffer; psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); - + /* Validate swap interval against limits */ if(ui32SwapInterval < psBuffer->psSwapChain->ui32MinSwapInterval || ui32SwapInterval > psBuffer->psSwapChain->ui32MaxSwapInterval) { @@ -1381,25 +1693,19 @@ PVRSRV_ERROR PVRSRVSwapToDCBufferKM(IMG_HANDLE hDeviceKM, #endif - + /* get the queue from the buffer structure */ psQueue = psBuffer->psSwapChain->psQueue; - + /* specify the syncs */ apsSrcSync[0] = psBuffer->sDeviceClassBuffer.psKernelSyncInfo; - - - if(bAddReferenceToLast && psBuffer->psSwapChain->psLastFlipBuffer && psBuffer != psBuffer->psSwapChain->psLastFlipBuffer) { apsSrcSync[1] = psBuffer->psSwapChain->psLastFlipBuffer->sDeviceClassBuffer.psKernelSyncInfo; - - - ui32NumSrcSyncs++; } - + /* insert the command (header) */ eError = PVRSRVInsertCommandKM (psQueue, &psCommand, psDCInfo->ui32DeviceID, @@ -1408,42 +1714,68 @@ PVRSRV_ERROR PVRSRVSwapToDCBufferKM(IMG_HANDLE hDeviceKM, IMG_NULL, ui32NumSrcSyncs, apsSrcSync, - sizeof(DISPLAYCLASS_FLIP_COMMAND) + (sizeof(IMG_RECT) * ui32ClipRectCount)); + sizeof(DISPLAYCLASS_FLIP_COMMAND) + (sizeof(IMG_RECT) * ui32ClipRectCount), + IMG_NULL, + IMG_NULL); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBufferKM: Failed to get space in queue")); goto Exit; } - + /* setup the flip command */ psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)psCommand->pvData; - + /* Ext Device Handle */ psFlipCmd->hExtDevice = psDCInfo->hExtDevice; - + /* Ext SwapChain Handle */ psFlipCmd->hExtSwapChain = psBuffer->psSwapChain->hExtSwapChain; - + /* Ext Buffer Handle (Buffer to Flip to) */ psFlipCmd->hExtBuffer = psBuffer->sDeviceClassBuffer.hExtBuffer; - + /* private tag */ psFlipCmd->hPrivateTag = hPrivateTag; - + /* setup the clip rects */ psFlipCmd->ui32ClipRectCount = ui32ClipRectCount; - - psFlipCmd->psClipRect = (IMG_RECT*)((IMG_UINT8*)psFlipCmd + sizeof(DISPLAYCLASS_FLIP_COMMAND)); - + /* cliprect memory appends the command structure */ + psFlipCmd->psClipRect = (IMG_RECT*)((IMG_UINT8*)psFlipCmd + sizeof(DISPLAYCLASS_FLIP_COMMAND)); // PRQA S 3305 + /* copy the clip rects */ for(i=0; i<ui32ClipRectCount; i++) { psFlipCmd->psClipRect[i] = psClipRect[i]; } - + /* number of vsyncs between successive flips */ psFlipCmd->ui32SwapInterval = ui32SwapInterval; - + SysAcquireData(&psSysData); + + /* Because we might be composing just software surfaces, without + * any SGX renders since the last frame, we won't necessarily + * have cleaned/flushed the CPU caches before the buffers need + * to be displayed. + * + * Doing so now is safe because InsertCommand bumped ROP2 on the + * affected buffers (preventing more SW renders starting) but the + * display won't start to process the buffers until SubmitCommand. + */ + { + if(psSysData->ePendingCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_FLUSH) + { + OSFlushCPUCacheKM(); + } + else if(psSysData->ePendingCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_CLEAN) + { + OSCleanCPUCacheKM(); + } + + psSysData->ePendingCacheOpType = PVRSRV_MISC_INFO_CPUCACHEOP_NONE; + } + + /* submit the command */ eError = PVRSRVSubmitCommandKM (psQueue, psCommand); if (eError != PVRSRV_OK) { @@ -1451,9 +1783,9 @@ PVRSRV_ERROR PVRSRVSwapToDCBufferKM(IMG_HANDLE hDeviceKM, goto Exit; } - - - SysAcquireData(&psSysData); + /* + Schedule an MISR to process it + */ eError = OSScheduleMISR(psSysData); if (eError != PVRSRV_OK) @@ -1462,7 +1794,7 @@ PVRSRV_ERROR PVRSRVSwapToDCBufferKM(IMG_HANDLE hDeviceKM, goto Exit; } - + /* update the last flip buffer */ psBuffer->psSwapChain->psLastFlipBuffer = psBuffer; Exit: @@ -1475,6 +1807,288 @@ Exit: return eError; } +typedef struct _CALLBACK_DATA_ +{ + IMG_PVOID pvPrivData; + IMG_UINT32 ui32PrivDataLength; + IMG_PVOID ppvMemInfos; + IMG_UINT32 ui32NumMemInfos; +} CALLBACK_DATA; + +static IMG_VOID FreePrivateData(IMG_HANDLE hCallbackData) +{ + CALLBACK_DATA *psCallbackData = hCallbackData; + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, psCallbackData->ui32PrivDataLength, + psCallbackData->pvPrivData, IMG_NULL); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(IMG_VOID *) * psCallbackData->ui32NumMemInfos, + psCallbackData->ppvMemInfos, IMG_NULL); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(CALLBACK_DATA), hCallbackData, IMG_NULL); +} + +IMG_EXPORT +PVRSRV_ERROR PVRSRVSwapToDCBuffer2KM(IMG_HANDLE hDeviceKM, + IMG_HANDLE hSwapChain, + IMG_UINT32 ui32SwapInterval, + PVRSRV_KERNEL_MEM_INFO **ppsMemInfos, + PVRSRV_KERNEL_SYNC_INFO **ppsSyncInfos, + IMG_UINT32 ui32NumMemSyncInfos, + IMG_PVOID pvPrivData, + IMG_UINT32 ui32PrivDataLength) +{ + PVRSRV_KERNEL_SYNC_INFO **ppsCompiledSyncInfos; + IMG_UINT32 i, ui32NumCompiledSyncInfos; + DISPLAYCLASS_FLIP_COMMAND2 *psFlipCmd; + PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + PVRSRV_DC_SWAPCHAIN *psSwapChain; + PVRSRV_ERROR eError = PVRSRV_OK; + CALLBACK_DATA *psCallbackData; + PVRSRV_QUEUE_INFO *psQueue; + PVRSRV_COMMAND *psCommand; + IMG_PVOID *ppvMemInfos; + SYS_DATA *psSysData; + + if(!hDeviceKM || !hSwapChain || !ppsMemInfos || !ppsSyncInfos || ui32NumMemSyncInfos < 1) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Invalid parameters")); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psSwapChain = ((PVRSRV_DC_SWAPCHAIN_REF*)hSwapChain)->psSwapChain; + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + + /* Validate swap interval against limits */ + if(ui32SwapInterval < psSwapChain->ui32MinSwapInterval || + ui32SwapInterval > psSwapChain->ui32MaxSwapInterval) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Invalid swap interval. Requested %u, Allowed range %u-%u", + ui32SwapInterval, psSwapChain->ui32MinSwapInterval, psSwapChain->ui32MaxSwapInterval)); + return PVRSRV_ERROR_INVALID_SWAPINTERVAL; + } + + eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(CALLBACK_DATA), + (IMG_VOID **)&psCallbackData, IMG_NULL, + "PVRSRVSwapToDCBuffer2KM callback data"); + if (eError != PVRSRV_OK) + { + return eError; + } + + psCallbackData->pvPrivData = pvPrivData; + psCallbackData->ui32PrivDataLength = ui32PrivDataLength; + + if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(IMG_VOID *) * ui32NumMemSyncInfos, + (IMG_VOID **)&ppvMemInfos, IMG_NULL, + "Swap Command Meminfos") != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to allocate space for meminfo list")); + psCallbackData->ppvMemInfos = IMG_NULL; + goto Exit; + } + + for(i = 0; i < ui32NumMemSyncInfos; i++) + { + ppvMemInfos[i] = ppsMemInfos[i]; + } + + psCallbackData->ppvMemInfos = ppvMemInfos; + psCallbackData->ui32NumMemInfos = ui32NumMemSyncInfos; + + /* get the queue from the buffer structure */ + psQueue = psSwapChain->psQueue; + +#if !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) + if(psSwapChain->ppsLastSyncInfos) + { + IMG_UINT32 ui32NumUniqueSyncInfos = psSwapChain->ui32LastNumSyncInfos; + IMG_UINT32 j; + + for(j = 0; j < psSwapChain->ui32LastNumSyncInfos; j++) + { + for(i = 0; i < ui32NumMemSyncInfos; i++) + { + if(psSwapChain->ppsLastSyncInfos[j] == ppsSyncInfos[i]) + { + psSwapChain->ppsLastSyncInfos[j] = IMG_NULL; + ui32NumUniqueSyncInfos--; + } + } + } + + ui32NumCompiledSyncInfos = ui32NumMemSyncInfos + ui32NumUniqueSyncInfos; + + if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(PVRSRV_KERNEL_SYNC_INFO *) * ui32NumCompiledSyncInfos, + (IMG_VOID **)&ppsCompiledSyncInfos, IMG_NULL, + "Compiled syncinfos") != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to allocate space for meminfo list")); + goto Exit; + } + + OSMemCopy(ppsCompiledSyncInfos, ppsSyncInfos, sizeof(PVRSRV_KERNEL_SYNC_INFO *) * ui32NumMemSyncInfos); + for(j = 0, i = ui32NumMemSyncInfos; j < psSwapChain->ui32LastNumSyncInfos; j++) + { + if(psSwapChain->ppsLastSyncInfos[j]) + { + ppsCompiledSyncInfos[i] = psSwapChain->ppsLastSyncInfos[j]; + i++; + } + } + } + else +#endif /* !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) */ + { + ppsCompiledSyncInfos = ppsSyncInfos; + ui32NumCompiledSyncInfos = ui32NumMemSyncInfos; + } + + /* insert the command (header) */ + eError = PVRSRVInsertCommandKM (psQueue, + &psCommand, + psDCInfo->ui32DeviceID, + DC_FLIP_COMMAND, + 0, + IMG_NULL, + ui32NumCompiledSyncInfos, + ppsCompiledSyncInfos, + sizeof(DISPLAYCLASS_FLIP_COMMAND2), + FreePrivateData, + psCallbackData); + + if (ppsCompiledSyncInfos != ppsSyncInfos) + { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(PVRSRV_KERNEL_SYNC_INFO *) * ui32NumCompiledSyncInfos, + (IMG_VOID *)ppsCompiledSyncInfos, + IMG_NULL); + } + if(eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to get space in queue")); + goto Exit; + } + + /* setup the flip command */ + psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND2*)psCommand->pvData; + + /* Ext Device Handle */ + psFlipCmd->hExtDevice = psDCInfo->hExtDevice; + + /* Ext SwapChain Handle */ + psFlipCmd->hExtSwapChain = psSwapChain->hExtSwapChain; + + /* number of vsyncs between successive flips */ + psFlipCmd->ui32SwapInterval = ui32SwapInterval; + + /* Opaque private data, if supplied */ + psFlipCmd->pvPrivData = pvPrivData; + psFlipCmd->ui32PrivDataLength = ui32PrivDataLength; + + psFlipCmd->ppsMemInfos = (PDC_MEM_INFO *)ppvMemInfos; + psFlipCmd->ui32NumMemInfos = ui32NumMemSyncInfos; + + /* Even though this is "unused", we have to initialize it, + * as the display controller might NULL-test it. + */ + psFlipCmd->hUnused = IMG_NULL; + + SysAcquireData(&psSysData); + + /* Because we might be composing just software surfaces, without + * any SGX renders since the last frame, we won't necessarily + * have cleaned/flushed the CPU caches before the buffers need + * to be displayed. + * + * Doing so now is safe because InsertCommand bumped ROP2 on the + * affected buffers (preventing more SW renders starting) but the + * display won't start to process the buffers until SubmitCommand. + */ + { + if(psSysData->ePendingCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_FLUSH) + { + OSFlushCPUCacheKM(); + } + else if(psSysData->ePendingCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_CLEAN) + { + OSCleanCPUCacheKM(); + } + + psSysData->ePendingCacheOpType = PVRSRV_MISC_INFO_CPUCACHEOP_NONE; + } + + /* submit the command */ + eError = PVRSRVSubmitCommandKM (psQueue, psCommand); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to submit command")); + goto Exit; + } + + /* The command has been submitted and so psCallbackData will be freed by the callback */ + psCallbackData = IMG_NULL; + + /* + Schedule an MISR to process it + */ + eError = OSScheduleMISR(psSysData); + + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to schedule MISR")); + goto Exit; + } + +#if !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) + /* Reallocate the syncinfo list if it was too small */ + if (psSwapChain->ui32LastNumSyncInfos < ui32NumMemSyncInfos) + { + if (psSwapChain->ppsLastSyncInfos) + { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_KERNEL_SYNC_INFO *) * psSwapChain->ui32LastNumSyncInfos, + psSwapChain->ppsLastSyncInfos, IMG_NULL); + } + + if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(PVRSRV_KERNEL_SYNC_INFO *) * ui32NumMemSyncInfos, + (IMG_VOID **)&psSwapChain->ppsLastSyncInfos, IMG_NULL, + "Last syncinfos") != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCBuffer2KM: Failed to allocate space for meminfo list")); + goto Exit; + } + } + + psSwapChain->ui32LastNumSyncInfos = ui32NumMemSyncInfos; + + for(i = 0; i < ui32NumMemSyncInfos; i++) + { + psSwapChain->ppsLastSyncInfos[i] = ppsSyncInfos[i]; + } +#endif /* !defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) */ + +Exit: + if (psCallbackData) + { + if(psCallbackData->ppvMemInfos) + { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(IMG_VOID *) * psCallbackData->ui32NumMemInfos, + psCallbackData->ppvMemInfos, IMG_NULL); + } + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(CALLBACK_DATA), psCallbackData, IMG_NULL); + } + if(eError == PVRSRV_ERROR_CANNOT_GET_QUEUE_SPACE) + { + eError = PVRSRV_ERROR_RETRY; + } + + return eError; +} + IMG_EXPORT PVRSRV_ERROR PVRSRVSwapToDCSystemKM(IMG_HANDLE hDeviceKM, @@ -1503,7 +2117,7 @@ PVRSRV_ERROR PVRSRVSwapToDCSystemKM(IMG_HANDLE hDeviceKM, psSwapChainRef = (PVRSRV_DC_SWAPCHAIN_REF*)hSwapChainRef; psSwapChain = psSwapChainRef->psSwapChain; - + /* get the queue from the buffer structure */ psQueue = psSwapChain->psQueue; #if defined(SUPPORT_CUSTOM_SWAP_OPERATIONS) @@ -1521,25 +2135,19 @@ PVRSRV_ERROR PVRSRVSwapToDCSystemKM(IMG_HANDLE hDeviceKM, #endif - + /* specify the syncs */ apsSrcSync[0] = psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo; - - - if(bAddReferenceToLast && psSwapChain->psLastFlipBuffer) { - + /* Make sure we don't make a double dependency on the same server */ if (apsSrcSync[0] != psSwapChain->psLastFlipBuffer->sDeviceClassBuffer.psKernelSyncInfo) { apsSrcSync[1] = psSwapChain->psLastFlipBuffer->sDeviceClassBuffer.psKernelSyncInfo; - - - ui32NumSrcSyncs++; } } - + /* insert the command (header) */ eError = PVRSRVInsertCommandKM (psQueue, &psCommand, psDCInfo->ui32DeviceID, @@ -1548,34 +2156,36 @@ PVRSRV_ERROR PVRSRVSwapToDCSystemKM(IMG_HANDLE hDeviceKM, IMG_NULL, ui32NumSrcSyncs, apsSrcSync, - sizeof(DISPLAYCLASS_FLIP_COMMAND)); + sizeof(DISPLAYCLASS_FLIP_COMMAND), + IMG_NULL, + IMG_NULL); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVSwapToDCSystemKM: Failed to get space in queue")); goto Exit; } - + /* setup the flip command */ psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)psCommand->pvData; - + /* Ext Device Handle */ psFlipCmd->hExtDevice = psDCInfo->hExtDevice; - + /* Ext SwapChain Handle */ psFlipCmd->hExtSwapChain = psSwapChain->hExtSwapChain; - + /* Ext Buffer Handle (Buffer to Flip to) */ psFlipCmd->hExtBuffer = psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtBuffer; - + /* private tag */ psFlipCmd->hPrivateTag = IMG_NULL; - + /* setup the clip rects */ psFlipCmd->ui32ClipRectCount = 0; psFlipCmd->ui32SwapInterval = 1; - + /* submit the command */ eError = PVRSRVSubmitCommandKM (psQueue, psCommand); if (eError != PVRSRV_OK) { @@ -1583,7 +2193,7 @@ PVRSRV_ERROR PVRSRVSwapToDCSystemKM(IMG_HANDLE hDeviceKM, goto Exit; } - + /* Schedule an MISR to process it */ SysAcquireData(&psSysData); eError = OSScheduleMISR(psSysData); @@ -1593,7 +2203,7 @@ PVRSRV_ERROR PVRSRVSwapToDCSystemKM(IMG_HANDLE hDeviceKM, goto Exit; } - + /* update the last flip buffer */ psSwapChain->psLastFlipBuffer = &psDCInfo->sSystemBuffer; eError = PVRSRV_OK; @@ -1609,6 +2219,26 @@ Exit: } +/*! +****************************************************************************** + + @Function PVRSRVRegisterSystemISRHandler + + @Description + + registers an external ISR to be called of the back of a system ISR + + @Input ppfnISRHandler : ISR pointer + + @Input hISRHandlerData : Callback data + + @Input ui32ISRSourceMask : ISR Mask + + @Input ui32DeviceID : unique device key + + @Return PVRSRV_ERROR : + +******************************************************************************/ static PVRSRV_ERROR PVRSRVRegisterSystemISRHandler (PFN_ISR_HANDLER pfnISRHandler, IMG_VOID *pvISRHandlerData, @@ -1622,7 +2252,7 @@ PVRSRV_ERROR PVRSRVRegisterSystemISRHandler (PFN_ISR_HANDLER pfnISRHandler, SysAcquireData(&psSysData); - + /* Find Dev Node (just using the device id, ignore the class) */ psDevNode = (PVRSRV_DEVICE_NODE*) List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, &MatchDeviceKM_AnyVaCb, @@ -1636,15 +2266,29 @@ PVRSRV_ERROR PVRSRVRegisterSystemISRHandler (PFN_ISR_HANDLER pfnISRHandler, return PVRSRV_ERROR_NO_DEVICENODE_FOUND; } - + /* set up data before enabling the ISR */ psDevNode->pvISRData = (IMG_VOID*) pvISRHandlerData; - + /* enable the ISR */ psDevNode->pfnDeviceISR = pfnISRHandler; return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVSetDCState_ForEachVaCb + + @Description + + If the device node is a display, calls its set state function. + + @Input psDeviceNode - the device node + va - variable argument list with: + ui32State - the state to be set. + +******************************************************************************/ static IMG_VOID PVRSRVSetDCState_ForEachVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va) { @@ -1663,8 +2307,22 @@ IMG_VOID PVRSRVSetDCState_ForEachVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list } +/*! +****************************************************************************** + + @Function PVRSRVSetDCState + + @Description + + Calls the display driver(s) to put them into the specified state. + + @Input ui32State: new DC state - one of DC_STATE_* + +******************************************************************************/ IMG_VOID IMG_CALLCONV PVRSRVSetDCState(IMG_UINT32 ui32State) { +/* PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + PVRSRV_DEVICE_NODE *psDeviceNode; */ SYS_DATA *psSysData; SysAcquireData(&psSysData); @@ -1674,7 +2332,50 @@ IMG_VOID IMG_CALLCONV PVRSRVSetDCState(IMG_UINT32 ui32State) ui32State); } +static PVRSRV_ERROR +PVRSRVDCMemInfoGetCpuVAddr(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo, + IMG_CPU_VIRTADDR *pVAddr) +{ + *pVAddr = psKernelMemInfo->pvLinAddrKM; + return PVRSRV_OK; +} + +static PVRSRV_ERROR +PVRSRVDCMemInfoGetCpuPAddr(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo, + IMG_SIZE_T uByteOffset, IMG_CPU_PHYADDR *pPAddr) +{ + *pPAddr = OSMemHandleToCpuPAddr(psKernelMemInfo->sMemBlk.hOSMemHandle, uByteOffset); + return PVRSRV_OK; +} + +static PVRSRV_ERROR +PVRSRVDCMemInfoGetByteSize(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo, + IMG_SIZE_T *uByteSize) +{ + *uByteSize = psKernelMemInfo->uAllocSize; + return PVRSRV_OK; +} + +static IMG_BOOL +PVRSRVDCMemInfoIsPhysContig(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo) +{ + return OSMemHandleIsPhysContig(psKernelMemInfo->sMemBlk.hOSMemHandle); +} + +/*! +****************************************************************************** + @Function PVRGetDisplayClassJTable + + @Description + + Sets up function table for 3rd party Display Class Device to call through + + @Input psJTable : pointer to function pointer table memory + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT IMG_BOOL PVRGetDisplayClassJTable(PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable) { @@ -1694,24 +2395,37 @@ IMG_BOOL PVRGetDisplayClassJTable(PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable) #if defined(SUPPORT_CUSTOM_SWAP_OPERATIONS) psJTable->pfnPVRSRVFreeCmdCompletePacket = &PVRSRVFreeCommandCompletePacketKM; #endif - + psJTable->pfnPVRSRVDCMemInfoGetCpuVAddr = &PVRSRVDCMemInfoGetCpuVAddr; + psJTable->pfnPVRSRVDCMemInfoGetCpuPAddr = &PVRSRVDCMemInfoGetCpuPAddr; + psJTable->pfnPVRSRVDCMemInfoGetByteSize = &PVRSRVDCMemInfoGetByteSize; + psJTable->pfnPVRSRVDCMemInfoIsPhysContig = &PVRSRVDCMemInfoIsPhysContig; return IMG_TRUE; } +/****************************************************************************** + + @Function PVRSRVCloseBCDeviceKM + + @Description + + Closes a connection to the Buffer Class device + + @Input hDeviceKM : device handle + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT -PVRSRV_ERROR PVRSRVCloseBCDeviceKM (IMG_HANDLE hDeviceKM, - IMG_BOOL bResManCallback) +PVRSRV_ERROR PVRSRVCloseBCDeviceKM (IMG_HANDLE hDeviceKM) { PVRSRV_ERROR eError; PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo; - PVR_UNREFERENCED_PARAMETER(bResManCallback); - psBCPerContextInfo = (PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *)hDeviceKM; - + /* Remove the item from the resman list and trigger the callback. */ eError = ResManFreeResByPtr(psBCPerContextInfo->hResItem, CLEANUP_WITH_POLL); return eError; @@ -1750,22 +2464,19 @@ static PVRSRV_ERROR CloseBCDeviceCallBack(IMG_PVOID pvParam, psBCInfo->ui32RefCount--; if(psBCInfo->ui32RefCount == 0) { - + /* close the external device */ psBCInfo->psFuncTable->pfnCloseBCDevice(psBCInfo->ui32DeviceID, psBCInfo->hExtDevice); - + /* free syncinfos */ for(i=0; i<psBCInfo->ui32BufferCount; i++) { if(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo) { - if (--psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->ui32RefCount == 0) - { - PVRSRVFreeSyncInfoKM(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo); - } + PVRSRVKernelSyncInfoDecRef(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL); } } - + /* free buffers */ if(psBCInfo->psBuffer) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BC_BUFFER) * psBCInfo->ui32BufferCount, psBCInfo->psBuffer, IMG_NULL); @@ -1774,12 +2485,31 @@ static PVRSRV_ERROR CloseBCDeviceCallBack(IMG_PVOID pvParam, } OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BUFFERCLASS_PERCONTEXT_INFO), psBCPerContextInfo, IMG_NULL); - + /*not nulling pointer, copy on stack*/ return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVOpenBCDeviceKM + + @Description + + Opens a connection to the Buffer Class device, associating the connection + with a Device Memory Context for a services managed device + + @Input psPerProc : Per-process data + @Input ui32DeviceID : unique device index + @Input hDevCookie : devcookie used to derive the Device Memory + Context into BC surfaces will be mapped into + @Outut phDeviceKM : handle to the DC device + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVOpenBCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, IMG_UINT32 ui32DeviceID, @@ -1801,7 +2531,7 @@ PVRSRV_ERROR PVRSRVOpenBCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, SysAcquireData(&psSysData); - + /* find the matching devicenode */ psDeviceNode = (PVRSRV_DEVICE_NODE*) List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, &MatchDeviceKM_AnyVaCb, @@ -1815,9 +2545,13 @@ PVRSRV_ERROR PVRSRVOpenBCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, } psBCInfo = (PVRSRV_BUFFERCLASS_INFO*)psDeviceNode->pvDevice; - - - +/* +FoundDevice: +*/ + /* + Allocate the per-context BC Info before calling the external device, + to make error handling easier. + */ if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psBCPerContextInfo), (IMG_VOID **)&psBCPerContextInfo, IMG_NULL, @@ -1834,10 +2568,10 @@ PVRSRV_ERROR PVRSRVOpenBCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, psDeviceNode = (PVRSRV_DEVICE_NODE *)hDevCookie; - + /* store the device kernel context to map into */ psBCInfo->hDevMemContext = (IMG_HANDLE)psDeviceNode->sDevMemoryInfo.pBMKernelContext; - + /* open the external device */ eError = psBCInfo->psFuncTable->pfnOpenBCDevice(ui32DeviceID, &psBCInfo->hExtDevice); if(eError != PVRSRV_OK) { @@ -1845,7 +2579,7 @@ PVRSRV_ERROR PVRSRVOpenBCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, return eError; } - + /* get information about the buffers */ eError = psBCInfo->psFuncTable->pfnGetBCInfo(psBCInfo->hExtDevice, &sBufferInfo); if(eError != PVRSRV_OK) { @@ -1853,11 +2587,10 @@ PVRSRV_ERROR PVRSRVOpenBCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, return eError; } - + /* interpret and store info */ psBCInfo->ui32BufferCount = sBufferInfo.ui32BufferCount; - - + /* allocate BC buffers */ eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BC_BUFFER) * sBufferInfo.ui32BufferCount, (IMG_VOID **)&psBCInfo->psBuffer, @@ -1874,7 +2607,7 @@ PVRSRV_ERROR PVRSRVOpenBCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, for(i=0; i<psBCInfo->ui32BufferCount; i++) { - + /* create a syncinfo for the device's system surface */ eError = PVRSRVAllocSyncInfoKM(IMG_NULL, psBCInfo->hDevMemContext, &psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo); @@ -1883,12 +2616,11 @@ PVRSRV_ERROR PVRSRVOpenBCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, PVR_DPF((PVR_DBG_ERROR,"PVRSRVOpenBCDeviceKM: Failed sync info alloc")); goto ErrorExit; } - - psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->ui32RefCount++; - - - + /* + get the buffers from the buffer class + drivers by index, passing-in the syncdata objects + */ eError = psBCInfo->psFuncTable->pfnGetBCBuffer(psBCInfo->hExtDevice, i, psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->psSyncData, @@ -1899,7 +2631,7 @@ PVRSRV_ERROR PVRSRVOpenBCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, goto ErrorExit; } - + /* setup common device class info */ psBCInfo->psBuffer[i].sDeviceClassBuffer.pfnGetBufferAddr = psBCInfo->psFuncTable->pfnGetBufferAddr; psBCInfo->psBuffer[i].sDeviceClassBuffer.hDevMemContext = psBCInfo->hDevMemContext; psBCInfo->psBuffer[i].sDeviceClassBuffer.hExtDevice = psBCInfo->hExtDevice; @@ -1914,26 +2646,23 @@ PVRSRV_ERROR PVRSRVOpenBCDeviceKM (PVRSRV_PER_PROCESS_DATA *psPerProc, 0, &CloseBCDeviceCallBack); - + /* return a reference to the BCPerContextInfo */ *phDeviceKM = (IMG_HANDLE)psBCPerContextInfo; return PVRSRV_OK; ErrorExit: - + /* free syncinfos */ for(i=0; i<psBCInfo->ui32BufferCount; i++) { if(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo) { - if (--psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo->ui32RefCount == 0) - { - PVRSRVFreeSyncInfoKM(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo); - } + PVRSRVKernelSyncInfoDecRef(psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo, IMG_NULL); } } - + /* free buffers */ if(psBCInfo->psBuffer) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_BC_BUFFER), psBCInfo->psBuffer, IMG_NULL); @@ -1946,6 +2675,20 @@ ErrorExit: +/****************************************************************************** + + @Function PVRSRVGetBCInfoKM + + @Description + + Gets Buffer Class device Info + + @Input hDeviceKM : device handle + @Output psBufferInfo + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVGetBCInfoKM (IMG_HANDLE hDeviceKM, BUFFER_INFO *psBufferInfo) @@ -1973,6 +2716,20 @@ PVRSRV_ERROR PVRSRVGetBCInfoKM (IMG_HANDLE hDeviceKM, } +/****************************************************************************** + + @Function PVRSRVGetBCBufferKM + + @Description + + Gets Buffer Class Buffer Handle + + @Input hDeviceKM : device handle + @Output psBufferInfo + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVGetBCBufferKM (IMG_HANDLE hDeviceKM, IMG_UINT32 ui32BufferIndex, @@ -2002,6 +2759,20 @@ PVRSRV_ERROR PVRSRVGetBCBufferKM (IMG_HANDLE hDeviceKM, } +/*! +****************************************************************************** + + @Function PVRGetBufferClassJTable + + @Description + + Sets up function table for 3rd party Buffer Class Device to call through + + @Input psJTable : pointer to function pointer table memory + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT IMG_BOOL PVRGetBufferClassJTable(PVRSRV_BC_BUFFER2SRV_KMJTABLE *psJTable) { @@ -2014,3 +2785,6 @@ IMG_BOOL PVRGetBufferClassJTable(PVRSRV_BC_BUFFER2SRV_KMJTABLE *psJTable) return IMG_TRUE; } +/****************************************************************************** + End of file (deviceclass.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/common/deviceid.h b/sgx/services4/srvkm/common/deviceid.h index 9a7bdb3..e4f0b4c 100644 --- a/sgx/services4/srvkm/common/deviceid.h +++ b/sgx/services4/srvkm/common/deviceid.h @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Device ID helpers +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #ifndef __DEVICEID_H__ #define __DEVICEID_H__ @@ -33,4 +49,4 @@ PVRSRV_ERROR AllocateDeviceID(SYS_DATA *psSysData, IMG_UINT32 *pui32DevID); PVRSRV_ERROR FreeDeviceID(SYS_DATA *psSysData, IMG_UINT32 ui32DevID); -#endif +#endif /* __DEVICEID_H__ */ diff --git a/sgx/services4/srvkm/common/devicemem.c b/sgx/services4/srvkm/common/devicemem.c index 5642640..e193396 100644 --- a/sgx/services4/srvkm/common/devicemem.c +++ b/sgx/services4/srvkm/common/devicemem.c @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@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> @@ -38,6 +55,11 @@ #include "mmap.h" #endif +#if defined(SUPPORT_ION) +#include "ion.h" +#include "env_perproc.h" +#endif + #if defined(SUPPORT_DRI_DRM_EXTERNAL) # include <linux/omap_drv.h> # include "perproc.h" @@ -45,21 +67,37 @@ extern int pvr_mapper_id; #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, - PVRSRV_KERNEL_MEM_INFO **ppsMemInfo); - + 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; @@ -71,6 +109,22 @@ typedef struct _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) @@ -93,22 +147,24 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetDeviceMemHeapsKM(IMG_HANDLE hDevCookie, 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++) @@ -120,6 +176,24 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetDeviceMemHeapsKM(IMG_HANDLE hDevCookie, 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, @@ -154,17 +228,20 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateDeviceMemContextKM(IMG_HANDLE hDevCook 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, @@ -175,19 +252,25 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateDeviceMemContextKM(IMG_HANDLE hDevCook 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 @@ -211,12 +294,17 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateDeviceMemContextKM(IMG_HANDLE hDevCook 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 @@ -227,7 +315,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateDeviceMemContextKM(IMG_HANDLE hDevCook } } - + /* return shared_exported and per context heap information to the caller */ *pui32ClientHeapCount = ui32ClientHeapCount; *phDevMemContext = hDevMemContext; @@ -247,6 +335,23 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroyDeviceMemContextKM(IMG_HANDLE hDevCookie, +/*! +****************************************************************************** + + @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, @@ -277,28 +382,31 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetDeviceMemHeapInfoKM(IMG_HANDLE hDevCookie 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 @@ -322,12 +430,13 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetDeviceMemHeapInfoKM(IMG_HANDLE hDevCookie 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 @@ -338,23 +447,57 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetDeviceMemHeapInfoKM(IMG_HANDLE hDevCookie } } - + /* return shared_exported and per context heap information to the caller */ *pui32ClientHeapCount = ui32ClientHeapCount; 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, - PVRSRV_KERNEL_MEM_INFO **ppsMemInfo) + 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; @@ -375,7 +518,7 @@ static PVRSRV_ERROR AllocDeviceMem(IMG_HANDLE hDevCookie, psMemBlock = &(psMemInfo->sMemBlk); - + /* BM supplied Device Virtual Address with physical backing RAM */ psMemInfo->ui32Flags = ui32Flags | PVRSRV_MEM_RAM_BACKED_ALLOCATION; bBMError = BM_Alloc (hDevMemHeap, @@ -383,42 +526,59 @@ static PVRSRV_ERROR AllocDeviceMem(IMG_HANDLE hDevCookie, 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; - psMemInfo->uAllocSize = ui32Size; + 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; - + /* + * 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, IMG_BOOL bFromAllocator) +static PVRSRV_ERROR FreeDeviceMem2(PVRSRV_KERNEL_MEM_INFO *psMemInfo, PVRSRV_FREE_CALLBACK_ORIGIN eCallbackOrigin) { BM_HANDLE hBuffer; @@ -429,23 +589,27 @@ static PVRSRV_ERROR FreeDeviceMem2(PVRSRV_KERNEL_MEM_INFO *psMemInfo, IMG_BOOL b hBuffer = psMemInfo->sMemBlk.hBuffer; - - if (bFromAllocator) - BM_Free(hBuffer, psMemInfo->ui32Flags); - else - BM_FreeExport(hBuffer, psMemInfo->ui32Flags); + 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) && bFromAllocator) + 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); } @@ -461,23 +625,32 @@ static PVRSRV_ERROR FreeDeviceMem(PVRSRV_KERNEL_MEM_INFO *psMemInfo) 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, @@ -500,35 +673,47 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVAllocSyncInfoKM(IMG_HANDLE hDevCookie, return PVRSRV_ERROR_OUT_OF_MEMORY; } - psKernelSyncInfo->ui32RefCount = 0; - + 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; @@ -536,8 +721,11 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVAllocSyncInfoKM(IMG_HANDLE hDevCookie, 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"); @@ -551,244 +739,177 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVAllocSyncInfoKM(IMG_HANDLE hDevCookie, psKernelSyncInfo->sWriteOpsCompleteDevVAddr.uiAddr = psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr + offsetof(PVRSRV_SYNC_DATA, ui32WriteOpsComplete); psKernelSyncInfo->sReadOpsCompleteDevVAddr.uiAddr = psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr + offsetof(PVRSRV_SYNC_DATA, ui32ReadOpsComplete); + psKernelSyncInfo->sReadOps2CompleteDevVAddr.uiAddr = psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr + offsetof(PVRSRV_SYNC_DATA, ui32ReadOps2Complete); psKernelSyncInfo->ui32UID = g_ui32SyncUID++; - psKernelSyncInfo->hSmartCache = NULL; - + /* syncinfo meminfo has no syncinfo! */ psKernelSyncInfo->psSyncDataMemInfoKM->psKernelSyncInfo = IMG_NULL; - + OSAtomicInc(psKernelSyncInfo->pvRefCount); + + /* return result */ *ppsKernelSyncInfo = psKernelSyncInfo; return PVRSRV_OK; } - IMG_EXPORT -PVRSRV_ERROR IMG_CALLCONV PVRSRVFreeSyncInfoKM(PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo) +IMG_VOID PVRSRVAcquireSyncInfoKM(PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo) { - PVRSRV_ERROR eError; + OSAtomicInc(psKernelSyncInfo->pvRefCount); +} - if (psKernelSyncInfo->ui32RefCount != 0) - { - PVR_DPF((PVR_DBG_ERROR, "oops: sync info ref count not zero at destruction")); - - return PVRSRV_ERROR_OUT_OF_MEMORY; - } +/*! +****************************************************************************** - eError = FreeDeviceMem(psKernelSyncInfo->psSyncDataMemInfoKM); - (IMG_VOID)OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_KERNEL_SYNC_INFO), psKernelSyncInfo, IMG_NULL); - + @Function PVRSRVFreeSyncInfoKM - return eError; -} + @Description -static IMG_VOID freeWrapped(PVRSRV_KERNEL_MEM_INFO *psMemInfo) -{ - IMG_HANDLE hOSWrapMem = psMemInfo->sMemBlk.hOSWrapMem; + Frees a sync info - - if(psMemInfo->sMemBlk.psIntSysPAddr) - { - OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(IMG_SYS_PHYADDR), psMemInfo->sMemBlk.psIntSysPAddr, IMG_NULL); - psMemInfo->sMemBlk.psIntSysPAddr = IMG_NULL; - } + @Return PVRSRV_ERROR : - if(hOSWrapMem) +******************************************************************************/ +IMG_EXPORT +IMG_VOID IMG_CALLCONV PVRSRVReleaseSyncInfoKM(PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo) +{ + if (OSAtomicDecAndTest(psKernelSyncInfo->pvRefCount)) { - OSReleasePhysPageAddr(hOSWrapMem); + 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*/ } } +/*! +****************************************************************************** -#if defined (PVRSRV_FLUSH_KERNEL_OPS_LAST_ONLY) -static -PVRSRV_ERROR _PollUntilAtLeast(volatile IMG_UINT32* pui32WatchedValue, - IMG_UINT32 ui32MinimumValue, - IMG_UINT32 ui32Waitus, - IMG_UINT32 ui32Tries) -{ - PVRSRV_ERROR eError; - IMG_INT32 iDiff; + @Function freeExternal - for(;;) - { - SYS_DATA *psSysData = SysAcquireDataNoCheck(); - iDiff = *pui32WatchedValue - ui32MinimumValue; + @Description - if (iDiff >= 0) - { - eError = PVRSRV_OK; - break; - } + Code for freeing meminfo elements that are specific to external types memory - if(!ui32Tries) - { - eError = PVRSRV_ERROR_TIMEOUT_POLLING_FOR_VALUE; - break; - } + @Input psMemInfo : Kernel meminfo - ui32Tries--; + @Return PVRSRV_ERROR : - - if (psSysData->psGlobalEventObject) - { - IMG_HANDLE hOSEventKM; - if(psSysData->psGlobalEventObject) - { - eError = OSEventObjectOpenKM(psSysData->psGlobalEventObject, &hOSEventKM); - if (eError |= PVRSRV_OK) - { - PVR_DPF((PVR_DBG_ERROR, - "_PollUntilAtLeast: OSEventObjectOpen failed")); - goto Exit; - } - eError = OSEventObjectWaitKM(hOSEventKM); - if (eError != PVRSRV_OK) - { - PVR_DPF((PVR_DBG_ERROR, - "_PollUntilAtLeast: PVRSRVEventObjectWait failed")); - goto Exit; - } - eError = OSEventObjectCloseKM(psSysData->psGlobalEventObject, hOSEventKM); - if (eError != PVRSRV_OK) - { - PVR_DPF((PVR_DBG_ERROR, - "_PollUntilAtLeast: OSEventObjectClose failed")); - } - } - } - } -Exit: - return eError; -} +******************************************************************************/ -static PVRSRV_ERROR FlushKernelOps(PVRSRV_SYNC_DATA *psSyncData) +static IMG_VOID freeExternal(PVRSRV_KERNEL_MEM_INFO *psMemInfo) { - PVRSRV_ERROR eError; + IMG_HANDLE hOSWrapMem = psMemInfo->sMemBlk.hOSWrapMem; - if(!psSyncData) + /* free the page addr array if req'd */ + if(psMemInfo->sMemBlk.psIntSysPAddr) { - PVR_DPF((PVR_DBG_ERROR, "FlushKernelOps: invalid psSyncData")); - return PVRSRV_ERROR_INVALID_PARAMS; + 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 - eError = _PollUntilAtLeast(&psSyncData->ui32ReadOpsComplete, - psSyncData->ui32ReadOpsPending, - MAX_HW_TIME_US/WAIT_TRY_COUNT, - WAIT_TRY_COUNT); - if (eError != PVRSRV_OK) - { - PVR_DPF((PVR_DBG_ERROR, "FlushClientOps: Read ops pending timeout")); - PVR_DBG_BREAK; - return eError; - } + Common code for freeing device mem (called for freeing, unwrapping and unmapping) - eError = _PollUntilAtLeast(&psSyncData->ui32WriteOpsComplete, - psSyncData->ui32WriteOpsPending, - MAX_HW_TIME_US/WAIT_TRY_COUNT, - WAIT_TRY_COUNT); - if (eError != PVRSRV_OK) - { - PVR_DPF((PVR_DBG_ERROR, "FlushClientOps: Write ops pending timeout")); - PVR_DBG_BREAK; - } + @Input psMemInfo : Kernel meminfo + @Input ui32Param : packet size + @Input uibFromAllocatorParam : Are we being called by the original allocator? - return eError; -} -#endif + @Return PVRSRV_ERROR : -static PVRSRV_ERROR FreeMemCallBackCommon(PVRSRV_KERNEL_MEM_INFO *psMemInfo, - IMG_UINT32 ui32Param, - IMG_BOOL bFromAllocator) +******************************************************************************/ +IMG_EXPORT +PVRSRV_ERROR FreeMemCallBackCommon(PVRSRV_KERNEL_MEM_INFO *psMemInfo, + IMG_UINT32 ui32Param, + PVRSRV_FREE_CALLBACK_ORIGIN eCallbackOrigin) { PVRSRV_ERROR eError = PVRSRV_OK; PVR_UNREFERENCED_PARAMETER(ui32Param); - - psMemInfo->ui32RefCount--; + /* decrement the refcount */ + PVRSRVKernelMemInfoDecRef(psMemInfo); - - if(((psMemInfo->ui32Flags & PVRSRV_MEM_EXPORTED) != 0) && (bFromAllocator == IMG_TRUE)) + /* 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; + IMG_SID hMemInfo = 0; #else - IMG_HANDLE hMemInfo = IMG_NULL; + IMG_HANDLE hMemInfo = IMG_NULL; #endif - - eError = PVRSRVFindHandle(KERNEL_HANDLE_BASE, - &hMemInfo, - psMemInfo, - PVRSRV_HANDLE_TYPE_MEM_INFO); - if(eError != PVRSRV_OK) - { - PVR_DPF((PVR_DBG_ERROR, "FreeMemCallBackCommon: can't find exported meminfo in the global handle list")); - return eError; - } - - - eError = PVRSRVReleaseHandle(KERNEL_HANDLE_BASE, - hMemInfo, - PVRSRV_HANDLE_TYPE_MEM_INFO); - if(eError != PVRSRV_OK) - { - PVR_DPF((PVR_DBG_ERROR, "FreeMemCallBackCommon: PVRSRVReleaseHandle failed for exported meminfo")); - return eError; - } - } - - - if (psMemInfo->ui32RefCount == 0) - { -#if defined (PVRSRV_FLUSH_KERNEL_OPS_LAST_ONLY) - if (psMemInfo->psKernelSyncInfo) - { - if (psMemInfo->sShareMemWorkaround.bInUse) + /* find the handle */ + eError = PVRSRVFindHandle(KERNEL_HANDLE_BASE, + &hMemInfo, + psMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO); + if(eError != PVRSRV_OK) { - - if (BM_XProcWorkaroundGetRefCount(psMemInfo->sShareMemWorkaround.ui32ShareIndex) - == 1) - { - FlushKernelOps(psMemInfo->psKernelSyncInfo->psSyncData); - } + PVR_DPF((PVR_DBG_ERROR, "FreeMemCallBackCommon: can't find exported meminfo in the global handle list")); + return eError; } - else - { - - - - - - - - FlushKernelOps(psMemInfo->psKernelSyncInfo->psSyncData); + /* 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; } } -#endif + switch(psMemInfo->memType) { - + /* Fall through: Free only what we should for each memory type */ case PVRSRV_MEMTYPE_WRAPPED: - freeWrapped(psMemInfo); + case PVRSRV_MEMTYPE_ION: + freeExternal(psMemInfo); case PVRSRV_MEMTYPE_DEVICE: + case PVRSRV_MEMTYPE_DEVICECLASS: if (psMemInfo->psKernelSyncInfo) { - psMemInfo->psKernelSyncInfo->ui32RefCount--; - - if (psMemInfo->psKernelSyncInfo->ui32RefCount == 0) + /* note: we have to inline PVRSRVReleaseSyncInfoKM here + * because we need clean up the GEM obj's ptr to the + * sync obj.. need to see if we can find a cleaner + * way.. + */ + PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo = psMemInfo->psKernelSyncInfo; + if (OSAtomicDecAndTest(psKernelSyncInfo->pvRefCount)) { #if defined(SUPPORT_DRI_DRM_EXTERNAL) struct drm_gem_object *buf = @@ -799,16 +920,17 @@ static PVRSRV_ERROR FreeMemCallBackCommon(PVRSRV_KERNEL_MEM_INFO *psMemInfo, omap_gem_set_sync_object(buf, NULL); } #endif - if (psMemInfo->psKernelSyncInfo->hSmartCache) - { - BM_UnregisterSmart(psMemInfo->sMemBlk.hBuffer, - psMemInfo->psKernelSyncInfo->hSmartCache); - PVRMMapFreeSmart(psMemInfo->psKernelSyncInfo->hSmartCache); - } - eError = PVRSRVFreeSyncInfoKM(psMemInfo->psKernelSyncInfo); + + 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*/ } } - case PVRSRV_MEMTYPE_DEVICECLASS: break; default: PVR_DPF((PVR_DBG_ERROR, "FreeMemCallBackCommon: Unknown memType")); @@ -816,15 +938,36 @@ static PVRSRV_ERROR FreeMemCallBackCommon(PVRSRV_KERNEL_MEM_INFO *psMemInfo, } } - + /* + * 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, bFromAllocator); + 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) @@ -833,10 +976,25 @@ static PVRSRV_ERROR FreeDeviceMemCallBack(IMG_PVOID pvParam, PVR_UNREFERENCED_PARAMETER(bDummy); - return FreeMemCallBackCommon(psMemInfo, ui32Param, IMG_TRUE); + 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) @@ -850,22 +1008,13 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVFreeDeviceMemKM(IMG_HANDLE hDevCookie, return PVRSRV_ERROR_INVALID_PARAMS; } - // XXX do we need this? - if (psMemInfo->psKernelSyncInfo && psMemInfo->psKernelSyncInfo->hSmartCache) - { - BM_UnregisterSmart(psMemInfo->sMemBlk.hBuffer, - psMemInfo->psKernelSyncInfo->hSmartCache); - PVRMMapFreeSmart(psMemInfo->psKernelSyncInfo->hSmartCache); - psMemInfo->psKernelSyncInfo->hSmartCache = NULL; - } - 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); } @@ -956,14 +1105,40 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVUnmapFromDevKM(IMG_HANDLE hDevCookie, } +/*! +****************************************************************************** + + @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, - PVRSRV_KERNEL_MEM_INFO **ppsMemInfo) +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; @@ -971,15 +1146,46 @@ PVRSRV_ERROR IMG_CALLCONV _PVRSRVAllocDeviceMemKM(IMG_HANDLE hDevCookie, IMG_HANDLE hDevMemContext; if (!hDevMemHeap || - (ui32Size == 0)) + ((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)) { @@ -992,6 +1198,12 @@ PVRSRV_ERROR IMG_CALLCONV _PVRSRVAllocDeviceMemKM(IMG_HANDLE hDevCookie, ui32Flags, ui32Size, ui32Alignment, + pvPrivData, + ui32PrivDataLength, + ui32ChunkSize, + ui32NumVirtChunks, + ui32NumPhysChunks, + pabMapChunk, &psMemInfo); if (eError != PVRSRV_OK) @@ -1005,9 +1217,10 @@ PVRSRV_ERROR IMG_CALLCONV _PVRSRVAllocDeviceMemKM(IMG_HANDLE hDevCookie, } 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, @@ -1017,17 +1230,11 @@ PVRSRV_ERROR IMG_CALLCONV _PVRSRVAllocDeviceMemKM(IMG_HANDLE hDevCookie, { goto free_mainalloc; } - psMemInfo->psKernelSyncInfo->ui32RefCount++; - - if (ui32Flags & PVRSRV_HAP_SMART) - { - psMemInfo->psKernelSyncInfo->hSmartCache = (IMG_HANDLE) - PVRMMapAllocateSmart(psMemInfo->psKernelSyncInfo); - BM_RegisterSmart(psMemInfo->sMemBlk.hBuffer, psMemInfo->psKernelSyncInfo->hSmartCache); - } } - + /* + * Setup the output. + */ *ppsMemInfo = psMemInfo; if (ui32Flags & PVRSRV_MEM_NO_RESMAN) @@ -1036,7 +1243,7 @@ PVRSRV_ERROR IMG_CALLCONV _PVRSRVAllocDeviceMemKM(IMG_HANDLE hDevCookie, } else { - + /* register with the resman */ psMemInfo->sMemBlk.hResItem = ResManRegisterRes(psPerProc->hResManContext, RESMAN_TYPE_DEVICEMEM_ALLOCATION, psMemInfo, @@ -1044,27 +1251,282 @@ PVRSRV_ERROR IMG_CALLCONV _PVRSRVAllocDeviceMemKM(IMG_HANDLE hDevCookie, &FreeDeviceMemCallBack); if (psMemInfo->sMemBlk.hResItem == IMG_NULL) { - eError = PVRSRV_ERROR_OUT_OF_MEMORY; goto free_mainalloc; } } - - psMemInfo->ui32RefCount++; + /* 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) @@ -1087,13 +1549,34 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVDissociateDeviceMemKM(IMG_HANDLE hD } +/*! +****************************************************************************** + + @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); @@ -1106,6 +1589,17 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetFreeDeviceMemKM(IMG_UINT32 ui32Flags, +/*! +****************************************************************************** + @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) { @@ -1118,6 +1612,16 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVUnwrapExtMemoryKM (PVRSRV_KERNEL_MEM_INFO *psMem } +/*! +****************************************************************************** + @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) @@ -1128,16 +1632,21 @@ static PVRSRV_ERROR UnwrapExtMemoryCallBack(IMG_PVOID pvParam, struct drm_gem_object *buf = BM_GetGEM(psMemInfo->sMemBlk.hBuffer); #endif - PVRSRV_ERROR err = FreeMemCallBackCommon(psMemInfo, ui32Param, IMG_TRUE); + PVRSRV_ERROR err = FreeMemCallBackCommon(psMemInfo, ui32Param, + PVRSRV_FREE_CALLBACK_ORIGIN_ALLOCATOR); PVR_UNREFERENCED_PARAMETER(bDummy); #if defined(SUPPORT_DRI_DRM_EXTERNAL) if (buf) { - if (bPhysContig) { + if (omap_gem_flags(buf) & OMAP_BO_TILED_MASK) { omap_gem_put_paddr(buf); } else { - omap_gem_put_pages(buf); + if (bPhysContig) { + omap_gem_put_paddr(buf); + } else { + omap_gem_put_pages(buf); + } } } #endif /* SUPPORT_DRI_DRM_EXTERNAL */ @@ -1146,6 +1655,26 @@ static PVRSRV_ERROR UnwrapExtMemoryCallBack(IMG_PVOID pvParam, } +/*! +****************************************************************************** + @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, @@ -1187,14 +1716,14 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVWrapExtMemoryKM(IMG_HANDLE hDevCookie, 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, @@ -1211,23 +1740,20 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVWrapExtMemoryKM(IMG_HANDLE hDevCookie, if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVWrapExtMemoryKM: Failed to alloc memory for block")); - eError = PVRSRV_ERROR_OUT_OF_MEMORY; + 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; } - else - { - - } - + /* Choose the heap to map to */ psDevMemoryInfo = &((BM_CONTEXT*)hDevMemContext)->psDeviceNode->sDevMemoryInfo; psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap; for(i=0; i<PVRSRV_MAX_CLIENT_HEAPS; i++) @@ -1236,7 +1762,6 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVWrapExtMemoryKM(IMG_HANDLE hDevCookie, { if(psDeviceMemoryHeap[i].DevMemHeapType == DEVICE_MEMORY_HEAP_PERCONTEXT) { - if (psDeviceMemoryHeap[i].ui32HeapSize > 0) { hDevMemHeap = BM_CreateHeap(hDevMemContext, &psDeviceMemoryHeap[i]); @@ -1291,27 +1816,29 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVWrapExtMemoryKM(IMG_HANDLE hDevCookie, 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, @@ -1322,34 +1849,33 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVWrapExtMemoryKM(IMG_HANDLE hDevCookie, goto ErrorExitPhase4; } - psMemInfo->psKernelSyncInfo->ui32RefCount++; - - - psMemInfo->ui32RefCount++; + /* 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; } @@ -1357,7 +1883,7 @@ ErrorExitPhase3: if(psMemInfo) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_KERNEL_MEM_INFO), psMemInfo, IMG_NULL); - + /*not nulling pointer, out of scope*/ } ErrorExitPhase2: @@ -1370,23 +1896,47 @@ 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; } +struct async_unmap_data { + PVRSRV_KERNEL_MEM_INFO *psMemInfo; + IMG_UINT32 ui32PID; +}; + static void async_unmap(void *arg) { - PVRSRV_KERNEL_MEM_INFO *psMemInfo = arg; + struct async_unmap_data *data = arg; + PVRSRV_KERNEL_MEM_INFO *psMemInfo = data->psMemInfo; LinuxLockMutex(&gPVRSRVLock); ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem, CLEANUP_WITH_POLL); + /* decrement the refcnt on the per-proc: */ + PVRSRVPerProcessDataDisconnect(data->ui32PID); LinuxUnLockMutex(&gPVRSRVLock); + + kfree(data); } +/*! +****************************************************************************** + + @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) +PVRSRV_ERROR IMG_CALLCONV PVRSRVUnmapDeviceMemoryKM (PVRSRV_KERNEL_MEM_INFO *psMemInfo, + PVRSRV_PER_PROCESS_DATA *psPerProc) { struct drm_gem_object *buf; @@ -1398,18 +1948,20 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVUnmapDeviceMemoryKM (PVRSRV_KERNEL_MEM_INFO *psM buf = BM_GetGEM(psMemInfo->sMemBlk.hBuffer); if (buf) { - // TODO: this approach will leave the buffer in the RM until - // the sync-obj callback.. but if the process exits, then it - // might get deleted by RM w/ blits in progress. Possibly - // we should be doing this *after* the RM callback so it is - // already removed from RM? OTOH, if SGX is hung and the - // sync-objs never get updated, could that leave us with a - // buffer that could never be free'd? + struct async_unmap_data *data = kmalloc(sizeof *data, GFP_KERNEL); int ret; + /* need to hold a ref to the per-proc, so an exiting/crashing + * app while there are still pending buffers for async free + * doesn't trigger premature cleanup.. + */ + PVRSRVPerProcessDataConnect(psPerProc->ui32PID, 0); + data->psMemInfo = psMemInfo; + data->ui32PID = psPerProc->ui32PID; + LinuxUnLockMutex(&gPVRSRVLock); ret = omap_gem_op_async(buf, OMAP_GEM_READ|OMAP_GEM_WRITE, - async_unmap, psMemInfo); + async_unmap, data); LinuxLockMutex(&gPVRSRVLock); if (ret == 0) return PVRSRV_OK; @@ -1420,6 +1972,17 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVUnmapDeviceMemoryKM (PVRSRV_KERNEL_MEM_INFO *psM } +/*! +****************************************************************************** + @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) @@ -1438,16 +2001,7 @@ static PVRSRV_ERROR UnmapDeviceMemoryCallBack(IMG_PVOID pvParam, if( psMapData->psMemInfo->psKernelSyncInfo ) { - psMapData->psMemInfo->psKernelSyncInfo->ui32RefCount--; - if (psMapData->psMemInfo->psKernelSyncInfo->ui32RefCount == 0) - { - eError = PVRSRVFreeSyncInfoKM(psMapData->psMemInfo->psKernelSyncInfo); - if(eError != PVRSRV_OK) - { - PVR_DPF((PVR_DBG_ERROR,"UnmapDeviceMemoryCallBack: Failed to free sync info")); - return eError; - } - } + PVRSRVKernelSyncInfoDecRef(psMapData->psMemInfo->psKernelSyncInfo, psMapData->psMemInfo); } eError = FreeDeviceMem(psMapData->psMemInfo); @@ -1457,16 +2011,34 @@ static PVRSRV_ERROR UnmapDeviceMemoryCallBack(IMG_PVOID pvParam, return eError; } - - eError = FreeMemCallBackCommon(psMapData->psSrcMemInfo, 0, IMG_FALSE); + /* 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, @@ -1489,24 +2061,23 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceMemoryKM(PVRSRV_PER_PROCESS_DATA *psPer 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, @@ -1518,23 +2089,23 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceMemoryKM(PVRSRV_PER_PROCESS_DATA *psPer 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, @@ -1576,50 +2147,51 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceMemoryKM(PVRSRV_PER_PROCESS_DATA *psPer 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) { - psMemInfo->psKernelSyncInfo->ui32RefCount++; + 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; - - psMemInfo->ui32RefCount++; + /* increment our refcount */ + PVRSRVKernelMemInfoIncRef(psMemInfo); - - psSrcMemInfo->ui32RefCount++; + /* 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, @@ -1630,29 +2202,29 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceMemoryKM(PVRSRV_PER_PROCESS_DATA *psPer 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; @@ -1672,13 +2244,21 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVImportGEMKM(PVRSRV_PER_PROCESS_DATA *psPerProc, PVRSRV_MEMBLK *psMemBlock; IMG_BOOL bBMError; PVRSRV_ERROR eError; - IMG_UINT32 i; - IMG_SIZE_T uByteSize; + IMG_UINT32 i; + IMG_UINT32 j; + IMG_SIZE_T uByteSize = 0; IMG_SIZE_T uPageOffset; + IMG_SIZE_T uTilerStride = 0; + IMG_UINT32 uTilerBPP = 0; + IMG_SIZE_T uPagesPerRow = 0; + IMG_UINT16 uTiledBufWidth; + IMG_UINT16 uTiledBufHeight; IMG_BOOL bPhysContig; - IMG_SYS_PHYADDR *psSysPAddr; /* array of page addresses */ + IMG_SYS_PHYADDR *psSysPAddr; /* array of page addresses */ IMG_UINT32 ui32Flags; - IMG_SIZE_T uPageCount = 0; + IMG_SIZE_T uPageCount = 0; + dma_addr_t paddr = 0; + struct page **pages = NULL; PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc = (PVRSRV_ENV_PER_PROCESS_DATA *)PVRSRVProcessPrivateData(psPerProc); struct drm_gem_object *buf = @@ -1707,15 +2287,43 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVImportGEMKM(PVRSRV_PER_PROCESS_DATA *psPerProc, if (omap_gem_flags(buf) & OMAP_BO_TILED_MASK) { - // TODO - PVR_DPF((PVR_DBG_ERROR,"PVRSRVImportGEMKM: not implemented")); - return PVRSRV_ERROR_INVALID_PARAMS; + if (!omap_gem_get_paddr(buf, &paddr, true)) + { + if (omap_gem_tiled_size(buf, &uTiledBufWidth, &uTiledBufHeight)) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVImportGEMKM: Failed to get TILED buffer size. Maybe buf is not tiled after all ?")); + return PVRSRV_ERROR_INVALID_PARAMS; + } + switch (omap_gem_flags(buf) & OMAP_BO_TILED_MASK) { + case OMAP_BO_TILED_8: + uTilerBPP = 1; + break; + case OMAP_BO_TILED_16: + uTilerBPP = 2; + break; + case OMAP_BO_TILED_32: + uTilerBPP = 4; + break; + default: + PVR_DPF((PVR_DBG_ERROR,"PVRSRVImportGEMKM: Wrong GEM bo format for rotation !")); + return PVRSRV_ERROR_INVALID_PARAMS; + } + uPageOffset = paddr & (ui32HostPageSize - 1); + paddr &= ~(ui32HostPageSize - 1); + bPhysContig = IMG_FALSE; + uTilerStride = omap_gem_tiled_stride(buf, 0); + uPagesPerRow = ((uTiledBufWidth * uTilerBPP) / PAGE_SIZE) + 1; + uPageCount = uPagesPerRow * uTiledBufHeight; + uByteSize = buf->size; + } + else + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVImportGEMKM: Failed to get paddr of TILED buffer")); + return PVRSRV_ERROR_INVALID_PARAMS; + } } else { - dma_addr_t paddr = 0; - struct page **pages = NULL; - if (!omap_gem_get_paddr(buf, &paddr, false)) { uPageOffset = paddr & (ui32HostPageSize - 1); @@ -1735,19 +2343,32 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVImportGEMKM(PVRSRV_PER_PROCESS_DATA *psPerProc, uByteSize = buf->size; uPageCount = HOST_PAGEALIGN(uByteSize + uPageOffset) / ui32HostPageSize; + } - PVR_DPF((PVR_DBG_MESSAGE,"paddr=%08x, pages=%p, uByteSize=%d, uPageCount=%d", - (u32)paddr, pages, uByteSize, uPageCount)); + PVR_DPF((PVR_DBG_MESSAGE,"paddr=%08x, pages=%p, uByteSize=%d, uPageCount=%d", + (u32)paddr, pages, uByteSize, uPageCount)); - if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, - uPageCount * sizeof(IMG_SYS_PHYADDR), - (IMG_VOID **)&psSysPAddr, IMG_NULL, - "Array of Page Addresses") != PVRSRV_OK) + 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,"PVRSRVImportGEMKM: Failed to alloc memory for block")); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + if (omap_gem_flags(buf) & OMAP_BO_TILED_MASK) + { + for (i = 0; i < uTiledBufHeight; i++) { - PVR_DPF((PVR_DBG_ERROR,"PVRSRVImportGEMKM: Failed to alloc memory for block")); - return PVRSRV_ERROR_OUT_OF_MEMORY; + for (j = 0; j < uPagesPerRow; j++) + { + psSysPAddr[(i * uPagesPerRow) + j].uiAddr = paddr + (i * uTilerStride) + (j * PAGE_SIZE); + } } - + } + else + { if (bPhysContig) { for (i = 0; i < uPageCount; i++) @@ -1834,9 +2455,10 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVImportGEMKM(PVRSRV_PER_PROCESS_DATA *psPerProc, omap_gem_set_sync_object(buf, psMemInfo->psKernelSyncInfo->psSyncData); } - - psMemInfo->psKernelSyncInfo->ui32RefCount++; - + else + { + PVRSRVKernelSyncInfoIncRef(psMemInfo->psKernelSyncInfo, psMemInfo); + } psMemInfo->ui32RefCount++; @@ -1890,7 +2512,19 @@ ErrorExitPhase2: } #endif /* SUPPORT_DRI_DRM_EXTERNAL */ +/*! +****************************************************************************** + @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) { @@ -1903,6 +2537,16 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVUnmapDeviceClassMemoryKM(PVRSRV_KERNEL_MEM_INFO } +/*! +****************************************************************************** + @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) @@ -1932,10 +2576,28 @@ static PVRSRV_ERROR UnmapDeviceClassMemoryCallBack(IMG_PVOID pvParam, OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_MAPINFO), psDCMapInfo, IMG_NULL); - return FreeMemCallBackCommon(psMemInfo, ui32Param, IMG_TRUE); + 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, @@ -1969,7 +2631,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceClassMemoryKM(PVRSRV_PER_PROCESS_DATA * return PVRSRV_ERROR_INVALID_PARAMS; } - + /* allocate resman storage structure */ if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_DC_MAPINFO), (IMG_VOID **)&psDCMapInfo, IMG_NULL, @@ -1982,25 +2644,26 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceClassMemoryKM(PVRSRV_PER_PROCESS_DATA * 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, @@ -2015,7 +2678,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceClassMemoryKM(PVRSRV_PER_PROCESS_DATA * goto ErrorExitPhase1; } - + /* Choose the heap to map to */ psBMContext = (BM_CONTEXT*)psDeviceClassBuffer->hDevMemContext; psDeviceNode = psBMContext->psDeviceNode; psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo; @@ -2026,7 +2689,6 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceClassMemoryKM(PVRSRV_PER_PROCESS_DATA * { if(psDeviceMemoryHeap[i].DevMemHeapType == DEVICE_MEMORY_HEAP_PERCONTEXT) { - if (psDeviceMemoryHeap[i].ui32HeapSize > 0) { hDevMemHeap = BM_CreateHeap(hDevMemContext, &psDeviceMemoryHeap[i]); @@ -2051,7 +2713,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceClassMemoryKM(PVRSRV_PER_PROCESS_DATA * 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); @@ -2081,32 +2743,40 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceClassMemoryKM(PVRSRV_PER_PROCESS_DATA * 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; @@ -2115,7 +2785,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceClassMemoryKM(PVRSRV_PER_PROCESS_DATA * if(psDCMapInfo->ui32TilingStride > 0) { - + /* try to acquire a tiling range on this device */ eError = psDeviceNode->pfnAllocMemTilingRange(psDeviceNode, psMemInfo, psDCMapInfo->ui32TilingStride, @@ -2128,7 +2798,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceClassMemoryKM(PVRSRV_PER_PROCESS_DATA * } #endif - + /* Register Resource */ psMemInfo->sMemBlk.hResItem = ResManRegisterRes(psPerProc->hResManContext, RESMAN_TYPE_DEVICECLASSMEM_MAPPING, psDCMapInfo, @@ -2136,17 +2806,30 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceClassMemoryKM(PVRSRV_PER_PROCESS_DATA * &UnmapDeviceClassMemoryCallBack); (psDeviceClassBuffer->ui32MemMapRefCount)++; - psMemInfo->ui32RefCount++; + PVRSRVKernelMemInfoIncRef(psMemInfo); psMemInfo->memType = PVRSRV_MEMTYPE_DEVICECLASS; - + /* return the meminfo */ *ppsMemInfo = psMemInfo; #if defined(SUPPORT_PDUMP_MULTI_PROCESS) - - PDUMPCOMMENT("Dump display surface"); - PDUMPMEM(IMG_NULL, psMemInfo, ui32Offset, psMemInfo->uAllocSize, PDUMP_FLAGS_CONTINUOUS, ((BM_BUF*)psMemInfo->sMemBlk.hBuffer)->pMapping); + /* 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; @@ -2154,10 +2837,16 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceClassMemoryKM(PVRSRV_PER_PROCESS_DATA * ErrorExitPhase3: if(psMemInfo) { - FreeDeviceMem(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 @@ -2203,3 +2892,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVChangeDeviceMemoryAttributesKM(IMG_HANDLE hKerne } +/****************************************************************************** + End of file (devicemem.c) +******************************************************************************/ + diff --git a/sgx/services4/srvkm/common/handle.c b/sgx/services4/srvkm/common/handle.c index 80f6d97..f71e67b 100644 --- a/sgx/services4/srvkm/common/handle.c +++ b/sgx/services4/srvkm/common/handle.c @@ -1,30 +1,61 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Resource Handle Manager +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Provide resource handle management +@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. + +*/ /**************************************************************************/ #if defined(PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE) +/* See handle.h for a description of the handle API. */ + +/* + * There is no locking here. It is assumed the code is used in a single + * threaded environment. In particular, it is assumed that the code will + * never be called from an interrupt handler. + * + * The implmentation supports movable handle structures, allowing the address + * of a handle structure to change without having to fix up pointers in + * any of the handle structures. For example, the linked list mechanism + * used to link subhandles together uses handle array indices rather than + * pointers to the structures themselves. + */ + #include <stddef.h> #include "services_headers.h" @@ -47,6 +78,7 @@ #define INDEX_IS_VALID(psBase, i) ((i) < (psBase)->ui32TotalHandCount) +/* Valid handles are never NULL, but handle array indices are based from 0 */ #if defined (SUPPORT_SID_INTERFACE) #define INDEX_TO_HANDLE(i) ((IMG_SID)((i) + 1)) #define HANDLE_TO_INDEX(h) ((IMG_UINT32)(h) - 1) @@ -110,6 +142,11 @@ #define MIN(x, y) (((x) < (y)) ? (x) : (y)) +/* + * Linked list structure. Used for both the list head and list items. + * Array indices, rather than pointers, are used to point to the next and + * previous items on the list. + */ struct sHandleList { IMG_UINT32 ui32Prev; @@ -128,101 +165,162 @@ enum ePVRSRVInternalHandleFlag INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE = 0x02, }; +/* Handle structure */ struct sHandle { - + /* Handle type */ PVRSRV_HANDLE_TYPE eType; - + /* Pointer to the data that the handle represents */ IMG_VOID *pvData; - + /* + * When handles are on the free list, the value of the "next index + * plus one field" has the following meaning: + * zero - next handle is the one that follows this one, + * nonzero - the index of the next handle is the value minus one. + * This scheme means handle space can be initialised to all zeros. + * + * When this field is used to link together handles on a list + * other than the free list, zero indicates the end of the + * list, with nonzero the same as above. + */ IMG_UINT32 ui32NextIndexPlusOne; - + /* Internal flags */ enum ePVRSRVInternalHandleFlag eInternalFlag; - + /* Flags specified when the handle was allocated */ PVRSRV_HANDLE_ALLOC_FLAG eFlag; - + /* Index of this handle in the handle array */ IMG_UINT32 ui32Index; - + /* List head for subhandles of this handle */ struct sHandleList sChildren; - + /* List entry for sibling subhandles */ struct sHandleList sSiblings; }; +/* Handle array index structure. + * The handle array is an array of index structures, reallocated as the number of + * handles increases. + * NOTE: There is one index structure per block of handles. + */ struct sHandleIndex { - + /* Pointer to first handle structure in the block */ struct sHandle *psHandle; - + /* Block allocation cookie returned from OSAllocMem for the block of handles */ IMG_HANDLE hBlockAlloc; - + /* Number of free handles in block */ IMG_UINT32 ui32FreeHandBlockCount; }; struct _PVRSRV_HANDLE_BASE_ { - + /* Handle returned from OSAllocMem for handle base allocation */ IMG_HANDLE hBaseBlockAlloc; - + /* Handle returned from OSAllocMem for handle array allocation */ IMG_HANDLE hArrayBlockAlloc; - + /* Pointer to array of pointers to handle structures */ struct sHandleIndex *psHandleArray; - + /* + * Pointer to handle hash table. + * The hash table is used to do reverse lookups, converting data + * pointers to handles. + */ HASH_TABLE *psHashTab; - + /* Number of free handles */ IMG_UINT32 ui32FreeHandCount; - + /* + * If purging is not enabled, this is the array index of first free + * handle. + * If purging is enabled, this is the index to start searching for + * a free handle from. In this case it is usually zero, unless + * the handle array size has been increased due to lack of + * handles. + */ IMG_UINT32 ui32FirstFreeIndex; - + /* Maximum handle index, plus one */ IMG_UINT32 ui32MaxIndexPlusOne; - + /* Total number of handles, free and allocated */ IMG_UINT32 ui32TotalHandCount; - + /* + * Index of the last free index, plus one. Not used if purging + * is enabled. + */ IMG_UINT32 ui32LastFreeIndexPlusOne; - + /* Size of current handle batch, or zero if batching not enabled */ IMG_UINT32 ui32HandBatchSize; - + /* Number of handles prior to start of current batch */ IMG_UINT32 ui32TotalHandCountPreBatch; - + /* Index of first handle in batch, plus one */ IMG_UINT32 ui32FirstBatchIndexPlusOne; - + /* Number of handle allocation failures in batch */ IMG_UINT32 ui32BatchHandAllocFailures; - + /* Purging enabled. + * If purging is enabled, the size of the table can be reduced + * by removing free space at the end of the table. To make + * purging more likely to succeed, handles are allocated as + * far to the front of the table as possible. The first free + * handle is found by a linear search from the start of the table, + * and so no free handle list management is done. + */ IMG_BOOL bPurgingEnabled; }; +/* + * The key for the handle hash table is an array of three elements, the + * pointer to the resource, the resource type, and the process ID. The + * eHandKey enumeration gives the array indices of the elements making + * up the key. + */ enum eHandKey { HAND_KEY_DATA = 0, HAND_KEY_TYPE, HAND_KEY_PARENT, - HAND_KEY_LEN + HAND_KEY_LEN /* Must be last item in list */ }; +/* + * Kernel handle base structure. For handles that are not allocated on + * behalf of a particular process + */ PVRSRV_HANDLE_BASE *gpsKernelHandleBase = IMG_NULL; +/* HAND_KEY is the type of the hash table key */ typedef IMG_UINTPTR_T HAND_KEY[HAND_KEY_LEN]; +/*! +****************************************************************************** + + @Function HandleListInit + + @Description Initialise a linked list structure embedded in a handle + structure. + + @Input ui32Index - index of handle in the handle array + psList - pointer to linked list structure + hParent - parent handle, or IMG_NULL + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(HandleListInit) #endif @@ -238,6 +336,17 @@ IMG_VOID HandleListInit(IMG_UINT32 ui32Index, struct sHandleList *psList, IMG_HA psList->hParent = hParent; } +/*! +****************************************************************************** + + @Function InitParentList + + @Description Initialise the children list head in a handle structure. + The children are the subhandles of this handle. + + @Input psHandle - pointer to handle structure + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(InitParentList) #endif @@ -249,6 +358,18 @@ IMG_VOID InitParentList(struct sHandle *psHandle) HandleListInit(ui32Parent, &psHandle->sChildren, INDEX_TO_HANDLE(ui32Parent)); } +/*! +****************************************************************************** + + @Function InitChildEntry + + @Description Initialise the child list entry in a handle structure. + The list entry is used to link together subhandles of + a given handle. + + @Input psHandle - pointer to handle structure + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(InitChildEntry) #endif @@ -258,6 +379,19 @@ IMG_VOID InitChildEntry(struct sHandle *psHandle) HandleListInit(HANDLE_PTR_TO_INDEX(psHandle), &psHandle->sSiblings, IMG_NULL); } +/*! +****************************************************************************** + + @Function HandleListIsEmpty + + @Description Determine whether a given linked list is empty. + + @Input ui32Index - index of the handle containing the list head + psList - pointer to the list head + + @Return IMG_TRUE if the list is empty, IMG_FALSE if it isn't. + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(HandleListIsEmpty) #endif @@ -273,7 +407,7 @@ IMG_BOOL HandleListIsEmpty(IMG_UINT32 ui32Index, struct sHandleList *psList) IMG_BOOL bIsEmpty2; bIsEmpty2 = (IMG_BOOL)(psList->ui32Prev == ui32Index); - PVR_ASSERT(bIsEmpty == bIsEmpty2) + PVR_ASSERT(bIsEmpty == bIsEmpty2); } #endif @@ -281,17 +415,41 @@ IMG_BOOL HandleListIsEmpty(IMG_UINT32 ui32Index, struct sHandleList *psList) } #ifdef DEBUG +/*! +****************************************************************************** + + @Function NoChildren + + @Description Determine whether a handle has any subhandles + + @Input psHandle - pointer to handle structure + + @Return IMG_TRUE if the handle has no subhandles, IMG_FALSE if it does. + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(NoChildren) #endif static INLINE IMG_BOOL NoChildren(struct sHandle *psHandle) { - PVR_ASSERT(psHandle->sChildren.hParent == HANDLE_PTR_TO_HANDLE(psHandle)) + PVR_ASSERT(psHandle->sChildren.hParent == HANDLE_PTR_TO_HANDLE(psHandle)); return HandleListIsEmpty(HANDLE_PTR_TO_INDEX(psHandle), &psHandle->sChildren); } +/*! +****************************************************************************** + + @Function NoParent + + @Description Determine whether a handle is a subhandle + + @Input psHandle - pointer to handle structure + + @Return IMG_TRUE if the handle is not a subhandle, IMG_FALSE if it is. + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(NoParent) #endif @@ -300,17 +458,29 @@ IMG_BOOL NoParent(struct sHandle *psHandle) { if (HandleListIsEmpty(HANDLE_PTR_TO_INDEX(psHandle), &psHandle->sSiblings)) { - PVR_ASSERT(psHandle->sSiblings.hParent == IMG_NULL) + PVR_ASSERT(psHandle->sSiblings.hParent == IMG_NULL); return IMG_TRUE; } else { - PVR_ASSERT(psHandle->sSiblings.hParent != IMG_NULL) + PVR_ASSERT(psHandle->sSiblings.hParent != IMG_NULL); } return IMG_FALSE; } -#endif +#endif /*DEBUG*/ +/*! +****************************************************************************** + + @Function ParentHandle + + @Description Determine the parent of a handle + + @Input psHandle - pointer to handle structure + + @Return Parent handle, or IMG_NULL if the handle is not a subhandle. + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(ParentHandle) #endif @@ -324,21 +494,49 @@ IMG_HANDLE ParentHandle(struct sHandle *psHandle) return psHandle->sSiblings.hParent; } +/* + * The LIST_PTR_FROM_INDEX_AND_OFFSET macro is used to generate either a + * pointer to the subhandle list head, or a pointer to the linked list + * structure of an item on a subhandle list. + * The list head is itself on the list, but is at a different offset + * in the handle structure to the linked list structure for items on + * the list. The two linked list structures are differentiated by + * the third parameter, containing the parent index. The parent field + * in the list head structure references the handle structure that contains + * it. For items on the list, the parent field in the linked list structure + * references the parent handle, which will be different from the handle + * containing the linked list structure. + */ #define LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, i, p, po, eo) \ ((struct sHandleList *)((IMG_CHAR *)(INDEX_TO_HANDLE_STRUCT_PTR(psBase, i)) + (((i) == (p)) ? (po) : (eo)))) +/*! +****************************************************************************** + + @Function HandleListInsertBefore + + @Description Insert a handle before a handle currently on the list. + + @Input ui32InsIndex - index of handle to be inserted after + psIns - pointer to handle structure to be inserted after + uiParentOffset - offset to list head struct in handle structure + ui32EntryIndex - index of handle to be inserted + psEntry - pointer to handle structure of item to be inserted + uiEntryOffset - offset of list item struct in handle structure + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(HandleListInsertBefore) #endif static INLINE IMG_VOID HandleListInsertBefore(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32InsIndex, struct sHandleList *psIns, IMG_SIZE_T uiParentOffset, IMG_UINT32 ui32EntryIndex, struct sHandleList *psEntry, IMG_SIZE_T uiEntryOffset, IMG_UINT32 ui32ParentIndex) { - + /* PRQA S 3305 7 */ /*override stricter alignment warning */ struct sHandleList *psPrevIns = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psIns->ui32Prev, ui32ParentIndex, uiParentOffset, uiEntryOffset); - PVR_ASSERT(psEntry->hParent == IMG_NULL) - PVR_ASSERT(ui32InsIndex == psPrevIns->ui32Next) - PVR_ASSERT(LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, ui32ParentIndex, ui32ParentIndex, uiParentOffset, uiParentOffset)->hParent == INDEX_TO_HANDLE(ui32ParentIndex)) + PVR_ASSERT(psEntry->hParent == IMG_NULL); + PVR_ASSERT(ui32InsIndex == psPrevIns->ui32Next); + PVR_ASSERT(LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, ui32ParentIndex, ui32ParentIndex, uiParentOffset, uiParentOffset)->hParent == INDEX_TO_HANDLE(ui32ParentIndex)); psEntry->ui32Prev = psIns->ui32Prev; psIns->ui32Prev = ui32EntryIndex; @@ -348,6 +546,17 @@ IMG_VOID HandleListInsertBefore(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32InsIn psEntry->hParent = INDEX_TO_HANDLE(ui32ParentIndex); } +/*! +****************************************************************************** + + @Function AdoptChild + + @Description Assign a subhandle to a handle + + @Input psParent - pointer to handle structure of parent handle + psChild - pointer to handle structure of child subhandle + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(AdoptChild) #endif @@ -356,12 +565,25 @@ IMG_VOID AdoptChild(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psParent, struct { IMG_UINT32 ui32Parent = HANDLE_TO_INDEX(psParent->sChildren.hParent); - PVR_ASSERT(ui32Parent == HANDLE_PTR_TO_INDEX(psParent)) + PVR_ASSERT(ui32Parent == HANDLE_PTR_TO_INDEX(psParent)); HandleListInsertBefore(psBase, ui32Parent, &psParent->sChildren, offsetof(struct sHandle, sChildren), HANDLE_PTR_TO_INDEX(psChild), &psChild->sSiblings, offsetof(struct sHandle, sSiblings), ui32Parent); } +/*! +****************************************************************************** + + @Function HandleListRemove + + @Description Remove a handle from a list + + @Input ui32EntryIndex - index of handle to be removed + psEntry - pointer to handle structure of item to be removed + uiEntryOffset - offset of list item struct in handle structure + uiParentOffset - offset to list head struct in handle structure + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(HandleListRemove) #endif @@ -370,12 +592,15 @@ IMG_VOID HandleListRemove(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32EntryIndex, { if (!HandleListIsEmpty(ui32EntryIndex, psEntry)) { - + /* PRQA S 3305 3 */ /*override stricter alignment warning */ struct sHandleList *psPrev = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psEntry->ui32Prev, HANDLE_TO_INDEX(psEntry->hParent), uiParentOffset, uiEntryOffset); struct sHandleList *psNext = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psEntry->ui32Next, HANDLE_TO_INDEX(psEntry->hParent), uiParentOffset, uiEntryOffset); - - PVR_ASSERT(psEntry->hParent != IMG_NULL) + /* + * The list head is on the list, and we don't want to + * remove it. + */ + PVR_ASSERT(psEntry->hParent != IMG_NULL); psPrev->ui32Next = psEntry->ui32Next; psNext->ui32Prev = psEntry->ui32Prev; @@ -384,6 +609,16 @@ IMG_VOID HandleListRemove(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32EntryIndex, } } +/*! +****************************************************************************** + + @Function UnlinkFromParent + + @Description Remove a subhandle from its parents list + + @Input psHandle - pointer to handle structure of child subhandle + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(UnlinkFromParent) #endif @@ -393,6 +628,19 @@ IMG_VOID UnlinkFromParent(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHandle) HandleListRemove(psBase, HANDLE_PTR_TO_INDEX(psHandle), &psHandle->sSiblings, offsetof(struct sHandle, sSiblings), offsetof(struct sHandle, sChildren)); } +/*! +****************************************************************************** + + @Function HandleListIterate + + @Description Iterate over the items in a list + + @Input psHead - pointer to list head + uiParentOffset - offset to list head struct in handle structure + uiEntryOffset - offset of list item struct in handle structure + pfnIterFunc - function to be called for each handle in the list + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(HandleListIterate) #endif @@ -402,18 +650,24 @@ PVRSRV_ERROR HandleListIterate(PVRSRV_HANDLE_BASE *psBase, struct sHandleList *p IMG_UINT32 ui32Index; IMG_UINT32 ui32Parent = HANDLE_TO_INDEX(psHead->hParent); - PVR_ASSERT(psHead->hParent != IMG_NULL) + PVR_ASSERT(psHead->hParent != IMG_NULL); - + /* + * Follow the next chain from the list head until we reach + * the list head again, which signifies the end of the list. + */ for(ui32Index = psHead->ui32Next; ui32Index != ui32Parent; ) { struct sHandle *psHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, ui32Index); - + /* PRQA S 3305 2 */ /*override stricter alignment warning */ struct sHandleList *psEntry = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, ui32Index, ui32Parent, uiParentOffset, uiEntryOffset); PVRSRV_ERROR eError; - PVR_ASSERT(psEntry->hParent == psHead->hParent) - + PVR_ASSERT(psEntry->hParent == psHead->hParent); + /* + * Get the next index now, in case the list item is + * modified by the iteration function. + */ ui32Index = psEntry->ui32Next; eError = (*pfnIterFunc)(psBase, psHandle); @@ -426,6 +680,17 @@ PVRSRV_ERROR HandleListIterate(PVRSRV_HANDLE_BASE *psBase, struct sHandleList *p return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function IterateOverChildren + + @Description Iterate over the subhandles of a parent handle + + @Input psParent - pointer to parent handle structure + pfnIterFunc - function to be called for each subhandle + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(IterateOverChildren) #endif @@ -435,6 +700,24 @@ PVRSRV_ERROR IterateOverChildren(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psP return HandleListIterate(psBase, &psParent->sChildren, offsetof(struct sHandle, sChildren), offsetof(struct sHandle, sSiblings), pfnIterFunc); } +/*! +****************************************************************************** + + @Function GetHandleStructure + + @Description Get the handle structure for a given handle + + @Input psBase - pointer to handle base structure + ppsHandle - location to return pointer to handle structure + hHandle - handle from client + eType - handle type or PVRSRV_HANDLE_TYPE_NONE if the + handle type is not to be checked. + + @Output ppsHandle - points to a pointer to the handle structure + + @Return Error code or PVRSRV_OK + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(GetHandleStructure) #endif @@ -448,7 +731,7 @@ PVRSRV_ERROR GetHandleStructure(PVRSRV_HANDLE_BASE *psBase, struct sHandle **pps IMG_UINT32 ui32Index = HANDLE_TO_INDEX(hHandle); struct sHandle *psHandle; - + /* Check handle index is in range */ if (!INDEX_IS_VALID(psBase, ui32Index)) { PVR_DPF((PVR_DBG_ERROR, "GetHandleStructure: Handle index out of range (%u >= %u)", ui32Index, psBase->ui32TotalHandCount)); @@ -468,7 +751,10 @@ PVRSRV_ERROR GetHandleStructure(PVRSRV_HANDLE_BASE *psBase, struct sHandle **pps return PVRSRV_ERROR_HANDLE_NOT_ALLOCATED; } - + /* + * Unless PVRSRV_HANDLE_TYPE_NONE was passed in to this function, + * check handle is of the correct type. + */ if (eType != PVRSRV_HANDLE_TYPE_NONE && eType != psHandle->eType) { PVR_DPF((PVR_DBG_ERROR, "GetHandleStructure: Handle type mismatch (%d != %d)", eType, psHandle->eType)); @@ -478,12 +764,26 @@ PVRSRV_ERROR GetHandleStructure(PVRSRV_HANDLE_BASE *psBase, struct sHandle **pps return PVRSRV_ERROR_HANDLE_TYPE_MISMATCH; } - + /* Return the handle structure */ *ppsHandle = psHandle; return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function ParentIfPrivate + + @Description Return the parent handle if the handle was allocated + with PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE, else return + IMG_NULL + + @Input psHandle - pointer to handle + + @Return Parent handle, or IMG_NULL + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(ParentIfPrivate) #endif @@ -498,6 +798,19 @@ IMG_HANDLE ParentIfPrivate(struct sHandle *psHandle) ParentHandle(psHandle) : IMG_NULL; } +/*! +****************************************************************************** + + @Function InitKey + + @Description Initialise a hash table key for the current process + + @Input psBase - pointer to handle base structure + aKey - pointer to key + pvData - pointer to the resource the handle represents + eType - type of resource + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(InitKey) #endif @@ -515,6 +828,21 @@ IMG_VOID InitKey(HAND_KEY aKey, PVRSRV_HANDLE_BASE *psBase, IMG_VOID *pvData, PV aKey[HAND_KEY_PARENT] = (IMG_UINTPTR_T)hParent; } +/*! +****************************************************************************** + + @Function ReallocHandleArray + + @Description Reallocate the handle array + + @Input psBase - handle base. + phBlockAlloc - pointer to block allocation handle. + ui32NewCount - new handle count + ui32OldCount - old handle count + + @Return Error code or PVRSRV_OK + +******************************************************************************/ static PVRSRV_ERROR ReallocHandleArray(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32NewCount) { @@ -541,15 +869,15 @@ PVRSRV_ERROR ReallocHandleArray(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32NewCo if (((ui32OldCount % HANDLE_BLOCK_SIZE) != 0) || ((ui32NewCount % HANDLE_BLOCK_SIZE) != 0)) { - PVR_ASSERT((ui32OldCount % HANDLE_BLOCK_SIZE) == 0) - PVR_ASSERT((ui32NewCount % HANDLE_BLOCK_SIZE) == 0) + PVR_ASSERT((ui32OldCount % HANDLE_BLOCK_SIZE) == 0); + PVR_ASSERT((ui32NewCount % HANDLE_BLOCK_SIZE) == 0); return PVRSRV_ERROR_INVALID_PARAMS; } if (ui32NewCount != 0) { - + /* Allocate new handle array */ eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, HANDLE_ARRAY_SIZE(ui32NewCount) * sizeof(struct sHandleIndex), (IMG_VOID **)&psNewArray, @@ -568,7 +896,10 @@ PVRSRV_ERROR ReallocHandleArray(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32NewCo } } - + /* + * If the new handle array is smaller than the old one, free + * unused handle structures + */ for(ui32Index = ui32NewCount; ui32Index < ui32OldCount; ui32Index += HANDLE_BLOCK_SIZE) { struct sHandleIndex *psIndex = INDEX_TO_INDEX_STRUCT_PTR(psOldArray, ui32Index); @@ -583,10 +914,13 @@ PVRSRV_ERROR ReallocHandleArray(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32NewCo } } - + /* + * If the new handle array is bigger than the old one, allocate + * new handle structures + */ for(ui32Index = ui32OldCount; ui32Index < ui32NewCount; ui32Index += HANDLE_BLOCK_SIZE) { - + /* PRQA S 0505 1 */ /* psNewArray is never NULL, see assert earlier */ struct sHandleIndex *psIndex = INDEX_TO_INDEX_STRUCT_PTR(psNewArray, ui32Index); eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, @@ -624,7 +958,7 @@ PVRSRV_ERROR ReallocHandleArray(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32NewCo } #ifdef DEBUG_MAX_HANDLE_COUNT - + /* Force handle failure to test error exit code */ if (ui32NewCount > DEBUG_MAX_HANDLE_COUNT) { PVR_DPF((PVR_DBG_ERROR, "ReallocHandleArray: Max handle count (%u) reached", DEBUG_MAX_HANDLE_COUNT)); @@ -635,7 +969,7 @@ PVRSRV_ERROR ReallocHandleArray(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32NewCo if (psOldArray != IMG_NULL) { - + /* Free old handle array */ eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, HANDLE_ARRAY_SIZE(ui32OldCount) * sizeof(struct sHandleIndex), psOldArray, @@ -652,16 +986,21 @@ PVRSRV_ERROR ReallocHandleArray(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32NewCo if (ui32NewCount > ui32OldCount) { - - PVR_ASSERT(psBase->ui32FreeHandCount + (ui32NewCount - ui32OldCount) > psBase->ui32FreeHandCount) + /* Check for wraparound */ + PVR_ASSERT(psBase->ui32FreeHandCount + (ui32NewCount - ui32OldCount) > psBase->ui32FreeHandCount); - + /* PRQA S 3382 1 */ /* ui32NewCount always > ui32OldCount */ psBase->ui32FreeHandCount += (ui32NewCount - ui32OldCount); - + /* + * If purging is enabled, there is no free handle list + * management, but as an optimization, when allocating + * new handles, we use ui32FirstFreeIndex to point to + * the first handle in a newly allocated block. + */ if (psBase->ui32FirstFreeIndex == 0) { - PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0) + PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0); psBase->ui32FirstFreeIndex = ui32OldCount; } @@ -669,8 +1008,8 @@ PVRSRV_ERROR ReallocHandleArray(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32NewCo { if (!psBase->bPurgingEnabled) { - PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0) - PVR_ASSERT(INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne == 0) + PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0); + PVR_ASSERT(INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne == 0); INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne = ui32OldCount + 1; } @@ -683,11 +1022,11 @@ PVRSRV_ERROR ReallocHandleArray(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32NewCo } else { - PVR_ASSERT(ui32NewCount == 0 || psBase->bPurgingEnabled) - PVR_ASSERT(ui32NewCount == 0 || psBase->ui32FirstFreeIndex <= ui32NewCount) - PVR_ASSERT(psBase->ui32FreeHandCount - (ui32OldCount - ui32NewCount) < psBase->ui32FreeHandCount) + PVR_ASSERT(ui32NewCount == 0 || psBase->bPurgingEnabled); + PVR_ASSERT(ui32NewCount == 0 || psBase->ui32FirstFreeIndex <= ui32NewCount); + PVR_ASSERT(psBase->ui32FreeHandCount - (ui32OldCount - ui32NewCount) < psBase->ui32FreeHandCount); - + /* PRQA S 3382 1 */ /* ui32OldCount always >= ui32NewCount */ psBase->ui32FreeHandCount -= (ui32OldCount - ui32NewCount); if (ui32NewCount == 0) @@ -697,16 +1036,16 @@ PVRSRV_ERROR ReallocHandleArray(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32NewCo } } - PVR_ASSERT(psBase->ui32FirstFreeIndex <= psBase->ui32TotalHandCount) + PVR_ASSERT(psBase->ui32FirstFreeIndex <= psBase->ui32TotalHandCount); return PVRSRV_OK; error: - PVR_ASSERT(eReturn != PVRSRV_OK) + PVR_ASSERT(eReturn != PVRSRV_OK); if (psNewArray != IMG_NULL) { - + /* Free any new handle structures that were allocated */ for(ui32Index = ui32OldCount; ui32Index < ui32NewCount; ui32Index += HANDLE_BLOCK_SIZE) { struct sHandleIndex *psIndex = INDEX_TO_INDEX_STRUCT_PTR(psNewArray, ui32Index); @@ -723,7 +1062,7 @@ error: } } - + /* Free new handle array */ eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, HANDLE_ARRAY_SIZE(ui32NewCount) * sizeof(struct sHandleIndex), psNewArray, @@ -737,18 +1076,52 @@ error: return eReturn; } +/*! +****************************************************************************** + + @Function FreeHandleArray + + @Description Frees the handle array. + The memory containing the array of handle structure + pointers is deallocated. + + @Input psBase - pointer to handle base structure + + @Return Error code or PVRSRV_OK + +******************************************************************************/ static PVRSRV_ERROR FreeHandleArray(PVRSRV_HANDLE_BASE *psBase) { return ReallocHandleArray(psBase, 0); } +/*! +****************************************************************************** + + @Function FreeHandle + + @Description Free a handle structure. + + @Input psBase - pointer to handle base structure + psHandle - pointer to handle structure + + @Return PVRSRV_OK or PVRSRV_ERROR + +******************************************************************************/ static PVRSRV_ERROR FreeHandle(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHandle) { HAND_KEY aKey; IMG_UINT32 ui32Index = HANDLE_PTR_TO_INDEX(psHandle); PVRSRV_ERROR eError; - + /* + * If a handle allocated in batch mode is freed whilst still + * in batch mode, the type is set to PVRSRV_HANDLE_TYPE_NONE further + * down, to indicate the handle will not be used, but not actually + * freed. The Free is completed when this function is called a + * second time as part of the batch commit or release. + */ + InitKey(aKey, psBase, psHandle->pvData, psHandle->eType, ParentIfPrivate(psHandle)); if (!TEST_ALLOC_FLAG(psHandle, PVRSRV_HANDLE_ALLOC_FLAG_MULTI) && !BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) @@ -762,15 +1135,15 @@ static PVRSRV_ERROR FreeHandle(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHan #endif - PVR_ASSERT(hHandle != IMG_NULL) - PVR_ASSERT(hHandle == INDEX_TO_HANDLE(ui32Index)) + PVR_ASSERT(hHandle != IMG_NULL); + PVR_ASSERT(hHandle == INDEX_TO_HANDLE(ui32Index)); PVR_UNREFERENCED_PARAMETER(hHandle); } - + /* Unlink handle from parent */ UnlinkFromParent(psBase, psHandle); - + /* Free children */ eError = IterateOverChildren(psBase, psHandle, FreeHandle); if (eError != PVRSRV_OK) { @@ -778,45 +1151,54 @@ static PVRSRV_ERROR FreeHandle(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHan return eError; } - + /* + * Clear the type here, so that a handle can no longer be looked + * up if it is only partially freed. + */ psHandle->eType = PVRSRV_HANDLE_TYPE_NONE; if (BATCHED_HANDLE(psHandle) && !BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) { - + /* PRQA S 1474,4130 1 */ /* ignore warnings about enum types being modified */ SET_BATCHED_HANDLE_PARTIALLY_FREE(psHandle); - + /* + * If the handle was allocated in batch mode, delay the free + * until the batch commit or release. + */ return PVRSRV_OK; } - + /* No free list management if purging is enabled */ if (!psBase->bPurgingEnabled) { if (psBase->ui32FreeHandCount == 0) { - PVR_ASSERT(psBase->ui32FirstFreeIndex == 0) - PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0) + PVR_ASSERT(psBase->ui32FirstFreeIndex == 0); + PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0); psBase->ui32FirstFreeIndex = ui32Index; } else { - - PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0) - PVR_ASSERT(INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne == 0) + /* + * Put the handle pointer on the end of the the free + * handle pointer linked list. + */ + PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0); + PVR_ASSERT(INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne == 0); INDEX_TO_HANDLE_STRUCT_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne = ui32Index + 1; } - PVR_ASSERT(psHandle->ui32NextIndexPlusOne == 0) + PVR_ASSERT(psHandle->ui32NextIndexPlusOne == 0); - + /* Update the end of the free handle linked list */ psBase->ui32LastFreeIndexPlusOne = ui32Index + 1; } psBase->ui32FreeHandCount++; INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32Index)++; - PVR_ASSERT(INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32Index)<= HANDLE_BLOCK_SIZE) + PVR_ASSERT(INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32Index)<= HANDLE_BLOCK_SIZE); #ifdef DEBUG { @@ -828,13 +1210,25 @@ static PVRSRV_ERROR FreeHandle(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHan ui32FreeHandCount += INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32BlockedIndex); } - PVR_ASSERT(ui32FreeHandCount == psBase->ui32FreeHandCount) + PVR_ASSERT(ui32FreeHandCount == psBase->ui32FreeHandCount); } #endif return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function FreeAllHandles + + @Description Free all handles for a given handle base + + @Input psBase - pointer to handle base structure + + @Return PVRSRV_OK or PVRSRV_ERROR + +******************************************************************************/ static PVRSRV_ERROR FreeAllHandles(PVRSRV_HANDLE_BASE *psBase) { IMG_UINT32 i; @@ -860,7 +1254,7 @@ static PVRSRV_ERROR FreeAllHandles(PVRSRV_HANDLE_BASE *psBase) break; } - + /* Break out of loop if all the handles free */ if (psBase->ui32FreeHandCount == psBase->ui32TotalHandCount) { break; @@ -871,6 +1265,18 @@ static PVRSRV_ERROR FreeAllHandles(PVRSRV_HANDLE_BASE *psBase) return eError; } +/*! +****************************************************************************** + + @Function FreeHandleBase + + @Description Free a handle base. + + @Input psHandleBase - pointer to handle base + + @Return Error code or PVRSRV_OK + +******************************************************************************/ static PVRSRV_ERROR FreeHandleBase(PVRSRV_HANDLE_BASE *psBase) { PVRSRV_ERROR eError; @@ -881,7 +1287,7 @@ static PVRSRV_ERROR FreeHandleBase(PVRSRV_HANDLE_BASE *psBase) PVRSRVReleaseHandleBatch(psBase); } - + /* Free the handle array */ eError = FreeAllHandles(psBase); if (eError != PVRSRV_OK) { @@ -889,7 +1295,7 @@ static PVRSRV_ERROR FreeHandleBase(PVRSRV_HANDLE_BASE *psBase) return eError; } - + /* Free the handle array */ eError = FreeHandleArray(psBase); if (eError != PVRSRV_OK) { @@ -899,7 +1305,7 @@ static PVRSRV_ERROR FreeHandleBase(PVRSRV_HANDLE_BASE *psBase) if (psBase->psHashTab != IMG_NULL) { - + /* Free the hash table */ HASH_Delete(psBase->psHashTab); } @@ -916,6 +1322,20 @@ static PVRSRV_ERROR FreeHandleBase(PVRSRV_HANDLE_BASE *psBase) return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function FindHandle + + @Description Find handle corresponding to a resource pointer + + @Input psBase - pointer to handle base structure + pvData - pointer to resource to be associated with the handle + eType - the type of resource + + @Return the handle, or IMG_NULL if not found + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(FindHandle) #endif @@ -928,7 +1348,7 @@ IMG_HANDLE FindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_VOID *pvData, PVRSRV_HANDL { HAND_KEY aKey; - PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE) + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); InitKey(aKey, psBase, pvData, eType, hParent); @@ -939,16 +1359,30 @@ IMG_HANDLE FindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_VOID *pvData, PVRSRV_HANDL #endif } +/*! +****************************************************************************** + + @Function IncreaseHandleArraySize + + @Description Allocate some more free handles + + @Input psBase - pointer to handle base structure + ui32Delta - number of new handles required + + @Return Error code or PVRSRV_OK + +******************************************************************************/ static PVRSRV_ERROR IncreaseHandleArraySize(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32Delta) { PVRSRV_ERROR eError; IMG_UINT32 ui32DeltaAdjusted = ROUND_UP_TO_MULTIPLE_OF_BLOCK_SIZE(ui32Delta); IMG_UINT32 ui32NewTotalHandCount = psBase->ui32TotalHandCount + ui32DeltaAdjusted; -; - PVR_ASSERT(ui32Delta != 0) + PVR_ASSERT(ui32Delta != 0); - + /* + * Check new count against max handle index, and check for wrap around. + */ if (ui32NewTotalHandCount > psBase->ui32MaxIndexPlusOne || ui32NewTotalHandCount <= psBase->ui32TotalHandCount) { ui32NewTotalHandCount = psBase->ui32MaxIndexPlusOne; @@ -962,9 +1396,9 @@ static PVRSRV_ERROR IncreaseHandleArraySize(PVRSRV_HANDLE_BASE *psBase, IMG_UINT } } - PVR_ASSERT(ui32DeltaAdjusted >= ui32Delta) + PVR_ASSERT(ui32DeltaAdjusted >= ui32Delta); - + /* Realloc handle pointer array */ eError = ReallocHandleArray(psBase, ui32NewTotalHandCount); if (eError != PVRSRV_OK) { @@ -975,6 +1409,19 @@ static PVRSRV_ERROR IncreaseHandleArraySize(PVRSRV_HANDLE_BASE *psBase, IMG_UINT return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function EnsureFreeHandles + + @Description Ensure there are enough free handles + + @Input psBase - pointer to handle base structure + ui32Free - number of free handles required + + @Return Error code or PVRSRV_OK + +******************************************************************************/ static PVRSRV_ERROR EnsureFreeHandles(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32Free) { PVRSRV_ERROR eError; @@ -994,6 +1441,23 @@ static PVRSRV_ERROR EnsureFreeHandles(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui3 return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function AllocHandle + + @Description Allocate a new handle + + @Input phHandle - location for new handle + pvData - pointer to resource to be associated with the handle + eType - the type of resource + hParent - parent handle or IMG_NULL + + @Output phHandle - points to new handle + + @Return Error code or PVRSRV_OK + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) static PVRSRV_ERROR AllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag, IMG_SID hParent) #else @@ -1010,15 +1474,15 @@ static PVRSRV_ERROR AllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle HAND_KEY aKey; PVRSRV_ERROR eError; - - PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE) - PVR_ASSERT(psBase != IMG_NULL) - PVR_ASSERT(psBase->psHashTab != IMG_NULL) + /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */ + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); + PVR_ASSERT(psBase != IMG_NULL); + PVR_ASSERT(psBase->psHashTab != IMG_NULL); if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) { - - PVR_ASSERT(FindHandle(psBase, pvData, eType, hParent) == IMG_NULL) + /* Handle must not already exist */ + PVR_ASSERT(FindHandle(psBase, pvData, eType, hParent) == IMG_NULL); } if (psBase->ui32FreeHandCount == 0 && HANDLES_BATCHED(psBase)) @@ -1026,30 +1490,41 @@ static PVRSRV_ERROR AllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle PVR_DPF((PVR_DBG_WARNING, "AllocHandle: Handle batch size (%u) was too small, allocating additional space", psBase->ui32HandBatchSize)); } - + /* Ensure there is a free handle */ eError = EnsureFreeHandles(psBase, 1); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "AllocHandle: EnsureFreeHandles failed (%d)", eError)); return eError; } - PVR_ASSERT(psBase->ui32FreeHandCount != 0) + PVR_ASSERT(psBase->ui32FreeHandCount != 0); if (!psBase->bPurgingEnabled) { - + /* Array index of first free handle */ ui32NewIndex = psBase->ui32FirstFreeIndex; - + /* Get handle array entry */ psNewHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, ui32NewIndex); } else { IMG_UINT32 ui32BlockedIndex; - - - PVR_ASSERT((psBase->ui32FirstFreeIndex % HANDLE_BLOCK_SIZE) == 0) + /* + * If purging is enabled, we always try to allocate handles + * at the front of the array, to increase the chances that + * the size of the handle array can be reduced by a purge. + * No linked list of free handles is kept; we search for + * free handles as required. + */ + + /* + * ui32FirstFreeIndex should only be set when a new batch of + * handle structures is allocated, and should always be a + * multiple of the block size. + */ + PVR_ASSERT((psBase->ui32FirstFreeIndex % HANDLE_BLOCK_SIZE) == 0); for (ui32BlockedIndex = ROUND_DOWN_TO_MULTIPLE_OF_BLOCK_SIZE(psBase->ui32FirstFreeIndex); ui32BlockedIndex < psBase->ui32TotalHandCount; ui32BlockedIndex += HANDLE_BLOCK_SIZE) { @@ -1070,20 +1545,24 @@ static PVRSRV_ERROR AllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle } } psBase->ui32FirstFreeIndex = 0; - PVR_ASSERT(ui32NewIndex < psBase->ui32TotalHandCount) + PVR_ASSERT(ui32NewIndex < psBase->ui32TotalHandCount); } - PVR_ASSERT(psNewHandle != IMG_NULL) + PVR_ASSERT(psNewHandle != IMG_NULL); - + /* Handle to be returned to client */ hHandle = INDEX_TO_HANDLE(ui32NewIndex); - + /* + * If a data pointer can be associated with multiple handles, we + * don't put the handle in the hash table, as the data pointer + * may not map to a unique handle + */ if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) { - + /* Initialise hash key */ InitKey(aKey, psBase, pvData, eType, hParent); - + /* Put the new handle in the hash table */ if (!HASH_Insert_Extended(psBase->psHashTab, aKey, (IMG_UINTPTR_T)hHandle)) { PVR_DPF((PVR_DBG_ERROR, "AllocHandle: Couldn't add handle to hash table")); @@ -1094,36 +1573,44 @@ static PVRSRV_ERROR AllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle psBase->ui32FreeHandCount--; - PVR_ASSERT(INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32NewIndex) <= HANDLE_BLOCK_SIZE) - PVR_ASSERT(INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32NewIndex) > 0) + PVR_ASSERT(INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32NewIndex) <= HANDLE_BLOCK_SIZE); + PVR_ASSERT(INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32NewIndex) > 0); INDEX_TO_FREE_HAND_BLOCK_COUNT(psBase, ui32NewIndex)--; - + /* No free list management if purging is enabled */ if (!psBase->bPurgingEnabled) { - + /* Check whether the last free handle has been allocated */ if (psBase->ui32FreeHandCount == 0) { - PVR_ASSERT(psBase->ui32FirstFreeIndex == ui32NewIndex) - PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == (ui32NewIndex + 1)) + PVR_ASSERT(psBase->ui32FirstFreeIndex == ui32NewIndex); + PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == (ui32NewIndex + 1)); psBase->ui32LastFreeIndexPlusOne = 0; psBase->ui32FirstFreeIndex = 0; } else { - + /* + * Update the first free handle index. + * If the "next free index plus one" field in the new + * handle structure is zero, the next free index is + * the index of the new handle plus one. This + * convention has been adopted to simplify the + * initialisation of freshly allocated handle + * space. + */ psBase->ui32FirstFreeIndex = (psNewHandle->ui32NextIndexPlusOne == 0) ? ui32NewIndex + 1 : psNewHandle->ui32NextIndexPlusOne - 1; } } - - PVR_ASSERT(psNewHandle->ui32Index == ui32NewIndex) + /* Initialise the newly allocated handle */ + PVR_ASSERT(psNewHandle->ui32Index == ui32NewIndex); - + /* PRQA S 0505 1 */ /* psNewHandle is never NULL, see assert earlier */ psNewHandle->eType = eType; psNewHandle->pvData = pvData; psNewHandle->eInternalFlag = INTERNAL_HANDLE_FLAG_NONE; @@ -1131,22 +1618,22 @@ static PVRSRV_ERROR AllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle InitParentList(psNewHandle); #if defined(DEBUG) - PVR_ASSERT(NoChildren(psNewHandle)) + PVR_ASSERT(NoChildren(psNewHandle)); #endif InitChildEntry(psNewHandle); #if defined(DEBUG) - PVR_ASSERT(NoParent(psNewHandle)) + PVR_ASSERT(NoParent(psNewHandle)); #endif if (HANDLES_BATCHED(psBase)) { - + /* Add handle to batch list */ psNewHandle->ui32NextIndexPlusOne = psBase->ui32FirstBatchIndexPlusOne; psBase->ui32FirstBatchIndexPlusOne = ui32NewIndex + 1; - + /* PRQA S 1474 1 */ /* ignore warnings about enum types being modified */ SET_BATCHED_HANDLE(psNewHandle); } else @@ -1154,12 +1641,28 @@ static PVRSRV_ERROR AllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle psNewHandle->ui32NextIndexPlusOne = 0; } - + /* Return the new handle to the client */ *phHandle = hHandle; return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVAllocHandle + + @Description Allocate a handle + + @Input phHandle - location for new handle + pvData - pointer to resource to be associated with the handle + eType - the type of resource + + @Output phHandle - points to new handle + + @Return Error code or PVRSRV_OK + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR PVRSRVAllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag) #else @@ -1181,16 +1684,19 @@ PVRSRV_ERROR PVRSRVAllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, if (HANDLES_BATCHED(psBase)) { - + /* + * Increment the counter in case of failure. It will be + * decremented on success. + */ psBase->ui32BatchHandAllocFailures++; } - - PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE) + /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */ + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) { - + /* See if there is already a handle for this data pointer */ hHandle = FindHandle(psBase, pvData, eType, IMG_NULL); #if defined (SUPPORT_SID_INTERFACE) if (hHandle != 0) @@ -1207,7 +1713,11 @@ PVRSRV_ERROR PVRSRVAllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, return eError; } - + /* + * If the client is willing to share a handle, and the + * existing handle is marked as shareable, return the + * existing handle. + */ if (TEST_FLAG(psHandle->eFlag & eFlag, PVRSRV_HANDLE_ALLOC_FLAG_SHARED)) { *phHandle = hHandle; @@ -1233,6 +1743,23 @@ exit_ok: return eError; } +/*! +****************************************************************************** + + @Function PVRSRVAllocSubHandle + + @Description Allocate a subhandle + + @Input phHandle - location for new subhandle + pvData - pointer to resource to be associated with the subhandle + eType - the type of resource + hParent - parent handle + + @Output phHandle - points to new subhandle + + @Return Error code or PVRSRV_OK + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR PVRSRVAllocSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag, IMG_SID hParent) #else @@ -1256,17 +1783,20 @@ PVRSRV_ERROR PVRSRVAllocSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHand if (HANDLES_BATCHED(psBase)) { - + /* + * Increment the counter in case of failure. It will be + * decremented on success. + */ psBase->ui32BatchHandAllocFailures++; } - - PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE) + /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */ + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); hParentKey = TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ? hParent : IMG_NULL; - + /* Lookup the parent handle */ eError = GetHandleStructure(psBase, &psPHand, hParent, PVRSRV_HANDLE_TYPE_NONE); if (eError != PVRSRV_OK) { @@ -1275,7 +1805,7 @@ PVRSRV_ERROR PVRSRVAllocSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHand if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) { - + /* See if there is already a handle for this data pointer */ hHandle = FindHandle(psBase, pvData, eType, hParentKey); #if defined (SUPPORT_SID_INTERFACE) if (hHandle != 0) @@ -1293,9 +1823,14 @@ PVRSRV_ERROR PVRSRVAllocSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHand return eErr; } - PVR_ASSERT(hParentKey != IMG_NULL && ParentHandle(HANDLE_TO_HANDLE_STRUCT_PTR(psBase, hHandle)) == hParent) + PVR_ASSERT(hParentKey != IMG_NULL && ParentHandle(HANDLE_TO_HANDLE_STRUCT_PTR(psBase, hHandle)) == hParent); - + /* + * If the client is willing to share a handle, the + * existing handle is marked as shareable, and the + * existing handle has the same parent, return the + * existing handle. + */ if (TEST_FLAG(psCHandle->eFlag & eFlag, PVRSRV_HANDLE_ALLOC_FLAG_SHARED) && ParentHandle(HANDLE_TO_HANDLE_STRUCT_PTR(psBase, hHandle)) == hParent) { *phHandle = hHandle; @@ -1314,7 +1849,11 @@ PVRSRV_ERROR PVRSRVAllocSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHand return eError; } - + /* + * Get the parent handle structure again, in case the handle + * structure has moved (depending on the implementation + * of AllocHandle). + */ psPHand = HANDLE_TO_HANDLE_STRUCT_PTR(psBase, hParent); psCHand = HANDLE_TO_HANDLE_STRUCT_PTR(psBase, hHandle); @@ -1332,6 +1871,22 @@ exit_ok: return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVFindHandle + + @Description Find handle corresponding to a resource pointer + + @Input phHandle - location for returned handle + pvData - pointer to resource to be associated with the handle + eType - the type of resource + + @Output phHandle - points to handle + + @Return Error code or PVRSRV_OK + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR PVRSRVFindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType) #else @@ -1344,9 +1899,9 @@ PVRSRV_ERROR PVRSRVFindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, IMG_HANDLE hHandle; #endif - PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE) + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); - + /* See if there is a handle for this data pointer */ #if defined (SUPPORT_SID_INTERFACE) hHandle = (IMG_SID) FindHandle(psBase, pvData, eType, IMG_NULL); #else @@ -1362,6 +1917,23 @@ PVRSRV_ERROR PVRSRVFindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVLookupHandleAnyType + + @Description Lookup the data pointer and type corresponding to a handle + + @Input ppvData - location to return data pointer + peType - location to return handle type + hHandle - handle from client + + @Output ppvData - points to the data pointer + peType - points to handle type + + @Return Error code or PVRSRV_OK + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR PVRSRVLookupHandleAnyType(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, PVRSRV_HANDLE_TYPE *peType, IMG_SID hHandle) #else @@ -1387,6 +1959,22 @@ PVRSRV_ERROR PVRSRVLookupHandleAnyType(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *pp return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVLookupHandle + + @Description Lookup the data pointer corresponding to a handle + + @Input ppvData - location to return data pointer + hHandle - handle from client + eType - handle type + + @Output ppvData - points to the data pointer + + @Return Error code or PVRSRV_OK + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR PVRSRVLookupHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType) #else @@ -1396,9 +1984,9 @@ PVRSRV_ERROR PVRSRVLookupHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, struct sHandle *psHandle; PVRSRV_ERROR eError; - PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE) + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); #if defined (SUPPORT_SID_INTERFACE) - PVR_ASSERT(hHandle != 0) + PVR_ASSERT(hHandle != 0); #endif eError = GetHandleStructure(psBase, &psHandle, hHandle, eType); @@ -1416,6 +2004,23 @@ PVRSRV_ERROR PVRSRVLookupHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVLookupSubHandle + + @Description Lookup the data pointer corresponding to a subhandle + + @Input ppvData - location to return data pointer + hHandle - handle from client + eType - handle type + hAncestor - ancestor handle + + @Output ppvData - points to the data pointer + + @Return Error code or PVRSRV_OK + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR PVRSRVLookupSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType, IMG_SID hAncestor) #else @@ -1426,9 +2031,9 @@ PVRSRV_ERROR PVRSRVLookupSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvDat struct sHandle *psCHand; PVRSRV_ERROR eError; - PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE) + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); #if defined (SUPPORT_SID_INTERFACE) - PVR_ASSERT(hHandle != 0) + PVR_ASSERT(hHandle != 0); #endif eError = GetHandleStructure(psBase, &psCHand, hHandle, eType); @@ -1438,7 +2043,7 @@ PVRSRV_ERROR PVRSRVLookupSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvDat return eError; } - + /* Look for hAncestor among the handle's ancestors */ for (psPHand = psCHand; ParentHandle(psPHand) != hAncestor; ) { eError = GetHandleStructure(psBase, &psPHand, ParentHandle(psPHand), PVRSRV_HANDLE_TYPE_NONE); @@ -1454,6 +2059,24 @@ PVRSRV_ERROR PVRSRVLookupSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvDat return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVGetParentHandle + + @Description Lookup the parent of a handle + + @Input phParent - location for returning parent handle + hHandle - handle for which the parent handle is required + eType - handle type + hParent - parent handle + + @Output *phParent - parent handle, or IMG_NULL if there is no parent + + @Return Error code or PVRSRV_OK. Note that not having a parent is + not regarded as an error. + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR PVRSRVGetParentHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID *phParent, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType) #else @@ -1463,7 +2086,7 @@ PVRSRV_ERROR PVRSRVGetParentHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *phPare struct sHandle *psHandle; PVRSRV_ERROR eError; - PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE) + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); eError = GetHandleStructure(psBase, &psHandle, hHandle, eType); if (eError != PVRSRV_OK) @@ -1477,6 +2100,23 @@ PVRSRV_ERROR PVRSRVGetParentHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *phPare return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVLookupAndReleaseHandle + + @Description Lookup the data pointer corresponding to a handle + + @Input ppvData - location to return data pointer + hHandle - handle from client + eType - handle type + eFlag - lookup flags + + @Output ppvData - points to the data pointer + + @Return Error code or PVRSRV_OK + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR PVRSRVLookupAndReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType) #else @@ -1486,7 +2126,7 @@ PVRSRV_ERROR PVRSRVLookupAndReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID struct sHandle *psHandle; PVRSRV_ERROR eError; - PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE) + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); eError = GetHandleStructure(psBase, &psHandle, hHandle, eType); if (eError != PVRSRV_OK) @@ -1505,6 +2145,19 @@ PVRSRV_ERROR PVRSRVLookupAndReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID return eError; } +/*! +****************************************************************************** + + @Function PVRSRVReleaseHandle + + @Description Release a handle that is no longer needed + + @Input hHandle - handle from client + eType - handle type + + @Return Error code or PVRSRV_OK + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR PVRSRVReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_SID hHandle, PVRSRV_HANDLE_TYPE eType) #else @@ -1514,7 +2167,7 @@ PVRSRV_ERROR PVRSRVReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE hHandle, struct sHandle *psHandle; PVRSRV_ERROR eError; - PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE) + PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE); eError = GetHandleStructure(psBase, &psHandle, hHandle, eType); if (eError != PVRSRV_OK) @@ -1528,6 +2181,19 @@ PVRSRV_ERROR PVRSRVReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE hHandle, return eError; } +/*! +****************************************************************************** + + @Function PVRSRVNewHandleBatch + + @Description Start a new handle batch + + @Input psBase - handle base + @Input ui32BatchSize - handle batch size + + @Return Error code or PVRSRV_OK + +******************************************************************************/ PVRSRV_ERROR PVRSRVNewHandleBatch(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32BatchSize) { PVRSRV_ERROR eError; @@ -1553,18 +2219,31 @@ PVRSRV_ERROR PVRSRVNewHandleBatch(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32Bat psBase->ui32HandBatchSize = ui32BatchSize; - + /* Record current number of handles */ psBase->ui32TotalHandCountPreBatch = psBase->ui32TotalHandCount; - PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0) + PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0); - PVR_ASSERT(psBase->ui32FirstBatchIndexPlusOne == 0) + PVR_ASSERT(psBase->ui32FirstBatchIndexPlusOne == 0); - PVR_ASSERT(HANDLES_BATCHED(psBase)) + PVR_ASSERT(HANDLES_BATCHED(psBase)); return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVHandleBatchCommitOrRelease + + @Description Release a handle batch + + @Input psBase - handle base + bCommit - commit handles + + @Return none + +******************************************************************************/ static PVRSRV_ERROR PVRSRVHandleBatchCommitOrRelease(PVRSRV_HANDLE_BASE *psBase, IMG_BOOL bCommit) { @@ -1587,24 +2266,32 @@ static PVRSRV_ERROR PVRSRVHandleBatchCommitOrRelease(PVRSRV_HANDLE_BASE *psBase, } bCommitBatch = IMG_FALSE; } - - PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0 || !bCommit) + /* + * The whole point of batched handles is to avoid handle allocation + * failures. + */ + PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0 || !bCommit); ui32IndexPlusOne = psBase->ui32FirstBatchIndexPlusOne; while(ui32IndexPlusOne != 0) { struct sHandle *psHandle = INDEX_TO_HANDLE_STRUCT_PTR(psBase, ui32IndexPlusOne - 1); IMG_UINT32 ui32NextIndexPlusOne = psHandle->ui32NextIndexPlusOne; - PVR_ASSERT(BATCHED_HANDLE(psHandle)) + PVR_ASSERT(BATCHED_HANDLE(psHandle)); psHandle->ui32NextIndexPlusOne = 0; if (!bCommitBatch || BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) { + /* + * We need a complete free here. If the handle + * is not partially free, set the handle as + * unbatched to avoid a partial free. + */ if (!BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) { - - SET_UNBATCHED_HANDLE(psHandle); + /* PRQA S 1474,4130 1 */ /* ignore warnings about enum types being modified */ + SET_UNBATCHED_HANDLE(psHandle); /* PRQA S 4130 */ /* mis-use of enums FIXME*/ } eError = FreeHandle(psBase, psHandle); @@ -1612,11 +2299,11 @@ static PVRSRV_ERROR PVRSRVHandleBatchCommitOrRelease(PVRSRV_HANDLE_BASE *psBase, { PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleBatchCommitOrRelease: Error freeing handle (%d)", eError)); } - PVR_ASSERT(eError == PVRSRV_OK) + PVR_ASSERT(eError == PVRSRV_OK); } else { - + /* PRQA S 1474,4130 1 */ /* ignore warnings about enum types being modified */ SET_UNBATCHED_HANDLE(psHandle); } @@ -1628,7 +2315,7 @@ static PVRSRV_ERROR PVRSRVHandleBatchCommitOrRelease(PVRSRV_HANDLE_BASE *psBase, { IMG_UINT32 ui32Delta = psBase->ui32TotalHandCount - psBase->ui32TotalHandCountPreBatch; - PVR_ASSERT(psBase->ui32TotalHandCount > psBase->ui32TotalHandCountPreBatch) + PVR_ASSERT(psBase->ui32TotalHandCount > psBase->ui32TotalHandCountPreBatch); PVR_DPF((PVR_DBG_WARNING, "PVRSRVHandleBatchCommitOrRelease: The batch size was too small. Batch size was %u, but needs to be %u", psBase->ui32HandBatchSize, psBase->ui32HandBatchSize + ui32Delta)); @@ -1639,7 +2326,7 @@ static PVRSRV_ERROR PVRSRVHandleBatchCommitOrRelease(PVRSRV_HANDLE_BASE *psBase, if (psBase->ui32BatchHandAllocFailures != 0 && bCommit) { - PVR_ASSERT(!bCommitBatch) + PVR_ASSERT(!bCommitBatch); eError = PVRSRV_ERROR_HANDLE_BATCH_COMMIT_FAILURE; } @@ -1652,16 +2339,53 @@ static PVRSRV_ERROR PVRSRVHandleBatchCommitOrRelease(PVRSRV_HANDLE_BASE *psBase, return eError; } +/*! +****************************************************************************** + + @Function PVRSRVCommitHandleBatch + + @Description Commit a handle batch + + @Input psBase - handle base + + @Return Error code or PVRSRV_OK + +******************************************************************************/ PVRSRV_ERROR PVRSRVCommitHandleBatch(PVRSRV_HANDLE_BASE *psBase) { return PVRSRVHandleBatchCommitOrRelease(psBase, IMG_TRUE); } +/*! +****************************************************************************** + + @Function PVRSRReleaseHandleBatch + + @Description Release a handle batch + + @Input psBase - handle base + + @Return none + +******************************************************************************/ IMG_VOID PVRSRVReleaseHandleBatch(PVRSRV_HANDLE_BASE *psBase) { (IMG_VOID) PVRSRVHandleBatchCommitOrRelease(psBase, IMG_FALSE); } +/*! +****************************************************************************** + + @Function PVRSRVSetMaxHandle + + @Description Set maximum handle number for given handle base + + @Input psBase - pointer to handle base structure + ui32MaxHandle - Maximum handle number + + @Return Error code or PVRSRV_OK + +******************************************************************************/ PVRSRV_ERROR PVRSRVSetMaxHandle(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32MaxHandle) { IMG_UINT32 ui32MaxHandleRounded; @@ -1672,7 +2396,7 @@ PVRSRV_ERROR PVRSRVSetMaxHandle(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32MaxHa return PVRSRV_ERROR_INVALID_PARAMS; } - + /* Validate the limit */ if (ui32MaxHandle == 0 || ui32MaxHandle > DEFAULT_MAX_HANDLE) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVSetMaxHandle: Limit must be between %u and %u, inclusive", 0, DEFAULT_MAX_HANDLE)); @@ -1680,7 +2404,7 @@ PVRSRV_ERROR PVRSRVSetMaxHandle(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32MaxHa return PVRSRV_ERROR_INVALID_PARAMS; } - + /* The limit can only be set if no handles have been allocated */ if (psBase->ui32TotalHandCount != 0) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVSetMaxHandle: Limit cannot be set because handles have already been allocated")); @@ -1690,24 +2414,54 @@ PVRSRV_ERROR PVRSRVSetMaxHandle(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32MaxHa ui32MaxHandleRounded = ROUND_DOWN_TO_MULTIPLE_OF_BLOCK_SIZE(ui32MaxHandle); - + /* + * Allow the maximum number of handles to be reduced, but never to + * zero. + */ if (ui32MaxHandleRounded != 0 && ui32MaxHandleRounded < psBase->ui32MaxIndexPlusOne) { psBase->ui32MaxIndexPlusOne = ui32MaxHandleRounded; } - PVR_ASSERT(psBase->ui32MaxIndexPlusOne != 0) - PVR_ASSERT(psBase->ui32MaxIndexPlusOne <= DEFAULT_MAX_INDEX_PLUS_ONE) - PVR_ASSERT((psBase->ui32MaxIndexPlusOne % HANDLE_BLOCK_SIZE) == 0) + PVR_ASSERT(psBase->ui32MaxIndexPlusOne != 0); + PVR_ASSERT(psBase->ui32MaxIndexPlusOne <= DEFAULT_MAX_INDEX_PLUS_ONE); + PVR_ASSERT((psBase->ui32MaxIndexPlusOne % HANDLE_BLOCK_SIZE) == 0); return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVGetMaxHandle + + @Description Get maximum handle number for given handle base + + @Input psBase - pointer to handle base structure + + @Output Maximum handle number, or 0 if handle limits not + supported. + + @Return Error code or PVRSRV_OK + +******************************************************************************/ IMG_UINT32 PVRSRVGetMaxHandle(PVRSRV_HANDLE_BASE *psBase) { return psBase->ui32MaxIndexPlusOne; } +/*! +****************************************************************************** + + @Function PVRSRVEnableHandlePurging + + @Description Enable purging for a given handle base + + @Input psBase - pointer to handle base structure + + @Return Error code or PVRSRV_OK + +******************************************************************************/ PVRSRV_ERROR PVRSRVEnableHandlePurging(PVRSRV_HANDLE_BASE *psBase) { if (psBase->bPurgingEnabled) @@ -1716,7 +2470,7 @@ PVRSRV_ERROR PVRSRVEnableHandlePurging(PVRSRV_HANDLE_BASE *psBase) return PVRSRV_OK; } - + /* Purging can only be enabled if no handles have been allocated */ if (psBase->ui32TotalHandCount != 0) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVEnableHandlePurging: Handles have already been allocated")); @@ -1728,6 +2482,18 @@ PVRSRV_ERROR PVRSRVEnableHandlePurging(PVRSRV_HANDLE_BASE *psBase) return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVPurgeHandles + + @Description Purge handles for a given handle base + + @Input psBase - pointer to handle base structure + + @Return Error code or PVRSRV_OK + +******************************************************************************/ PVRSRV_ERROR PVRSRVPurgeHandles(PVRSRV_HANDLE_BASE *psBase) { IMG_UINT32 ui32BlockIndex; @@ -1745,7 +2511,7 @@ PVRSRV_ERROR PVRSRVPurgeHandles(PVRSRV_HANDLE_BASE *psBase) return PVRSRV_ERROR_INVALID_PARAMS; } - PVR_ASSERT((psBase->ui32TotalHandCount % HANDLE_BLOCK_SIZE) == 0) + PVR_ASSERT((psBase->ui32TotalHandCount % HANDLE_BLOCK_SIZE) == 0); for (ui32BlockIndex = INDEX_TO_BLOCK_INDEX(psBase->ui32TotalHandCount); ui32BlockIndex != 0; ui32BlockIndex--) { @@ -1756,12 +2522,14 @@ PVRSRV_ERROR PVRSRVPurgeHandles(PVRSRV_HANDLE_BASE *psBase) } ui32NewHandCount = BLOCK_INDEX_TO_INDEX(ui32BlockIndex); - + /* + * Check for a suitable decrease in the handle count. + */ if (ui32NewHandCount <= (psBase->ui32TotalHandCount/2)) { PVRSRV_ERROR eError; - + // PVR_TRACE((" PVRSRVPurgeHandles: reducing number of handles from %u to %u", psBase->ui32TotalHandCount, ui32NewHandCount)); eError = ReallocHandleArray(psBase, ui32NewHandCount); if (eError != PVRSRV_OK) @@ -1773,6 +2541,20 @@ PVRSRV_ERROR PVRSRVPurgeHandles(PVRSRV_HANDLE_BASE *psBase) return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVAllocHandleBase + + @Description Allocate a handle base structure for a process + + @Input ppsBase - pointer to handle base structure pointer + + @Output ppsBase - points to handle base structure pointer + + @Return Error code or PVRSRV_OK + +******************************************************************************/ PVRSRV_ERROR PVRSRVAllocHandleBase(PVRSRV_HANDLE_BASE **ppsBase) { PVRSRV_HANDLE_BASE *psBase; @@ -1791,7 +2573,7 @@ PVRSRV_ERROR PVRSRVAllocHandleBase(PVRSRV_HANDLE_BASE **ppsBase) } OSMemSet(psBase, 0, sizeof(*psBase)); - + /* Create hash table */ psBase->psHashTab = HASH_Create_Extended(HANDLE_HASH_TAB_INIT_SIZE, sizeof(HAND_KEY), HASH_Func_Default, HASH_Key_Comp_Default); if (psBase->psHashTab == IMG_NULL) { @@ -1809,11 +2591,23 @@ PVRSRV_ERROR PVRSRVAllocHandleBase(PVRSRV_HANDLE_BASE **ppsBase) return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVFreeHandleBase + + @Description Free a handle base structure + + @Input psBase - pointer to handle base structure + + @Return Error code or PVRSRV_OK + +******************************************************************************/ PVRSRV_ERROR PVRSRVFreeHandleBase(PVRSRV_HANDLE_BASE *psBase) { PVRSRV_ERROR eError; - PVR_ASSERT(psBase != gpsKernelHandleBase) + PVR_ASSERT(psBase != gpsKernelHandleBase); eError = FreeHandleBase(psBase); if (eError != PVRSRV_OK) @@ -1824,11 +2618,21 @@ PVRSRV_ERROR PVRSRVFreeHandleBase(PVRSRV_HANDLE_BASE *psBase) return eError; } +/*! +****************************************************************************** + + @Function PVRSRVHandleInit + + @Description Initialise handle management + + @Return Error code or PVRSRV_OK + +******************************************************************************/ PVRSRV_ERROR PVRSRVHandleInit(IMG_VOID) { PVRSRV_ERROR eError; - PVR_ASSERT(gpsKernelHandleBase == IMG_NULL) + PVR_ASSERT(gpsKernelHandleBase == IMG_NULL); eError = PVRSRVAllocHandleBase(&gpsKernelHandleBase); if (eError != PVRSRV_OK) @@ -1850,6 +2654,16 @@ error: return eError; } +/*! +****************************************************************************** + + @Function PVRSRVHandleDeInit + + @Description De-initialise handle management + + @Return Error code or PVRSRV_OK + +******************************************************************************/ PVRSRV_ERROR PVRSRVHandleDeInit(IMG_VOID) { PVRSRV_ERROR eError = PVRSRV_OK; @@ -1870,4 +2684,8 @@ PVRSRV_ERROR PVRSRVHandleDeInit(IMG_VOID) return eError; } #else -#endif +/* disable warning about empty module */ +#endif /* #if defined(PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE) */ +/****************************************************************************** + End of file (handle.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/common/hash.c b/sgx/services4/srvkm/common/hash.c index 78eab44..a3791fa 100644 --- a/sgx/services4/srvkm/common/hash.c +++ b/sgx/services4/srvkm/common/hash.c @@ -1,28 +1,50 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Self scaling hash tables. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +@Description + Implements simple self scaling hash tables. Hash collisions are + handled by chaining entries together. Hash tables are increased in + size when they become more than (50%?) full and decreased in size + when less than (25%?) full. Hash tables are never decreased below + their initial size. +*/ /**************************************************************************/ #include "pvr_debug.h" #include "img_defs.h" @@ -39,43 +61,57 @@ #define KEY_COMPARE(pHash, pKey1, pKey2) \ ((pHash)->pfnKeyComp((pHash)->uKeySize, (pKey1), (pKey2))) +/* Each entry in a hash table is placed into a bucket */ struct _BUCKET_ { - + /* the next bucket on the same chain */ struct _BUCKET_ *pNext; - + /* entry value */ IMG_UINTPTR_T v; - - IMG_UINTPTR_T k[]; + /* entry key */ + IMG_UINTPTR_T k[]; /* PRQA S 0642 */ /* override dynamic array declaration warning */ }; typedef struct _BUCKET_ BUCKET; struct _HASH_TABLE_ { - + /* the hash table array */ BUCKET **ppBucketTable; - + /* current size of the hash table */ IMG_UINT32 uSize; - + /* number of entries currently in the hash table */ IMG_UINT32 uCount; - + /* the minimum size that the hash table should be re-sized to */ IMG_UINT32 uMinimumSize; - + /* size of key in bytes */ IMG_UINT32 uKeySize; - + /* hash function */ HASH_FUNC *pfnHashFunc; - + /* key comparison function */ HASH_KEY_COMP *pfnKeyComp; }; +/*! +****************************************************************************** + @Function HASH_Func_Default + + @Description Hash function intended for hashing keys composed of + IMG_UINTPTR_T arrays. + + @Input uKeySize - the size of the hash key, in bytes. + @Input pKey - a pointer to the key to hash. + @Input uHashTabLen - the length of the hash table. + + @Return the hash value. +******************************************************************************/ IMG_UINT32 HASH_Func_Default (IMG_SIZE_T uKeySize, IMG_VOID *pKey, IMG_UINT32 uHashTabLen) { @@ -107,6 +143,18 @@ HASH_Func_Default (IMG_SIZE_T uKeySize, IMG_VOID *pKey, IMG_UINT32 uHashTabLen) return uHashKey; } +/*! +****************************************************************************** + @Function HASH_Key_Comp_Default + + @Description Compares keys composed of IMG_UINTPTR_T arrays. + + @Input uKeySize - the size of the hash key, in bytes. + @Input pKey1 - pointer to first hash key to compare. + @Input pKey2 - pointer to second hash key to compare. + @Return IMG_TRUE - the keys match. + IMG_FALSE - the keys don't match. +******************************************************************************/ IMG_BOOL HASH_Key_Comp_Default (IMG_SIZE_T uKeySize, IMG_VOID *pKey1, IMG_VOID *pKey2) { @@ -126,6 +174,18 @@ HASH_Key_Comp_Default (IMG_SIZE_T uKeySize, IMG_VOID *pKey1, IMG_VOID *pKey2) return IMG_TRUE; } +/*! +****************************************************************************** + @Function _ChainInsert + + @Description Insert a bucket into the appropriate hash table chain. + + @Input pBucket - the bucket + @Input ppBucketTable - the hash table + @Input uSize - the size of the hash table + + @Return PVRSRV_ERROR +******************************************************************************/ static PVRSRV_ERROR _ChainInsert (HASH_TABLE *pHash, BUCKET *pBucket, BUCKET **ppBucketTable, IMG_UINT32 uSize) { @@ -141,13 +201,27 @@ _ChainInsert (HASH_TABLE *pHash, BUCKET *pBucket, BUCKET **ppBucketTable, IMG_UI return PVRSRV_ERROR_INVALID_PARAMS; } - uIndex = KEY_TO_INDEX(pHash, pBucket->k, uSize); + uIndex = KEY_TO_INDEX(pHash, pBucket->k, uSize); /* PRQA S 0432,0541 */ /* ignore dynamic array warning */ pBucket->pNext = ppBucketTable[uIndex]; ppBucketTable[uIndex] = pBucket; return PVRSRV_OK; } +/*! +****************************************************************************** + @Function _Rehash + + @Description Iterate over every entry in an old hash table and + rehash into the new table. + + @Input ppOldTable - the old hash table + @Input uOldSize - the size of the old hash table + @Input ppNewTable - the new hash table + @Input uNewSize - the size of the new hash table + + @Return None +******************************************************************************/ static PVRSRV_ERROR _Rehash (HASH_TABLE *pHash, BUCKET **ppOldTable, IMG_UINT32 uOldSize, @@ -174,6 +248,20 @@ _Rehash (HASH_TABLE *pHash, return PVRSRV_OK; } +/*! +****************************************************************************** + @Function _Resize + + @Description Attempt to resize a hash table, failure to allocate a + new larger hash table is not considered a hard failure. + We simply continue and allow the table to fill up, the + effect is to allow hash chains to become longer. + + @Input pHash - Hash table to resize. + @Input uNewSize - Required table size. + @Return IMG_TRUE Success + IMG_FALSE Failed +******************************************************************************/ static IMG_BOOL _Resize (HASH_TABLE *pHash, IMG_UINT32 uNewSize) { @@ -202,7 +290,7 @@ _Resize (HASH_TABLE *pHash, IMG_UINT32 uNewSize) } OSFreeMem (PVRSRV_PAGEABLE_SELECT, sizeof(BUCKET *)*pHash->uSize, pHash->ppBucketTable, IMG_NULL); - + /*not nulling pointer, being reassigned just below*/ pHash->ppBucketTable = ppNewTable; pHash->uSize = uNewSize; } @@ -210,6 +298,23 @@ _Resize (HASH_TABLE *pHash, IMG_UINT32 uNewSize) } +/*! +****************************************************************************** + @Function HASH_Create_Extended + + @Description Create a self scaling hash table, using the supplied + key size, and the supplied hash and key comparsion + functions. + + @Input uInitialLen - initial and minimum length of the + hash table, where the length refers to the number + of entries in the hash table, not its size in + bytes. + @Input uKeySize - the size of the key, in bytes. + @Input pfnHashFunc - pointer to hash function. + @Input pfnKeyComp - pointer to key comparsion function. + @Return IMG_NULL or hash table handle. +******************************************************************************/ HASH_TABLE * HASH_Create_Extended (IMG_UINT32 uInitialLen, IMG_SIZE_T uKeySize, HASH_FUNC *pfnHashFunc, HASH_KEY_COMP *pfnKeyComp) { HASH_TABLE *pHash; @@ -240,7 +345,7 @@ HASH_TABLE * HASH_Create_Extended (IMG_UINT32 uInitialLen, IMG_SIZE_T uKeySize, if (pHash->ppBucketTable == IMG_NULL) { OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(HASH_TABLE), pHash, IMG_NULL); - + /*not nulling pointer, out of scope*/ return IMG_NULL; } @@ -249,12 +354,38 @@ HASH_TABLE * HASH_Create_Extended (IMG_UINT32 uInitialLen, IMG_SIZE_T uKeySize, return pHash; } +/*! +****************************************************************************** + @Function HASH_Create + + @Description Create a self scaling hash table with a key + consisting of a single IMG_UINTPTR_T, and using + the default hash and key comparison functions. + + @Input uInitialLen - initial and minimum length of the + hash table, where the length refers to the + number of entries in the hash table, not its size + in bytes. + @Return IMG_NULL or hash table handle. +******************************************************************************/ HASH_TABLE * HASH_Create (IMG_UINT32 uInitialLen) { return HASH_Create_Extended(uInitialLen, sizeof(IMG_UINTPTR_T), &HASH_Func_Default, &HASH_Key_Comp_Default); } +/*! +****************************************************************************** + @Function HASH_Delete + + @Description Delete a hash table created by HASH_Create_Extended or + HASH_Create. All entries in the table must have been + removed before calling this function. + + @Input pHash - hash table + + @Return None +******************************************************************************/ IMG_VOID HASH_Delete (HASH_TABLE *pHash) { @@ -271,10 +402,24 @@ HASH_Delete (HASH_TABLE *pHash) OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(BUCKET *)*pHash->uSize, pHash->ppBucketTable, IMG_NULL); pHash->ppBucketTable = IMG_NULL; OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(HASH_TABLE), pHash, IMG_NULL); - + /*not nulling pointer, copy on stack*/ } } +/*! +****************************************************************************** + @Function HASH_Insert_Extended + + @Description Insert a key value pair into a hash table created + with HASH_Create_Extended. + + @Input pHash - the hash table. + @Input pKey - pointer to the key. + @Input v - the value associated with the key. + + @Return IMG_TRUE - success + IMG_FALSE - failure +******************************************************************************/ IMG_BOOL HASH_Insert_Extended (HASH_TABLE *pHash, IMG_VOID *pKey, IMG_UINTPTR_T v) { @@ -301,7 +446,7 @@ HASH_Insert_Extended (HASH_TABLE *pHash, IMG_VOID *pKey, IMG_UINTPTR_T v) } pBucket->v = v; - + /* PRQA S 0432,0541 1 */ /* ignore warning about dynamic array k (linux)*/ OSMemCopy(pBucket->k, pKey, pHash->uKeySize); if (_ChainInsert (pHash, pBucket, pHash->ppBucketTable, pHash->uSize) != PVRSRV_OK) { @@ -313,11 +458,12 @@ HASH_Insert_Extended (HASH_TABLE *pHash, IMG_VOID *pKey, IMG_UINTPTR_T v) pHash->uCount++; - + /* check if we need to think about re-balencing */ if (pHash->uCount << 1 > pHash->uSize) { - - + /* Ignore the return code from _Resize because the hash table is + still in a valid state and although not ideally sized, it is still + functional */ _Resize (pHash, pHash->uSize << 1); } @@ -325,6 +471,20 @@ HASH_Insert_Extended (HASH_TABLE *pHash, IMG_VOID *pKey, IMG_UINTPTR_T v) return IMG_TRUE; } +/*! +****************************************************************************** + @Function HASH_Insert + + @Description Insert a key value pair into a hash table created with + HASH_Create. + + @Input pHash - the hash table. + @Input k - the key value. + @Input v - the value associated with the key. + + @Return IMG_TRUE - success. + IMG_FALSE - failure. +******************************************************************************/ IMG_BOOL HASH_Insert (HASH_TABLE *pHash, IMG_UINTPTR_T k, IMG_UINTPTR_T v) { @@ -335,6 +495,19 @@ HASH_Insert (HASH_TABLE *pHash, IMG_UINTPTR_T k, IMG_UINTPTR_T v) return HASH_Insert_Extended(pHash, &k, v); } +/*! +****************************************************************************** + @Function HASH_Remove_Extended + + @Description Remove a key from a hash table created with + HASH_Create_Extended. + + @Input pHash - the hash table. + @Input pKey - pointer to key. + + @Return 0 if the key is missing, or the value associated + with the key. +******************************************************************************/ IMG_UINTPTR_T HASH_Remove_Extended(HASH_TABLE *pHash, IMG_VOID *pKey) { @@ -356,7 +529,7 @@ HASH_Remove_Extended(HASH_TABLE *pHash, IMG_VOID *pKey) for (ppBucket = &(pHash->ppBucketTable[uIndex]); *ppBucket != IMG_NULL; ppBucket = &((*ppBucket)->pNext)) { - + /* PRQA S 0432,0541 1 */ /* ignore warning about dynamic array k */ if (KEY_COMPARE(pHash, (*ppBucket)->k, pKey)) { BUCKET *pBucket = *ppBucket; @@ -364,16 +537,17 @@ HASH_Remove_Extended(HASH_TABLE *pHash, IMG_VOID *pKey) (*ppBucket) = pBucket->pNext; OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(BUCKET) + pHash->uKeySize, pBucket, IMG_NULL); - + /*not nulling original pointer, already overwritten*/ pHash->uCount--; - + /* check if we need to think about re-balencing */ if (pHash->uSize > (pHash->uCount << 2) && pHash->uSize > pHash->uMinimumSize) { - - + /* Ignore the return code from _Resize because the + hash table is still in a valid state and although + not ideally sized, it is still functional */ _Resize (pHash, PRIVATE_MAX (pHash->uSize >> 1, pHash->uMinimumSize)); @@ -391,6 +565,19 @@ HASH_Remove_Extended(HASH_TABLE *pHash, IMG_VOID *pKey) return 0; } +/*! +****************************************************************************** + @Function HASH_Remove + + @Description Remove a key value pair from a hash table created + with HASH_Create. + + @Input pHash - the hash table + @Input k - the key + + @Return 0 if the key is missing, or the value associated + with the key. +******************************************************************************/ IMG_UINTPTR_T HASH_Remove (HASH_TABLE *pHash, IMG_UINTPTR_T k) { @@ -400,6 +587,19 @@ HASH_Remove (HASH_TABLE *pHash, IMG_UINTPTR_T k) return HASH_Remove_Extended(pHash, &k); } +/*! +****************************************************************************** + @Function HASH_Retrieve_Extended + + @Description Retrieve a value from a hash table created with + HASH_Create_Extended. + + @Input pHash - the hash table. + @Input pKey - pointer to the key. + + @Return 0 if the key is missing, or the value associated with + the key. +******************************************************************************/ IMG_UINTPTR_T HASH_Retrieve_Extended (HASH_TABLE *pHash, IMG_VOID *pKey) { @@ -421,7 +621,7 @@ HASH_Retrieve_Extended (HASH_TABLE *pHash, IMG_VOID *pKey) for (ppBucket = &(pHash->ppBucketTable[uIndex]); *ppBucket != IMG_NULL; ppBucket = &((*ppBucket)->pNext)) { - + /* PRQA S 0432,0541 1 */ /* ignore warning about dynamic array k */ if (KEY_COMPARE(pHash, (*ppBucket)->k, pKey)) { BUCKET *pBucket = *ppBucket; @@ -439,6 +639,18 @@ HASH_Retrieve_Extended (HASH_TABLE *pHash, IMG_VOID *pKey) return 0; } +/*! +****************************************************************************** + @Function HASH_Retrieve + + @Description Retrieve a value from a hash table created with + HASH_Create. + + @Input pHash - the hash table + @Input k - the key + @Return 0 if the key is missing, or the value associated with + the key. +******************************************************************************/ IMG_UINTPTR_T HASH_Retrieve (HASH_TABLE *pHash, IMG_UINTPTR_T k) { @@ -447,6 +659,17 @@ HASH_Retrieve (HASH_TABLE *pHash, IMG_UINTPTR_T k) return HASH_Retrieve_Extended(pHash, &k); } +/*! +****************************************************************************** + @Function HASH_Iterate + + @Description Iterate over every entry in the hash table + + @Input pHash - the old hash table + @Input pfnCallback - the size of the old hash table + + @Return Callback error if any, otherwise PVRSRV_OK +******************************************************************************/ PVRSRV_ERROR HASH_Iterate(HASH_TABLE *pHash, HASH_pfnCallback pfnCallback) { @@ -462,7 +685,7 @@ HASH_Iterate(HASH_TABLE *pHash, HASH_pfnCallback pfnCallback) eError = pfnCallback((IMG_UINTPTR_T) ((IMG_VOID *) *(pBucket->k)), (IMG_UINTPTR_T) pBucket->v); - + /* The callback might want us to break out early */ if (eError != PVRSRV_OK) return eError; @@ -473,6 +696,17 @@ HASH_Iterate(HASH_TABLE *pHash, HASH_pfnCallback pfnCallback) } #ifdef HASH_TRACE +/*! +****************************************************************************** + @Function HASH_Dump + + @Description To dump the contents of a hash table in human readable + form. + + @Input pHash - the hash table + + @Return None +******************************************************************************/ IMG_VOID HASH_Dump (HASH_TABLE *pHash) { diff --git a/sgx/services4/srvkm/common/lists.c b/sgx/services4/srvkm/common/lists.c index 1081781..038cab1 100644 --- a/sgx/services4/srvkm/common/lists.c +++ b/sgx/services4/srvkm/common/lists.c @@ -1,32 +1,54 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Linked list shared functions implementation +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Implementation of the list iterators for types shared among + more than one file in the services code. +@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 "lists.h" #include "services_headers.h" +/*=================================================================== + LIST ITERATOR FUNCTIONS USED IN MORE THAN ONE FILE (those used just + once are implemented locally). + ===================================================================*/ + IMPLEMENT_LIST_ANY_VA(BM_HEAP) IMPLEMENT_LIST_ANY_2(BM_HEAP, PVRSRV_ERROR, PVRSRV_OK) IMPLEMENT_LIST_ANY_VA_2(BM_HEAP, PVRSRV_ERROR, PVRSRV_OK) @@ -55,6 +77,27 @@ IMPLEMENT_LIST_INSERT(PVRSRV_POWER_DEV) IMPLEMENT_LIST_REMOVE(PVRSRV_POWER_DEV) +/*=================================================================== + BELOW ARE IMPLEMENTED SOME COMMON CALLBACKS USED IN DIFFERENT FILES + ===================================================================*/ + + +/*! +****************************************************************************** + @Function MatchDeviceKM_AnyVaCb + @Description Matchs a device node with an id and optionally a class. + + @Input psDeviceNode - Pointer to the device node. + @Input va - Variable argument list, with te following values: + # ui32DevIndex - Index of de device to match. + # bIgnoreClass - Flag indicating if there's + no need to check the device class. + # eDevClass - Device class, ONLY present if + bIgnoreClass was IMG_FALSE. + + @Return The pointer to the device node if it matchs, IMG_NULL + otherwise. +******************************************************************************/ IMG_VOID* MatchDeviceKM_AnyVaCb(PVRSRV_DEVICE_NODE* psDeviceNode, va_list va) { IMG_UINT32 ui32DevIndex; @@ -69,8 +112,9 @@ IMG_VOID* MatchDeviceKM_AnyVaCb(PVRSRV_DEVICE_NODE* psDeviceNode, va_list va) } else { - - + /*this value will never be used, since the short circuit evaluation + of the first clause will stop because bIgnoreClass is true, but the + compiler complains if it's not initialized.*/ eDevClass = PVRSRV_DEVICE_CLASS_FORCE_I32; } @@ -82,6 +126,20 @@ IMG_VOID* MatchDeviceKM_AnyVaCb(PVRSRV_DEVICE_NODE* psDeviceNode, va_list va) return IMG_NULL; } +/*! +****************************************************************************** + + @Function MatchPowerDeviceIndex_AnyVaCb + + @Description + Matches a power device with its device index. + + @Input va : variable argument list with: + ui32DeviceIndex : device index + + @Return the pointer to the device it matched, IMG_NULL otherwise. + +******************************************************************************/ IMG_VOID* MatchPowerDeviceIndex_AnyVaCb(PVRSRV_POWER_DEV *psPowerDev, va_list va) { IMG_UINT32 ui32DeviceIndex; diff --git a/sgx/services4/srvkm/common/mem.c b/sgx/services4/srvkm/common/mem.c index 5b5d1ac..3f8286b 100644 --- a/sgx/services4/srvkm/common/mem.c +++ b/sgx/services4/srvkm/common/mem.c @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title System memory functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description System memory allocation 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 "services_headers.h" #include "pvr_bridge_km.h" @@ -47,7 +64,7 @@ FreeSharedSysMemCallBack(IMG_PVOID pvParam, sizeof(PVRSRV_KERNEL_MEM_INFO), psKernelMemInfo, IMG_NULL); - + /*not nulling pointer, copy on stack*/ return PVRSRV_OK; } @@ -80,6 +97,9 @@ PVRSRVAllocSharedSysMemoryKM(PVRSRV_PER_PROCESS_DATA *psPerProc, if(OSAllocPages(psKernelMemInfo->ui32Flags, psKernelMemInfo->uAllocSize, (IMG_UINT32)HOST_PAGESIZE(), + IMG_NULL, + 0, + IMG_NULL, &psKernelMemInfo->pvLinAddrKM, &psKernelMemInfo->sMemBlk.hOSMemHandle) != PVRSRV_OK) @@ -92,7 +112,7 @@ PVRSRVAllocSharedSysMemoryKM(PVRSRV_PER_PROCESS_DATA *psPerProc, return PVRSRV_ERROR_OUT_OF_MEMORY; } - + /* register with the resman */ psKernelMemInfo->sMemBlk.hResItem = ResManRegisterRes(psPerProc->hResManContext, RESMAN_TYPE_SHARED_MEM_INFO, @@ -151,3 +171,6 @@ PVRSRVDissociateMemFromResmanKM(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo) return eError; } +/****************************************************************************** + End of file (mem.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/common/mem_debug.c b/sgx/services4/srvkm/common/mem_debug.c index e721fb3..6b49db0 100644 --- a/sgx/services4/srvkm/common/mem_debug.c +++ b/sgx/services4/srvkm/common/mem_debug.c @@ -1,28 +1,46 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Memory debugging routines. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Adds extra memory to the allocations to trace the memory bounds + and other runtime information. +@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. + +*/ /**************************************************************************/ #ifndef MEM_DEBUG_C #define MEM_DEBUG_C @@ -39,13 +57,17 @@ extern "C" #define STOP_ON_ERROR 0 - - - - - - - + /* + Allocated Memory Layout: + + --------- \ + Status [OSMEM_DEBUG_INFO] |- TEST_BUFFER_PADDING_STATUS + --------- < + [0xBB]* [raw bytes] |- ui32Size + --------- < + [0xB2]* [raw bytes] |- TEST_BUFFER_PADDING_AFTER + --------- / + */ IMG_BOOL MemCheck(const IMG_PVOID pvAddr, const IMG_UINT8 ui8Pattern, IMG_SIZE_T uSize) { @@ -60,13 +82,14 @@ extern "C" return IMG_TRUE; } - - + /* + This function expects the pointer to the user data, not the debug data. + */ IMG_VOID OSCheckMemDebug(IMG_PVOID pvCpuVAddr, IMG_SIZE_T uSize, const IMG_CHAR *pszFileName, const IMG_UINT32 uLine) { OSMEM_DEBUG_INFO const *psInfo = (OSMEM_DEBUG_INFO *)((IMG_UINT32)pvCpuVAddr - TEST_BUFFER_PADDING_STATUS); - + /* invalid pointer */ if (pvCpuVAddr == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "Pointer 0x%X : null pointer" @@ -77,7 +100,7 @@ extern "C" while (STOP_ON_ERROR); } - + /* align */ if (((IMG_UINT32)pvCpuVAddr&3) != 0) { PVR_DPF((PVR_DBG_ERROR, "Pointer 0x%X : invalid alignment" @@ -88,7 +111,7 @@ extern "C" while (STOP_ON_ERROR); } - + /*check guard region before*/ if (!MemCheck((IMG_PVOID)psInfo->sGuardRegionBefore, 0xB1, sizeof(psInfo->sGuardRegionBefore))) { PVR_DPF((PVR_DBG_ERROR, "Pointer 0x%X : guard region before overwritten" @@ -99,7 +122,7 @@ extern "C" while (STOP_ON_ERROR); } - + /*check size*/ if (uSize != psInfo->uSize) { PVR_DPF((PVR_DBG_WARNING, "Pointer 0x%X : supplied size was different to stored size (0x%X != 0x%X)" @@ -110,7 +133,7 @@ extern "C" while (STOP_ON_ERROR); } - + /*check size parity*/ if ((0x01234567 ^ psInfo->uSizeParityCheck) != psInfo->uSize) { PVR_DPF((PVR_DBG_WARNING, "Pointer 0x%X : stored size parity error (0x%X != 0x%X)" @@ -122,11 +145,11 @@ extern "C" } else { - + /*the stored size is ok, so we use it instead the supplied uSize*/ uSize = psInfo->uSize; } - + /*check padding after*/ if (uSize) { if (!MemCheck((IMG_VOID*)((IMG_UINT32)pvCpuVAddr + uSize), 0xB2, TEST_BUFFER_PADDING_AFTER)) @@ -139,7 +162,7 @@ extern "C" } } - + /* allocated... */ if (psInfo->eValid != isAllocated) { PVR_DPF((PVR_DBG_ERROR, "Pointer 0x%X : not allocated (freed? %d)" @@ -155,7 +178,7 @@ extern "C" { IMG_SIZE_T i = 0; - for (; i < 128; i++) + for (; i < 128; i++) /*changed to 128 to match the filename array size*/ { *pDest = *pSrc; if (*pSrc == '\0') break; @@ -187,11 +210,10 @@ extern "C" return eError; } - OSMemSet((IMG_CHAR *)(*ppvCpuVAddr) + TEST_BUFFER_PADDING_STATUS, 0xBB, ui32Size); OSMemSet((IMG_CHAR *)(*ppvCpuVAddr) + ui32Size + TEST_BUFFER_PADDING_STATUS, 0xB2, TEST_BUFFER_PADDING_AFTER); - + /*fill the dbg info struct*/ psInfo = (OSMEM_DEBUG_INFO *)(*ppvCpuVAddr); OSMemSet(psInfo->sGuardRegionBefore, 0xB1, sizeof(psInfo->sGuardRegionBefore)); @@ -201,11 +223,12 @@ extern "C" psInfo->uSize = ui32Size; psInfo->uSizeParityCheck = 0x01234567 ^ ui32Size; - + /*point to the user data section*/ *ppvCpuVAddr = (IMG_PVOID) ((IMG_UINT32)*ppvCpuVAddr)+TEST_BUFFER_PADDING_STATUS; #ifdef PVRSRV_LOG_MEMORY_ALLOCS - + /*this is here to simplify the surounding logging macro, that is a expression + maybe the macro should be an expression */ PVR_TRACE(("Allocated pointer (after debug info): 0x%X from %s:%d", *ppvCpuVAddr, pszFilename, ui32Line)); #endif @@ -221,16 +244,16 @@ extern "C" { OSMEM_DEBUG_INFO *psInfo; - + /*check dbginfo (arg pointing to user memory)*/ OSCheckMemDebug(pvCpuVAddr, ui32Size, pszFilename, ui32Line); - - OSMemSet(pvCpuVAddr, 0xBF, ui32Size + TEST_BUFFER_PADDING_AFTER); + /*mark memory as freed*/ + OSMemSet(pvCpuVAddr, 0xBF, ui32Size + TEST_BUFFER_PADDING_AFTER); - + /*point to the starting address of the total allocated memory*/ psInfo = (OSMEM_DEBUG_INFO *)((IMG_UINT32) pvCpuVAddr - TEST_BUFFER_PADDING_STATUS); - + /*update dbg info struct*/ psInfo->uSize = 0; psInfo->uSizeParityCheck = 0; psInfo->eValid = isFree; @@ -245,6 +268,6 @@ extern "C" } #endif -#endif +#endif /* PVRSRV_DEBUG_OS_MEMORY */ -#endif +#endif /* MEM_DEBUG_C */ diff --git a/sgx/services4/srvkm/common/metrics.c b/sgx/services4/srvkm/common/metrics.c index 640eb04..e9f459a 100644 --- a/sgx/services4/srvkm/common/metrics.c +++ b/sgx/services4/srvkm/common/metrics.c @@ -1,36 +1,54 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Time measuring functions. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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 "services_headers.h" #include "metrics.h" +/* VGX: */ #if defined(SUPPORT_VGX) #include "vgxapi_km.h" #endif +/* SGX: */ #if defined(SUPPORT_SGX) #include "sgxapi_km.h" #endif @@ -47,6 +65,13 @@ static volatile IMG_UINT32 *pui32TimerRegister = 0; Temporal_Data asTimers[PVRSRV_NUM_TIMERS]; +/*********************************************************************************** + Function Name : PVRSRVTimeNow + Inputs : None + Outputs : None + Returns : Current timer register value + Description : Returns the current timer register value +************************************************************************************/ IMG_UINT32 PVRSRVTimeNow(IMG_VOID) { if (!pui32TimerRegister) @@ -67,14 +92,21 @@ IMG_UINT32 PVRSRVTimeNow(IMG_VOID) return (0xffffffff-*pui32TimerRegister); -#else +#else /* defined(__sh__) */ return 0; -#endif +#endif /* defined(__sh__) */ } +/*********************************************************************************** + Function Name : PVRSRVGetCPUFreq + Inputs : None + Outputs : None + Returns : CPU timer frequency + Description : Returns the CPU timer frequency +************************************************************************************/ static IMG_UINT32 PVRSRVGetCPUFreq(IMG_VOID) { IMG_UINT32 ui32Time1, ui32Time2; @@ -91,6 +123,13 @@ static IMG_UINT32 PVRSRVGetCPUFreq(IMG_VOID) } +/*********************************************************************************** + Function Name : PVRSRVSetupMetricTimers + Inputs : pvDevInfo + Outputs : None + Returns : None + Description : Resets metric timers and sets up the timer register +************************************************************************************/ IMG_VOID PVRSRVSetupMetricTimers(IMG_VOID *pvDevInfo) { IMG_UINT32 ui32Loop; @@ -106,29 +145,36 @@ IMG_VOID PVRSRVSetupMetricTimers(IMG_VOID *pvDevInfo) #if defined(__sh__) - - - - + /* timer control register */ + // clock / 1024 when TIMER_DIVISOR = 4 + // underflow int disabled + // we get approx 38 uS per timer tick *TCR_2 = TIMER_DIVISOR; - + /* reset the timer counter to 0 */ *TCOR_2 = *TCNT_2 = (IMG_UINT)0xffffffff; - + /* start timer 2 */ *TST_REG |= (IMG_UINT8)0x04; pui32TimerRegister = (IMG_UINT32 *)TCNT_2; - #else + #else /* defined(__sh__) */ pui32TimerRegister = 0; - #endif + #endif /* defined(__sh__) */ } +/*********************************************************************************** + Function Name : PVRSRVOutputMetricTotals + Inputs : None + Outputs : None + Returns : None + Description : Displays final metric data +************************************************************************************/ IMG_VOID PVRSRVOutputMetricTotals(IMG_VOID) { IMG_UINT32 ui32TicksPerMS, ui32Loop; @@ -149,12 +195,18 @@ IMG_VOID PVRSRVOutputMetricTotals(IMG_VOID) } } #if 0 - + /* + ** EXAMPLE TIMER OUTPUT + */ PVR_DPF((PVR_DBG_ERROR," Timer(%u): Total = %u",PVRSRV_TIMER_EXAMPLE_1, PVRSRV_TIMER_TOTAL_IN_TICKS(PVRSRV_TIMER_EXAMPLE_1))); PVR_DPF((PVR_DBG_ERROR," Timer(%u): Time = %ums",PVRSRV_TIMER_EXAMPLE_1, PVRSRV_TIMER_TOTAL_IN_MS(PVRSRV_TIMER_EXAMPLE_1))); PVR_DPF((PVR_DBG_ERROR," Timer(%u): Count = %u",PVRSRV_TIMER_EXAMPLE_1, PVRSRV_TIMER_COUNT(PVRSRV_TIMER_EXAMPLE_1))); #endif } -#endif +#endif /* defined(DEBUG) || defined(TIMING) */ + +/****************************************************************************** + End of file (metrics.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/common/osfunc_common.c b/sgx/services4/srvkm/common/osfunc_common.c index e0a46da..99d4928 100644 --- a/sgx/services4/srvkm/common/osfunc_common.c +++ b/sgx/services4/srvkm/common/osfunc_common.c @@ -1,28 +1,46 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Wrapper layer for osfunc routines that have common code. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Adds extra memory to the allocations to trace the memory bounds + and other runtime information. +@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 "img_types.h" #include "services_headers.h" diff --git a/sgx/services4/srvkm/common/pdump_common.c b/sgx/services4/srvkm/common/pdump_common.c index 4d6c429..bb10f03 100644 --- a/sgx/services4/srvkm/common/pdump_common.c +++ b/sgx/services4/srvkm/common/pdump_common.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Common PDump functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #if defined(PDUMP) #include <stdarg.h> @@ -30,13 +46,16 @@ #include "services_headers.h" #include "perproc.h" +/* pdump headers */ #include "pdump_km.h" #include "pdump_int.h" +/* Allow temporary buffer size override */ #if !defined(PDUMP_TEMP_BUFFER_SIZE) #define PDUMP_TEMP_BUFFER_SIZE (64 * 1024U) #endif +/* DEBUG */ #if 1 #define PDUMP_DBG(a) PDumpOSDebugPrintf (a) #else @@ -53,6 +72,7 @@ static IMG_HANDLE ghTempBufferBlockAlloc; static IMG_UINT16 gui16MMUContextUsage = 0; #if defined(PDUMP_DEBUG_OUTFILES) +/* counter increments each time debug write is called */ IMG_UINT32 g_ui32EveryLineCounter = 1U; #endif @@ -66,7 +86,7 @@ IMG_BOOL _PDumpIsPersistent(IMG_VOID) if(psPerProc == IMG_NULL) { - + /* only occurs early in driver init, and init phase is already persistent */ return IMG_FALSE; } return psPerProc->bPDumpPersistent; @@ -81,13 +101,15 @@ IMG_BOOL _PDumpIsProcessActive(IMG_VOID) PVRSRV_PER_PROCESS_DATA* psPerProc = PVRSRVFindPerProcessData(); if(psPerProc == IMG_NULL) { - + /* FIXME: kernel process logs some comments when kernel module is + * loaded, want to keep those. + */ return IMG_TRUE; } return psPerProc->bPDumpActive; } -#endif +#endif /* SUPPORT_PDUMP_MULTI_PROCESS */ #if defined(PDUMP_DEBUG_OUTFILES) static INLINE @@ -96,16 +118,30 @@ IMG_UINT32 _PDumpGetPID(IMG_VOID) PVRSRV_PER_PROCESS_DATA* psPerProc = PVRSRVFindPerProcessData(); if(psPerProc == IMG_NULL) { - + /* Kernel PID */ return 0; } return psPerProc->ui32PID; } -#endif - +#endif /* PDUMP_DEBUG_OUTFILES */ + +/************************************************************************** + * Function Name : GetTempBuffer + * Inputs : None + * Outputs : None + * Returns : Temporary buffer address, or IMG_NULL + * Description : Get temporary buffer address. +**************************************************************************/ static IMG_VOID *GetTempBuffer(IMG_VOID) { - + /* + * Allocate the temporary buffer, it it hasn't been allocated already. + * Return the address of the temporary buffer, or IMG_NULL if it + * couldn't be allocated. + * It is expected that the buffer will be allocated once, at driver + * load time, and left in place until the driver unloads. + */ + if (gpvTempBuffer == IMG_NULL) { PVRSRV_ERROR eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, @@ -144,19 +180,19 @@ static IMG_VOID FreeTempBuffer(IMG_VOID) IMG_VOID PDumpInitCommon(IMG_VOID) { - + /* Allocate temporary buffer for copying from user space */ (IMG_VOID) GetTempBuffer(); - + /* Call environment specific PDump initialisation */ PDumpInit(); } IMG_VOID PDumpDeInitCommon(IMG_VOID) { - + /* Free temporary buffer */ FreeTempBuffer(); - + /* Call environment specific PDump Deinitialisation */ PDumpDeInit(); } @@ -191,6 +227,13 @@ PVRSRV_ERROR PDumpSetFrameKM(IMG_UINT32 ui32Frame) #endif } +/************************************************************************** + * Function Name : PDumpRegWithFlagsKM + * Inputs : pszPDumpDevName, Register offset, and value to write + * Outputs : None + * Returns : PVRSRV_ERROR + * Description : Create a PDUMP string, which represents a register write +**************************************************************************/ PVRSRV_ERROR PDumpRegWithFlagsKM(IMG_CHAR *pszPDumpRegName, IMG_UINT32 ui32Reg, IMG_UINT32 ui32Data, @@ -211,6 +254,13 @@ PVRSRV_ERROR PDumpRegWithFlagsKM(IMG_CHAR *pszPDumpRegName, return PVRSRV_OK; } +/************************************************************************** + * Function Name : PDumpRegKM + * Inputs : Register offset, and value to write + * Outputs : None + * Returns : PVRSRV_ERROR + * Description : Create a PDUMP string, which represents a register write +**************************************************************************/ PVRSRV_ERROR PDumpRegKM(IMG_CHAR *pszPDumpRegName, IMG_UINT32 ui32Reg, IMG_UINT32 ui32Data) @@ -218,6 +268,18 @@ PVRSRV_ERROR PDumpRegKM(IMG_CHAR *pszPDumpRegName, return PDumpRegWithFlagsKM(pszPDumpRegName, ui32Reg, ui32Data, PDUMP_FLAGS_CONTINUOUS); } +/************************************************************************** + * Function Name : PDumpRegPolWithFlagsKM + * Inputs : Description of what this register read is trying to do + * pszPDumpDevName + * Register offset + * expected value + * mask for that value + * Outputs : None + * Returns : None + * Description : Create a PDUMP string which represents a register read + * with the expected value +**************************************************************************/ PVRSRV_ERROR PDumpRegPolWithFlagsKM(IMG_CHAR *pszPDumpRegName, IMG_UINT32 ui32RegAddr, IMG_UINT32 ui32RegValue, @@ -225,7 +287,7 @@ PVRSRV_ERROR PDumpRegPolWithFlagsKM(IMG_CHAR *pszPDumpRegName, IMG_UINT32 ui32Flags, PDUMP_POLL_OPERATOR eOperator) { - + /* Timings correct for linux and XP */ #define POLL_DELAY 1000U #define POLL_COUNT_LONG (2000000000U / POLL_DELAY) #define POLL_COUNT_SHORT (1000000U / POLL_DELAY) @@ -237,25 +299,11 @@ PVRSRV_ERROR PDumpRegPolWithFlagsKM(IMG_CHAR *pszPDumpRegName, PDUMP_DBG(("PDumpRegPolWithFlagsKM")); if ( _PDumpIsPersistent() ) { - + /* Don't pdump-poll if the process is persistent */ return PVRSRV_OK; } -#if 0 - if (((ui32RegAddr == EUR_CR_EVENT_STATUS) && - (ui32RegValue & ui32Mask & EUR_CR_EVENT_STATUS_TA_FINISHED_MASK) != 0) || - ((ui32RegAddr == EUR_CR_EVENT_STATUS) && - (ui32RegValue & ui32Mask & EUR_CR_EVENT_STATUS_PIXELBE_END_RENDER_MASK) != 0) || - ((ui32RegAddr == EUR_CR_EVENT_STATUS) && - (ui32RegValue & ui32Mask & EUR_CR_EVENT_STATUS_DPM_3D_MEM_FREE_MASK) != 0)) - { - ui32PollCount = POLL_COUNT_LONG; - } - else -#endif - { - ui32PollCount = POLL_COUNT_LONG; - } + ui32PollCount = POLL_COUNT_LONG; eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "POL :%s:0x%08X 0x%08X 0x%08X %d %u %d\r\n", pszPDumpRegName, ui32RegAddr, ui32RegValue, @@ -270,11 +318,38 @@ PVRSRV_ERROR PDumpRegPolWithFlagsKM(IMG_CHAR *pszPDumpRegName, } +/************************************************************************** + * Function Name : PDumpRegPol + * Inputs : Description of what this register read is trying to do + * pszPDumpDevName + Register offset + * expected value + * mask for that value + * Outputs : None + * Returns : None + * Description : Create a PDUMP string which represents a register read + * with the expected value +**************************************************************************/ PVRSRV_ERROR PDumpRegPolKM(IMG_CHAR *pszPDumpRegName, IMG_UINT32 ui32RegAddr, IMG_UINT32 ui32RegValue, IMG_UINT32 ui32Mask, PDUMP_POLL_OPERATOR eOperator) { return PDumpRegPolWithFlagsKM(pszPDumpRegName, ui32RegAddr, ui32RegValue, ui32Mask, PDUMP_FLAGS_CONTINUOUS, eOperator); } +/************************************************************************** + * Function Name : PDumpMallocPages + * Inputs : psDevID, ui32DevVAddr, pvLinAddr, ui32NumBytes, hOSMemHandle + * : hUniqueTag + * Outputs : None + * Returns : None + * Description : Malloc memory pages + +FIXME: This function assumes pvLinAddr is the address of the start of the +block for this hOSMemHandle. +If this isn't true, the call to PDumpOSCPUVAddrToDevPAddr below will be +incorrect. (Consider using OSMemHandleToCPUPAddr() instead?) +The only caller at the moment is in buffer_manager.c, which does the right +thing. +**************************************************************************/ PVRSRV_ERROR PDumpMallocPages (PVRSRV_DEVICE_IDENTIFIER *psDevID, IMG_UINT32 ui32DevVAddr, IMG_CPU_VIRTADDR pvLinAddr, @@ -294,14 +369,14 @@ PVRSRV_ERROR PDumpMallocPages (PVRSRV_DEVICE_IDENTIFIER *psDevID, PDUMP_GET_SCRIPT_STRING(); #if defined(SUPPORT_PDUMP_MULTI_PROCESS) - + /* Always dump physical pages backing a shared allocation */ ui32Flags |= ( _PDumpIsPersistent() || bShared ) ? PDUMP_FLAGS_PERSISTENT : 0; #else PVR_UNREFERENCED_PARAMETER(bShared); ui32Flags |= ( _PDumpIsPersistent() ) ? PDUMP_FLAGS_PERSISTENT : 0; #endif - + /* However, lin addr is only required in non-linux OSes */ #if !defined(LINUX) PVR_ASSERT(((IMG_UINTPTR_T)pvLinAddr & HOST_PAGEMASK) == 0); #endif @@ -309,8 +384,9 @@ PVRSRV_ERROR PDumpMallocPages (PVRSRV_DEVICE_IDENTIFIER *psDevID, PVR_ASSERT(((IMG_UINT32) ui32DevVAddr & HOST_PAGEMASK) == 0); PVR_ASSERT(((IMG_UINT32) ui32NumBytes & HOST_PAGEMASK) == 0); - - + /* + Write a comment to the PDump2 script streams indicating the memory allocation + */ eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "-- MALLOC :%s:VA_%08X 0x%08X %u\r\n", psDevID->pszPDumpDevName, ui32DevVAddr, ui32NumBytes, ui32PageSize); if(eErr != PVRSRV_OK) @@ -319,8 +395,9 @@ PVRSRV_ERROR PDumpMallocPages (PVRSRV_DEVICE_IDENTIFIER *psDevID, } PDumpOSWriteString2(hScript, ui32Flags); - - + /* + Write to the MMU script stream indicating the memory allocation + */ pui8LinAddr = (IMG_PUINT8) pvLinAddr; ui32Offset = 0; ui32NumPages = ui32NumBytes / ui32PageSize; @@ -328,16 +405,11 @@ PVRSRV_ERROR PDumpMallocPages (PVRSRV_DEVICE_IDENTIFIER *psDevID, { ui32NumPages--; - - - - - - - - - - + /* See FIXME in function header. + * Currently: linux pdump uses OSMemHandle and Offset + * other OSes use the LinAddr. + */ + /* Calculate the device physical address for this page */ PDumpOSCPUVAddrToDevPAddr(psDevID->eDeviceType, hOSMemHandle, ui32Offset, @@ -345,7 +417,7 @@ PVRSRV_ERROR PDumpMallocPages (PVRSRV_DEVICE_IDENTIFIER *psDevID, ui32PageSize, &sDevPAddr); ui32Page = (IMG_UINT32)(sDevPAddr.uiAddr / ui32PageSize); - + /* increment kernel virtual address */ pui8LinAddr += ui32PageSize; ui32Offset += ui32PageSize; @@ -366,6 +438,13 @@ PVRSRV_ERROR PDumpMallocPages (PVRSRV_DEVICE_IDENTIFIER *psDevID, } +/************************************************************************** + * Function Name : PDumpMallocPageTable + * Inputs : psDevId, pvLinAddr, ui32NumBytes, hUniqueTag + * Outputs : None + * Returns : None + * Description : Malloc memory page table +**************************************************************************/ PVRSRV_ERROR PDumpMallocPageTable (PVRSRV_DEVICE_IDENTIFIER *psDevId, IMG_HANDLE hOSMemHandle, IMG_UINT32 ui32Offset, @@ -383,8 +462,9 @@ PVRSRV_ERROR PDumpMallocPageTable (PVRSRV_DEVICE_IDENTIFIER *psDevId, ui32Flags |= PDUMP_FLAGS_CONTINUOUS; ui32Flags |= ( _PDumpIsPersistent() ) ? PDUMP_FLAGS_PERSISTENT : 0; - - + /* + Write a comment to the PDump2 script streams indicating the memory allocation + */ eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "-- MALLOC :%s:PAGE_TABLE 0x%08X %u\r\n", @@ -397,15 +477,16 @@ PVRSRV_ERROR PDumpMallocPageTable (PVRSRV_DEVICE_IDENTIFIER *psDevId, } PDumpOSWriteString2(hScript, ui32Flags); - - - - - - + /* + Write to the MMU script stream indicating the memory allocation + */ + // FIXME: we'll never need more than a 4k page for a pagetable + // fixing to 1 page for now. + // note: when the mmu code supports packed pagetables the PTs + // will be as small as 16bytes PDumpOSCPUVAddrToDevPAddr(psDevId->eDeviceType, - hOSMemHandle, + hOSMemHandle, /* um - does this mean the pvLinAddr would be ignored? Is that safe? */ ui32Offset, (IMG_PUINT8) pvLinAddr, ui32PTSize, @@ -415,8 +496,8 @@ PVRSRV_ERROR PDumpMallocPageTable (PVRSRV_DEVICE_IDENTIFIER *psDevId, psDevId->pszPDumpDevName, (IMG_UINT32)(IMG_UINTPTR_T)hUniqueTag, sDevPAddr.uiAddr, - ui32PTSize, - ui32PTSize, + ui32PTSize,//size + ui32PTSize,//alignment sDevPAddr.uiAddr); if(eErr != PVRSRV_OK) { @@ -427,12 +508,21 @@ PVRSRV_ERROR PDumpMallocPageTable (PVRSRV_DEVICE_IDENTIFIER *psDevId, return PVRSRV_OK; } +/************************************************************************** + * Function Name : PDumpFreePages + * Inputs : psBMHeap, sDevVAddr, ui32NumBytes, hUniqueTag, + bInterLeaved + * Outputs : None + * Returns : None + * Description : Free memory pages +**************************************************************************/ PVRSRV_ERROR PDumpFreePages (BM_HEAP *psBMHeap, IMG_DEV_VIRTADDR sDevVAddr, IMG_UINT32 ui32NumBytes, IMG_UINT32 ui32PageSize, IMG_HANDLE hUniqueTag, - IMG_BOOL bInterleaved) + IMG_BOOL bInterleaved, + IMG_BOOL bSparse) { PVRSRV_ERROR eErr; IMG_UINT32 ui32NumPages, ui32PageCounter; @@ -448,8 +538,9 @@ PVRSRV_ERROR PDumpFreePages (BM_HEAP *psBMHeap, psDeviceNode = psBMHeap->pBMContext->psDeviceNode; ui32Flags |= ( _PDumpIsPersistent() ) ? PDUMP_FLAGS_PERSISTENT : 0; - - + /* + Write a comment to the PDUMP2 script streams indicating the memory free + */ eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "-- FREE :%s:VA_%08X\r\n", psDeviceNode->sDevId.pszPDumpDevName, sDevVAddr.uiAddr); if(eErr != PVRSRV_OK) @@ -458,7 +549,9 @@ PVRSRV_ERROR PDumpFreePages (BM_HEAP *psBMHeap, } #if defined(SUPPORT_PDUMP_MULTI_PROCESS) - + /* if we're dumping a shared heap, need to ensure phys allocation + * is freed even if this app isn't the one marked for pdumping + */ { PVRSRV_DEVICE_NODE *psDeviceNode = psBMHeap->pBMContext->psDeviceNode; @@ -470,8 +563,9 @@ PVRSRV_ERROR PDumpFreePages (BM_HEAP *psBMHeap, #endif PDumpOSWriteString2(hScript, ui32Flags); - - + /* + Write to the MMU script stream indicating the memory free + */ ui32NumPages = ui32NumBytes / ui32PageSize; for (ui32PageCounter = 0; ui32PageCounter < ui32NumPages; ui32PageCounter++) { @@ -479,7 +573,13 @@ PVRSRV_ERROR PDumpFreePages (BM_HEAP *psBMHeap, { sDevPAddr = psDeviceNode->pfnMMUGetPhysPageAddr(psBMHeap->pMMUHeap, sDevVAddr); - PVR_ASSERT(sDevPAddr.uiAddr != 0) + /* With sparse mappings we expect spaces */ + if (bSparse && (sDevPAddr.uiAddr == 0)) + { + continue; + } + + PVR_ASSERT(sDevPAddr.uiAddr != 0); eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "FREE :%s:PA_%08X%08X\r\n", psDeviceNode->sDevId.pszPDumpDevName, (IMG_UINT32)(IMG_UINTPTR_T)hUniqueTag, sDevPAddr.uiAddr); @@ -491,7 +591,7 @@ PVRSRV_ERROR PDumpFreePages (BM_HEAP *psBMHeap, } else { - + /* Gap pages in an interleaved allocation should be ignored. */ } sDevVAddr.uiAddr += ui32PageSize; @@ -499,6 +599,13 @@ PVRSRV_ERROR PDumpFreePages (BM_HEAP *psBMHeap, return PVRSRV_OK; } +/************************************************************************** + * Function Name : PDumpFreePageTable + * Inputs : psDevID, pvLinAddr, ui32NumBytes, hUniqueTag + * Outputs : None + * Returns : None + * Description : Free memory page table +**************************************************************************/ PVRSRV_ERROR PDumpFreePageTable (PVRSRV_DEVICE_IDENTIFIER *psDevID, IMG_HANDLE hOSMemHandle, IMG_CPU_VIRTADDR pvLinAddr, @@ -515,11 +622,12 @@ PVRSRV_ERROR PDumpFreePageTable (PVRSRV_DEVICE_IDENTIFIER *psDevID, ui32Flags |= PDUMP_FLAGS_CONTINUOUS; ui32Flags |= ( _PDumpIsPersistent() ) ? PDUMP_FLAGS_PERSISTENT : 0; - - PVR_ASSERT(((IMG_UINTPTR_T)pvLinAddr & (ui32PTSize-1UL)) == 0); - - + /* override QAC warning about wrap around */ + PVR_ASSERT(((IMG_UINTPTR_T)pvLinAddr & (ui32PTSize-1UL)) == 0); /* PRQA S 3382 */ + /* + Write a comment to the PDUMP2 script streams indicating the memory free + */ eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "-- FREE :%s:PAGE_TABLE\r\n", psDevID->pszPDumpDevName); if(eErr != PVRSRV_OK) { @@ -527,15 +635,16 @@ PVRSRV_ERROR PDumpFreePageTable (PVRSRV_DEVICE_IDENTIFIER *psDevID, } PDumpOSWriteString2(hScript, ui32Flags); - - - - - - + /* + Write to the MMU script stream indicating the memory free + */ + // FIXME: we'll never need more than a 4k page for a pagetable + // fixing to 1 page for now. + // note: when the mmu code supports packed pagetables the PTs + // will be as small as 16bytes PDumpOSCPUVAddrToDevPAddr(psDevID->eDeviceType, - hOSMemHandle, + hOSMemHandle, /* um - does this mean the pvLinAddr would be ignored? Is that safe? */ 0, (IMG_PUINT8) pvLinAddr, ui32PTSize, @@ -556,6 +665,18 @@ PVRSRV_ERROR PDumpFreePageTable (PVRSRV_DEVICE_IDENTIFIER *psDevID, return PVRSRV_OK; } +/************************************************************************** + * Function Name : PDumpPDRegWithFlags + * Inputs : psMMUAttrib + * : ui32Reg + * : ui32Data + * : hUniqueTag + * Outputs : None + * Returns : None + * Description : Kernel Services internal pdump memory API + * Used for registers specifying physical addresses + e.g. MMU page directory register +**************************************************************************/ PVRSRV_ERROR PDumpPDRegWithFlags(PDUMP_MMU_ATTRIB *psMMUAttrib, IMG_UINT32 ui32Reg, IMG_UINT32 ui32Data, @@ -575,8 +696,9 @@ PVRSRV_ERROR PDumpPDRegWithFlags(PDUMP_MMU_ATTRIB *psMMUAttrib, pszRegString = psMMUAttrib->sDevId.pszPDumpRegName; } - - + /* + Write to the MMU script stream indicating the physical page directory + */ #if defined(SGX_FEATURE_36BIT_MMU) eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW :%s:$1 :%s:PA_%08X%08X:0x0\r\n", @@ -626,6 +748,18 @@ PVRSRV_ERROR PDumpPDRegWithFlags(PDUMP_MMU_ATTRIB *psMMUAttrib, return PVRSRV_OK; } +/************************************************************************** + * Function Name : PDumpPDReg + * Inputs : psMMUAttrib + : ui32Reg + * : ui32Data + * : hUniqueTag + * Outputs : None + * Returns : PVRSRV_ERROR + * Description : Kernel Services internal pdump memory API + * Used for registers specifying physical addresses + e.g. MMU page directory register +**************************************************************************/ PVRSRV_ERROR PDumpPDReg (PDUMP_MMU_ATTRIB *psMMUAttrib, IMG_UINT32 ui32Reg, IMG_UINT32 ui32Data, @@ -634,6 +768,19 @@ PVRSRV_ERROR PDumpPDReg (PDUMP_MMU_ATTRIB *psMMUAttrib, return PDumpPDRegWithFlags(psMMUAttrib, ui32Reg, ui32Data, PDUMP_FLAGS_CONTINUOUS, hUniqueTag); } +/************************************************************************** + * Function Name : PDumpMemPolKM + * Inputs : psMemInfo + * : ui32Offset + * : ui32Value + * : ui32Mask + * : eOperator + * : ui32Flags + * : hUniqueTag + * Outputs : None + * Returns : PVRSRV_ERROR + * Description : Implements Client pdump memory poll API +**************************************************************************/ PVRSRV_ERROR PDumpMemPolKM(PVRSRV_KERNEL_MEM_INFO *psMemInfo, IMG_UINT32 ui32Offset, IMG_UINT32 ui32Value, @@ -661,17 +808,18 @@ PVRSRV_ERROR PDumpMemPolKM(PVRSRV_KERNEL_MEM_INFO *psMemInfo, if ( _PDumpIsPersistent() ) { - + /* Don't pdump-poll if the process is persistent */ return PVRSRV_OK; } - + /* Check the offset and size don't exceed the bounds of the allocation */ PVR_ASSERT((ui32Offset + sizeof(IMG_UINT32)) <= psMemInfo->uAllocSize); psMMUAttrib = ((BM_BUF*)psMemInfo->sMemBlk.hBuffer)->pMapping->pBMHeap->psMMUAttrib; - - + /* + Write a comment to the PDump2 script streams indicating the virtual memory pol + */ eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "-- POL :%s:VA_%08X 0x%08X 0x%08X %d %d %d\r\n", @@ -691,27 +839,28 @@ PVRSRV_ERROR PDumpMemPolKM(PVRSRV_KERNEL_MEM_INFO *psMemInfo, pui8LinAddr = psMemInfo->pvLinAddrKM; - + /* Advance address by offset */ pui8LinAddr += ui32Offset; - - - + /* + query the buffer manager for the physical pages that back the + virtual address + */ PDumpOSCPUVAddrToPhysPages(psMemInfo->sMemBlk.hOSMemHandle, ui32Offset, pui8LinAddr, psMMUAttrib->ui32DataPageMask, &ui32PageOffset); - + /* calculate the DevV page address */ sDevVPageAddr.uiAddr = psMemInfo->sDevVAddr.uiAddr + ui32Offset - ui32PageOffset; PVR_ASSERT((sDevVPageAddr.uiAddr & psMMUAttrib->ui32DataPageMask) == 0); - + /* get the physical page address based on the device virtual address */ BM_GetPhysPageAddr(psMemInfo, sDevVPageAddr, &sDevPAddr); - + /* convert DevP page address to byte address */ sDevPAddr.uiAddr += ui32PageOffset; eErr = PDumpOSBufprintf(hScript, @@ -735,12 +884,23 @@ PVRSRV_ERROR PDumpMemPolKM(PVRSRV_KERNEL_MEM_INFO *psMemInfo, return PVRSRV_OK; } -PVRSRV_ERROR PDumpMemKM(IMG_PVOID pvAltLinAddr, - PVRSRV_KERNEL_MEM_INFO *psMemInfo, - IMG_UINT32 ui32Offset, - IMG_UINT32 ui32Bytes, - IMG_UINT32 ui32Flags, - IMG_HANDLE hUniqueTag) +/************************************************************************** + * Function Name : _PDumpMemIntKM + * Inputs : psMemInfo + * : ui32Offset + * : ui32Bytes + * : ui32Flags + * : hUniqueTag + * Outputs : None + * Returns : PVRSRV_ERROR + * Description : Implements Client pdump mem API +**************************************************************************/ +static PVRSRV_ERROR _PDumpMemIntKM(IMG_PVOID pvAltLinAddr, + PVRSRV_KERNEL_MEM_INFO *psMemInfo, + IMG_UINT32 ui32Offset, + IMG_UINT32 ui32Bytes, + IMG_UINT32 ui32Flags, + IMG_HANDLE hUniqueTag) { PVRSRV_ERROR eErr; IMG_UINT32 ui32NumPages; @@ -757,7 +917,7 @@ PVRSRV_ERROR PDumpMemKM(IMG_PVOID pvAltLinAddr, PDUMP_GET_SCRIPT_AND_FILE_STRING(); - + /* PRQA S 3415 1 */ /* side effects desired */ if (ui32Bytes == 0 || PDumpOSIsSuspended()) { return PVRSRV_OK; @@ -765,8 +925,9 @@ PVRSRV_ERROR PDumpMemKM(IMG_PVOID pvAltLinAddr, psMMUAttrib = ((BM_BUF*)psMemInfo->sMemBlk.hBuffer)->pMapping->pBMHeap->psMMUAttrib; - - + /* + check the offset and size don't exceed the bounds of the allocation + */ PVR_ASSERT((ui32Offset + ui32Bytes) <= psMemInfo->uAllocSize); if (!PDumpOSJTInitialised()) @@ -775,7 +936,9 @@ PVRSRV_ERROR PDumpMemKM(IMG_PVOID pvAltLinAddr, } #if defined(SUPPORT_PDUMP_MULTI_PROCESS) - + /* if we're dumping a shared heap, need to ensure phys allocation + * is initialised even if this app isn't the one marked for pdumping + */ { BM_HEAP *pHeap = ((BM_BUF*)psMemInfo->sMemBlk.hBuffer)->pMapping->pBMHeap; PVRSRV_DEVICE_NODE *psDeviceNode = pHeap->pBMContext->psDeviceNode; @@ -787,7 +950,7 @@ PVRSRV_ERROR PDumpMemKM(IMG_PVOID pvAltLinAddr, } #endif - + /* setup memory addresses */ if(pvAltLinAddr) { pui8DataLinAddr = pvAltLinAddr; @@ -799,7 +962,7 @@ PVRSRV_ERROR PDumpMemKM(IMG_PVOID pvAltLinAddr, pui8LinAddr = (IMG_UINT8 *)psMemInfo->pvLinAddrKM; sDevVAddr = psMemInfo->sDevVAddr; - + /* advance address by offset */ sDevVAddr.uiAddr += ui32Offset; pui8LinAddr += ui32Offset; @@ -809,8 +972,9 @@ PVRSRV_ERROR PDumpMemKM(IMG_PVOID pvAltLinAddr, ui32ParamOutPos = PDumpOSGetStreamOffset(PDUMP_STREAM_PARAM2); - - + /* + write the binary data up-front. + */ if(!PDumpOSWriteString(PDumpOSGetStream(PDUMP_STREAM_PARAM2), pui8DataLinAddr, ui32Bytes, @@ -832,8 +996,9 @@ PVRSRV_ERROR PDumpMemKM(IMG_PVOID pvAltLinAddr, return eErr; } - - + /* + Write a comment to the PDump2 script streams indicating the virtual memory load + */ eErr = PDumpOSBufprintf(hScript, ui32MaxLenScript, "-- LDB :%s:VA_%08X%08X:0x%08X 0x%08X 0x%08X %s\r\n", @@ -850,9 +1015,10 @@ PVRSRV_ERROR PDumpMemKM(IMG_PVOID pvAltLinAddr, } PDumpOSWriteString2(hScript, ui32Flags); - - - + /* + query the buffer manager for the physical pages that back the + virtual address + */ PDumpOSCPUVAddrToPhysPages(psMemInfo->sMemBlk.hOSMemHandle, ui32Offset, pui8LinAddr, @@ -865,30 +1031,30 @@ PVRSRV_ERROR PDumpMemKM(IMG_PVOID pvAltLinAddr, { ui32NumPages--; - + /* calculate the DevV page address */ sDevVPageAddr.uiAddr = sDevVAddr.uiAddr - ui32PageByteOffset; if (ui32DataPageSize <= PDUMP_TEMP_BUFFER_SIZE) { - + /* if a page fits within temp buffer, we should dump in page-aligned chunks. */ PVR_ASSERT((sDevVPageAddr.uiAddr & psMMUAttrib->ui32DataPageMask) == 0); } - + /* get the physical page address based on the device virtual address */ BM_GetPhysPageAddr(psMemInfo, sDevVPageAddr, &sDevPAddr); - + /* convert DevP page address to byte address */ sDevPAddr.uiAddr += ui32PageByteOffset; - + /* how many bytes to dump from this page */ if (ui32PageByteOffset + ui32Bytes > ui32DataPageSize) { - + /* dump up to the page boundary */ ui32BlockBytes = ui32DataPageSize - ui32PageByteOffset; } else { - + /* dump what's left */ ui32BlockBytes = ui32Bytes; } @@ -908,28 +1074,68 @@ PVRSRV_ERROR PDumpMemKM(IMG_PVOID pvAltLinAddr, } PDumpOSWriteString2(hScript, ui32Flags); - + /* update details for next page */ #if defined(SGX_FEATURE_VARIABLE_MMU_PAGE_SIZE) - + /* page may be larger than pdump temporary buffer */ ui32PageByteOffset = (ui32PageByteOffset + ui32BlockBytes) % ui32DataPageSize; #else - + /* page offset 0 after first page dump */ ui32PageByteOffset = 0; #endif - - ui32Bytes -= ui32BlockBytes; - + /* bytes left over */ + ui32Bytes -= ui32BlockBytes; /* PRQA S 3382 */ /* QAC missed MIN test */ + /* advance devVaddr */ sDevVAddr.uiAddr += ui32BlockBytes; - + /* advance the cpuVaddr */ pui8LinAddr += ui32BlockBytes; - + /* update the file write offset */ ui32ParamOutPos += ui32BlockBytes; } return PVRSRV_OK; } +/************************************************************************** + * Function Name : PDumpMemKM + * Inputs : psMemInfo + * : ui32Offset + * : ui32Bytes + * : ui32Flags + * : hUniqueTag + * Outputs : None + * Returns : PVRSRV_ERROR + * Description : Implements Client pdump mem API +**************************************************************************/ +PVRSRV_ERROR PDumpMemKM(IMG_PVOID pvAltLinAddr, + PVRSRV_KERNEL_MEM_INFO *psMemInfo, + IMG_UINT32 ui32Offset, + IMG_UINT32 ui32Bytes, + IMG_UINT32 ui32Flags, + IMG_HANDLE hUniqueTag) +{ + /* + For now we don't support dumping sparse allocations that + are from within the kernel, or are from UM but without a + alternative linear address + */ + PVR_ASSERT((psMemInfo->ui32Flags & PVRSRV_MEM_SPARSE) == 0); + + if (psMemInfo->ui32Flags & PVRSRV_MEM_SPARSE) + { + return PVRSRV_ERROR_INVALID_PARAMS; + } + else + { + return _PDumpMemIntKM(pvAltLinAddr, + psMemInfo, + ui32Offset, + ui32Bytes, + ui32Flags, + hUniqueTag); + } +} + PVRSRV_ERROR PDumpMemPDEntriesKM(PDUMP_MMU_ATTRIB *psMMUAttrib, IMG_HANDLE hOSMemHandle, IMG_CPU_VIRTADDR pvLinAddr, @@ -941,7 +1147,7 @@ PVRSRV_ERROR PDumpMemPDEntriesKM(PDUMP_MMU_ATTRIB *psMMUAttrib, { PDUMP_MMU_ATTRIB sMMUAttrib; - + /* Override the (variable) PT size since PDs are always 4K in size */ sMMUAttrib = *psMMUAttrib; sMMUAttrib.ui32PTSize = (IMG_UINT32)HOST_PAGESIZE(); return PDumpMemPTEntriesKM( &sMMUAttrib, @@ -954,6 +1160,23 @@ PVRSRV_ERROR PDumpMemPDEntriesKM(PDUMP_MMU_ATTRIB *psMMUAttrib, hUniqueTag2); } +/************************************************************************** + * Function Name : PDumpMemPTEntriesKM + * Inputs : psMMUAttrib - MMU attributes for pdump + * : pvLinAddr - CPU address of PT base + * : ui32Bytes - size + * : ui32Flags - pdump flags + * : bInitialisePages - whether to initialise pages from file + * : hUniqueTag1 - ID for PT physical page + * : hUniqueTag2 - ID for target physical page (if !bInitialisePages) + * Outputs : None + * Returns : PVRSRV_ERROR + * Description : Kernel Services internal pdump memory API + * Used for memory without DevVAddress mappings + e.g. MMU page tables + FIXME: This function doesn't support non-4k data pages, + e.g. dummy data page +**************************************************************************/ PVRSRV_ERROR PDumpMemPTEntriesKM(PDUMP_MMU_ATTRIB *psMMUAttrib, IMG_HANDLE hOSMemHandle, IMG_CPU_VIRTADDR pvLinAddr, @@ -972,7 +1195,7 @@ PVRSRV_ERROR PDumpMemPTEntriesKM(PDUMP_MMU_ATTRIB *psMMUAttrib, IMG_CPU_PHYADDR sCpuPAddr; IMG_UINT32 ui32Offset; IMG_UINT32 ui32ParamOutPos; - IMG_UINT32 ui32PageMask; + IMG_UINT32 ui32PageMask; /* mask for the physical page backing the PT */ PDUMP_GET_SCRIPT_AND_FILE_STRING(); ui32Flags |= ( _PDumpIsPersistent() ) ? PDUMP_FLAGS_PERSISTENT : 0; @@ -998,9 +1221,10 @@ PVRSRV_ERROR PDumpMemPTEntriesKM(PDUMP_MMU_ATTRIB *psMMUAttrib, if (bInitialisePages) { - - - + /* + write the binary data up-front + Use the 'continuous' memory stream + */ if (!PDumpOSWriteString(PDumpOSGetStream(PDUMP_STREAM_PARAM2), pvLinAddr, ui32Bytes, @@ -1023,16 +1247,18 @@ PVRSRV_ERROR PDumpMemPTEntriesKM(PDUMP_MMU_ATTRIB *psMMUAttrib, } } - - - - - + /* + Mask for the physical page address backing the PT + The PT size can be less than 4k with variable page size support + The PD size is always 4k + FIXME: This won't work for dumping the dummy data page + */ ui32PageMask = psMMUAttrib->ui32PTSize - 1; - - - + /* + Write to the MMU script stream indicating the physical page table entries + */ + /* physical pages that back the virtual address */ ui32PageOffset = (IMG_UINT32)((IMG_UINTPTR_T)pvLinAddr & (psMMUAttrib->ui32PTSize - 1)); ui32NumPages = (ui32PageOffset + ui32Bytes + psMMUAttrib->ui32PTSize - 1) / psMMUAttrib->ui32PTSize; pui8LinAddr = (IMG_UINT8*) pvLinAddr; @@ -1040,29 +1266,31 @@ PVRSRV_ERROR PDumpMemPTEntriesKM(PDUMP_MMU_ATTRIB *psMMUAttrib, while (ui32NumPages) { ui32NumPages--; - - - - - - + /* FIXME: if we used OSMemHandleToCPUPAddr() here, we might be + able to lose the lin addr arg. At least one thing that + would need to be done here is to pass in an offset, as the + calling function doesn't necessarily give us the lin addr + of the start of the mem area. Probably best to keep the + lin addr arg for now - but would be nice to remove the + redundancy */ sCpuPAddr = OSMapLinToCPUPhys(hOSMemHandle, pui8LinAddr); sDevPAddr = SysCpuPAddrToDevPAddr(psMMUAttrib->sDevId.eDeviceType, sCpuPAddr); - + /* how many bytes to dump from this page */ if (ui32PageOffset + ui32Bytes > psMMUAttrib->ui32PTSize) { - + /* dump up to the page boundary */ ui32BlockBytes = psMMUAttrib->ui32PTSize - ui32PageOffset; } else { - + /* dump what's left */ ui32BlockBytes = ui32Bytes; } - - + /* + Write a comment to the MMU script stream indicating the page table load + */ if (bInitialisePages) { @@ -1086,11 +1314,11 @@ PVRSRV_ERROR PDumpMemPTEntriesKM(PDUMP_MMU_ATTRIB *psMMUAttrib, { for (ui32Offset = 0; ui32Offset < ui32BlockBytes; ui32Offset += sizeof(IMG_UINT32)) { - IMG_UINT32 ui32PTE = *((IMG_UINT32 *)(IMG_UINTPTR_T)(pui8LinAddr + ui32Offset)); + IMG_UINT32 ui32PTE = *((IMG_UINT32 *)(IMG_UINTPTR_T)(pui8LinAddr + ui32Offset)); /* PRQA S 3305 */ /* strict pointer */ if ((ui32PTE & psMMUAttrib->ui32PDEMask) != 0) { - + /* PT entry points to non-null page */ #if defined(SGX_FEATURE_36BIT_MMU) eErr = PDumpOSBufprintf(hScript, ui32MaxLenScript, @@ -1176,15 +1404,15 @@ PVRSRV_ERROR PDumpMemPTEntriesKM(PDUMP_MMU_ATTRIB *psMMUAttrib, } } - + /* update details for next page */ - + /* page offset 0 after first page dump */ ui32PageOffset = 0; - + /* bytes left over */ ui32Bytes -= ui32BlockBytes; - + /* advance the cpuVaddr */ pui8LinAddr += ui32BlockBytes; - + /* update the file write offset */ ui32ParamOutPos += ui32BlockBytes; } @@ -1205,7 +1433,7 @@ PVRSRV_ERROR PDumpPDDevPAddrKM(PVRSRV_KERNEL_MEM_INFO *psMemInfo, IMG_UINT32 ui32Flags = PDUMP_FLAGS_CONTINUOUS; IMG_UINT32 ui32ParamOutPos; PDUMP_MMU_ATTRIB *psMMUAttrib; - IMG_UINT32 ui32PageMask; + IMG_UINT32 ui32PageMask; /* mask for the physical page backing the PT */ PDUMP_GET_SCRIPT_AND_FILE_STRING(); @@ -1219,7 +1447,7 @@ PVRSRV_ERROR PDumpPDDevPAddrKM(PVRSRV_KERNEL_MEM_INFO *psMemInfo, ui32ParamOutPos = PDumpOSGetStreamOffset(PDUMP_STREAM_PARAM2); - + /* Write the PD phys addr to the param stream up front */ if(!PDumpOSWriteString(PDumpOSGetStream(PDUMP_STREAM_PARAM2), (IMG_UINT8 *)&sPDDevPAddr, sizeof(IMG_DEV_PHYADDR), @@ -1241,7 +1469,9 @@ PVRSRV_ERROR PDumpPDDevPAddrKM(PVRSRV_KERNEL_MEM_INFO *psMemInfo, return eErr; } - + /* Write a comment indicating the PD phys addr write, so that the offsets + * into the param stream increase in correspondence with the number of bytes + * written. */ eErr = PDumpOSBufprintf(hScript, ui32MaxLenScript, "-- LDB :%s:PA_0x%08X%08X:0x%08X 0x%08X 0x%08X %s\r\n", @@ -1258,7 +1488,6 @@ PVRSRV_ERROR PDumpPDDevPAddrKM(PVRSRV_KERNEL_MEM_INFO *psMemInfo, } PDumpOSWriteString2(hScript, ui32Flags); - sDevVAddr = psMemInfo->sDevVAddr; ui32PageByteOffset = sDevVAddr.uiAddr & ui32PageMask; @@ -1368,13 +1597,17 @@ PVRSRV_ERROR PDumpPDDevPAddrKM(PVRSRV_KERNEL_MEM_INFO *psMemInfo, return PVRSRV_OK; } - - - +/************************************************************************** + * Function Name : PDumpCommentKM + * Inputs : pszComment, ui32Flags + * Outputs : None + * Returns : None + * Description : Dumps a comment +**************************************************************************/ PVRSRV_ERROR PDumpCommentKM(IMG_CHAR *pszComment, IMG_UINT32 ui32Flags) { PVRSRV_ERROR eErr; - IMG_CHAR pszCommentPrefix[] = "-- "; + IMG_CHAR pszCommentPrefix[] = "-- "; /* prefix for comments */ #if defined(PDUMP_DEBUG_OUTFILES) IMG_CHAR pszTemp[256]; #endif @@ -1382,17 +1615,19 @@ PVRSRV_ERROR PDumpCommentKM(IMG_CHAR *pszComment, IMG_UINT32 ui32Flags) PDUMP_GET_SCRIPT_STRING(); PDUMP_DBG(("PDumpCommentKM")); #if defined(PDUMP_DEBUG_OUTFILES) - + /* include comments in the "extended" init phase. + * default is to ignore them. + */ ui32Flags |= ( _PDumpIsPersistent() ) ? PDUMP_FLAGS_PERSISTENT : 0; #endif - + /* Put \r \n sequence at the end if it isn't already there */ PDumpOSVerifyLineEnding(pszComment, ui32MaxLen); - + /* Length of string excluding terminating NULL character */ ui32LenCommentPrefix = PDumpOSBuflen(pszCommentPrefix, sizeof(pszCommentPrefix)); - - + /* Ensure output file is available for writing */ + /* FIXME: is this necessary? */ if (!PDumpOSWriteString(PDumpOSGetStream(PDUMP_STREAM_SCRIPT2), (IMG_UINT8*)pszCommentPrefix, ui32LenCommentPrefix, @@ -1425,13 +1660,13 @@ PVRSRV_ERROR PDumpCommentKM(IMG_CHAR *pszComment, IMG_UINT32 ui32Flags) } #if defined(PDUMP_DEBUG_OUTFILES) - + /* Prefix comment with PID and line number */ eErr = PDumpOSSprintf(pszTemp, 256, "%d-%d %s", _PDumpGetPID(), g_ui32EveryLineCounter, pszComment); - + /* Append the comment to the script stream */ eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "%s", pszTemp); #else @@ -1447,14 +1682,22 @@ PVRSRV_ERROR PDumpCommentKM(IMG_CHAR *pszComment, IMG_UINT32 ui32Flags) return PVRSRV_OK; } - +/************************************************************************** + * Function Name : PDumpCommentWithFlags + * Inputs : psPDev - PDev for PDump device + * : pszFormat - format string for comment + * : ... - args for format string + * Outputs : None + * Returns : None + * Description : PDumps a comments +**************************************************************************/ PVRSRV_ERROR PDumpCommentWithFlags(IMG_UINT32 ui32Flags, IMG_CHAR * pszFormat, ...) { PVRSRV_ERROR eErr; PDUMP_va_list ap; PDUMP_GET_MSG_STRING(); - + /* Construct the string */ PDUMP_va_start(ap, pszFormat); eErr = PDumpOSVSprintf(pszMsg, ui32MaxLen, pszFormat, ap); PDUMP_va_end(ap); @@ -1466,13 +1709,22 @@ PVRSRV_ERROR PDumpCommentWithFlags(IMG_UINT32 ui32Flags, IMG_CHAR * pszFormat, . return PDumpCommentKM(pszMsg, ui32Flags); } +/************************************************************************** + * Function Name : PDumpComment + * Inputs : psPDev - PDev for PDump device + * : pszFormat - format string for comment + * : ... - args for format string + * Outputs : None + * Returns : None + * Description : PDumps a comments +**************************************************************************/ PVRSRV_ERROR PDumpComment(IMG_CHAR *pszFormat, ...) { PVRSRV_ERROR eErr; PDUMP_va_list ap; PDUMP_GET_MSG_STRING(); - + /* Construct the string */ PDUMP_va_start(ap, pszFormat); eErr = PDumpOSVSprintf(pszMsg, ui32MaxLen, pszFormat, ap); PDUMP_va_end(ap); @@ -1484,20 +1736,27 @@ PVRSRV_ERROR PDumpComment(IMG_CHAR *pszFormat, ...) return PDumpCommentKM(pszMsg, PDUMP_FLAGS_CONTINUOUS); } +/************************************************************************** + * Function Name : PDumpDriverInfoKM + * Inputs : pszString, ui32Flags + * Outputs : None + * Returns : None + * Description : Dumps a comment +**************************************************************************/ PVRSRV_ERROR PDumpDriverInfoKM(IMG_CHAR *pszString, IMG_UINT32 ui32Flags) { PVRSRV_ERROR eErr; IMG_UINT32 ui32MsgLen; PDUMP_GET_MSG_STRING(); - + /* Construct the string */ eErr = PDumpOSSprintf(pszMsg, ui32MaxLen, "%s", pszString); if(eErr != PVRSRV_OK) { return eErr; } - + /* Put \r \n sequence at the end if it isn't already there */ PDumpOSVerifyLineEnding(pszMsg, ui32MaxLen); ui32MsgLen = PDumpOSBuflen(pszMsg, ui32MaxLen); @@ -1518,6 +1777,30 @@ PVRSRV_ERROR PDumpDriverInfoKM(IMG_CHAR *pszString, IMG_UINT32 ui32Flags) return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PDumpBitmapKM + + @Description + + Dumps a bitmap from device memory to a file + + @Input psDevId + @Input pszFileName + @Input ui32FileOffset + @Input ui32Width + @Input ui32Height + @Input ui32StrideInBytes + @Input sDevBaseAddr + @Input ui32Size + @Input ePixelFormat + @Input eMemFormat + @Input ui32PDumpFlags + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR PDumpBitmapKM( PVRSRV_DEVICE_NODE *psDeviceNode, IMG_CHAR *pszFileName, IMG_UINT32 ui32FileOffset, @@ -1543,7 +1826,7 @@ PVRSRV_ERROR PDumpBitmapKM( PVRSRV_DEVICE_NODE *psDeviceNode, PDumpCommentWithFlags(ui32PDumpFlags, "\r\n-- Dump bitmap of render\r\n"); - + /* find MMU context ID */ ui32MMUContextID = psDeviceNode->pfnMMUGetContextID( hDevMemContext ); eErr = PDumpOSBufprintf(hScript, @@ -1570,6 +1853,25 @@ PVRSRV_ERROR PDumpBitmapKM( PVRSRV_DEVICE_NODE *psDeviceNode, return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PDumpReadRegKM + + @Description + + Dumps a read from a device register to a file + + @Input psConnection : connection info + @Input pszFileName + @Input ui32FileOffset + @Input ui32Address + @Input ui32Size + @Input ui32PDumpFlags + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR PDumpReadRegKM ( IMG_CHAR *pszPDumpRegName, IMG_CHAR *pszFileName, IMG_UINT32 ui32FileOffset, @@ -1599,12 +1901,19 @@ PVRSRV_ERROR PDumpReadRegKM ( IMG_CHAR *pszPDumpRegName, return PVRSRV_OK; } +/***************************************************************************** + @name PDumpTestNextFrame + @brief Tests whether the next frame will be pdumped + @param ui32CurrentFrame + @return bFrameDumped +*****************************************************************************/ IMG_BOOL PDumpTestNextFrame(IMG_UINT32 ui32CurrentFrame) { IMG_BOOL bFrameDumped; - - + /* + Try dumping a string + */ (IMG_VOID) PDumpSetFrameKM(ui32CurrentFrame + 1); bFrameDumped = PDumpIsCaptureFrameKM(); (IMG_VOID) PDumpSetFrameKM(ui32CurrentFrame); @@ -1612,6 +1921,16 @@ IMG_BOOL PDumpTestNextFrame(IMG_UINT32 ui32CurrentFrame) return bFrameDumped; } +/***************************************************************************** + @name PDumpSignatureRegister + @brief Dumps a single signature register + @param psDevId - device ID + @param ui32Address - The register address + @param ui32Size - The amount of data to be dumped in bytes + @param pui32FileOffset - Offset of dump in output file + @param ui32Flags - Flags + @return none +*****************************************************************************/ static PVRSRV_ERROR PDumpSignatureRegister (PVRSRV_DEVICE_IDENTIFIER *psDevId, IMG_CHAR *pszFileName, IMG_UINT32 ui32Address, @@ -1639,6 +1958,18 @@ static PVRSRV_ERROR PDumpSignatureRegister (PVRSRV_DEVICE_IDENTIFIER *psDevId, return PVRSRV_OK; } +/***************************************************************************** + @name PDumpRegisterRange + @brief Dumps a list of signature registers to a file + @param psDevId - device ID + @param pszFileName - target filename for dump + @param pui32Registers - register list + @param ui32NumRegisters - number of regs to dump + @param pui32FileOffset - file offset + @param ui32Size - size of write in bytes + @param ui32Flags - pdump flags + @return none + *****************************************************************************/ static IMG_VOID PDumpRegisterRange(PVRSRV_DEVICE_IDENTIFIER *psDevId, IMG_CHAR *pszFileName, IMG_UINT32 *pui32Registers, @@ -1654,6 +1985,14 @@ static IMG_VOID PDumpRegisterRange(PVRSRV_DEVICE_IDENTIFIER *psDevId, } } +/***************************************************************************** + @name PDump3DSignatureRegisters + @brief Dumps the signature registers for 3D modules... + @param psDevId - device ID info + @param pui32Registers - register list + @param ui32NumRegisters - number of regs to dump + @return Error +*****************************************************************************/ PVRSRV_ERROR PDump3DSignatureRegisters(PVRSRV_DEVICE_IDENTIFIER *psDevId, IMG_UINT32 ui32DumpFrameNum, IMG_BOOL bLastFrame, @@ -1686,6 +2025,17 @@ PVRSRV_ERROR PDump3DSignatureRegisters(PVRSRV_DEVICE_IDENTIFIER *psDevId, return PVRSRV_OK; } +/***************************************************************************** + @name PDumpTASignatureRegisters + @brief Dumps the TA signature registers + @param psDevId - device id info + @param ui32DumpFrameNum - frame number + @param ui32TAKickCount - TA kick counter + @param bLastFrame + @param pui32Registers - register list + @param ui32NumRegisters - number of regs to dump + @return Error +*****************************************************************************/ PVRSRV_ERROR PDumpTASignatureRegisters (PVRSRV_DEVICE_IDENTIFIER *psDevId, IMG_UINT32 ui32DumpFrameNum, IMG_UINT32 ui32TAKickCount, @@ -1718,6 +2068,16 @@ PVRSRV_ERROR PDumpTASignatureRegisters (PVRSRV_DEVICE_IDENTIFIER *psDevId, return PVRSRV_OK; } +/***************************************************************************** + @name PDumpCounterRegisters + @brief Dumps the performance counters + @param psDevId - device id info + @param ui32DumpFrameNum - frame number + @param bLastFrame + @param pui32Registers - register list + @param ui32NumRegisters - number of regs to dump + @return Error +*****************************************************************************/ PVRSRV_ERROR PDumpCounterRegisters (PVRSRV_DEVICE_IDENTIFIER *psDevId, IMG_UINT32 ui32DumpFrameNum, IMG_BOOL bLastFrame, @@ -1750,6 +2110,14 @@ PVRSRV_ERROR PDumpCounterRegisters (PVRSRV_DEVICE_IDENTIFIER *psDevId, return PVRSRV_OK; } +/***************************************************************************** + @name PDumpRegRead + @brief Dump signature register read to script + @param pszPDumpDevName - pdump device name + @param ui32RegOffset - register offset + @param ui32Flags - pdump flags + @return Error +*****************************************************************************/ PVRSRV_ERROR PDumpRegRead(IMG_CHAR *pszPDumpRegName, const IMG_UINT32 ui32RegOffset, IMG_UINT32 ui32Flags) @@ -1768,6 +2136,17 @@ PVRSRV_ERROR PDumpRegRead(IMG_CHAR *pszPDumpRegName, return PVRSRV_OK; } +/***************************************************************************** + @name PDumpSaveMemKM + @brief Save device memory to a file + @param psDevId + @param pszFileName + @param ui32FileOffset + @param sDevBaseAddr + @param ui32Size + @param ui32PDumpFlags + @return Error +*****************************************************************************/ PVRSRV_ERROR PDumpSaveMemKM (PVRSRV_DEVICE_IDENTIFIER *psDevId, IMG_CHAR *pszFileName, IMG_UINT32 ui32FileOffset, @@ -1797,6 +2176,13 @@ PVRSRV_ERROR PDumpSaveMemKM (PVRSRV_DEVICE_IDENTIFIER *psDevId, return PVRSRV_OK; } +/***************************************************************************** + @name PDumpCycleCountRegRead + @brief Dump counter register read to script + @param ui32RegOffset - register offset + @param bLastFrame + @return Error +*****************************************************************************/ PVRSRV_ERROR PDumpCycleCountRegRead(PVRSRV_DEVICE_IDENTIFIER *psDevId, const IMG_UINT32 ui32RegOffset, IMG_BOOL bLastFrame) @@ -1816,6 +2202,18 @@ PVRSRV_ERROR PDumpCycleCountRegRead(PVRSRV_DEVICE_IDENTIFIER *psDevId, } +/*! +****************************************************************************** + + @Function PDumpSignatureBuffer + + @Description + + Dumps a signature registers buffer + + @Return PVRSRV_ERROR + +******************************************************************************/ PVRSRV_ERROR PDumpSignatureBuffer (PVRSRV_DEVICE_IDENTIFIER *psDevId, IMG_CHAR *pszFileName, IMG_CHAR *pszBufferType, @@ -1838,6 +2236,18 @@ PVRSRV_ERROR PDumpSignatureBuffer (PVRSRV_DEVICE_IDENTIFIER *psDevId, } +/*! +****************************************************************************** + + @Function PDumpHWPerfCBKM + + @Description + + Dumps the HW Perf Circular Buffer + + @Return PVRSRV_ERROR + +******************************************************************************/ PVRSRV_ERROR PDumpHWPerfCBKM (PVRSRV_DEVICE_IDENTIFIER *psDevId, IMG_CHAR *pszFileName, IMG_UINT32 ui32FileOffset, @@ -1852,6 +2262,15 @@ PVRSRV_ERROR PDumpHWPerfCBKM (PVRSRV_DEVICE_IDENTIFIER *psDevId, } +/***************************************************************************** + FUNCTION : PDumpCBP + + PURPOSE : Dump CBP command to script + + PARAMETERS : + + RETURNS : None +*****************************************************************************/ PVRSRV_ERROR PDumpCBP(PPVRSRV_KERNEL_MEM_INFO psROffMemInfo, IMG_UINT32 ui32ROffOffset, IMG_UINT32 ui32WPosVal, @@ -1866,41 +2285,42 @@ PVRSRV_ERROR PDumpCBP(PPVRSRV_KERNEL_MEM_INFO psROffMemInfo, IMG_DEV_VIRTADDR sDevVAddr; IMG_DEV_PHYADDR sDevPAddr; IMG_DEV_VIRTADDR sDevVPageAddr; - + //IMG_CPU_PHYADDR CpuPAddr; PDUMP_MMU_ATTRIB *psMMUAttrib; PDUMP_GET_SCRIPT_STRING(); psMMUAttrib = ((BM_BUF*)psROffMemInfo->sMemBlk.hBuffer)->pMapping->pBMHeap->psMMUAttrib; - + /* Check the offset and size don't exceed the bounds of the allocation */ PVR_ASSERT((ui32ROffOffset + sizeof(IMG_UINT32)) <= psROffMemInfo->uAllocSize); pui8LinAddr = psROffMemInfo->pvLinAddrKM; sDevVAddr = psROffMemInfo->sDevVAddr; - + /* Advance addresses by offset */ pui8LinAddr += ui32ROffOffset; sDevVAddr.uiAddr += ui32ROffOffset; - - - + /* + query the buffer manager for the physical pages that back the + virtual address + */ PDumpOSCPUVAddrToPhysPages(psROffMemInfo->sMemBlk.hOSMemHandle, ui32ROffOffset, pui8LinAddr, psMMUAttrib->ui32DataPageMask, &ui32PageOffset); - + /* calculate the DevV page address */ sDevVPageAddr.uiAddr = sDevVAddr.uiAddr - ui32PageOffset; PVR_ASSERT((sDevVPageAddr.uiAddr & 0xFFF) == 0); - + /* get the physical page address based on the device virtual address */ BM_GetPhysPageAddr(psROffMemInfo, sDevVPageAddr, &sDevPAddr); - + /* convert DevP page address to byte address */ sDevPAddr.uiAddr += ui32PageOffset; eErr = PDumpOSBufprintf(hScript, @@ -1922,6 +2342,13 @@ PVRSRV_ERROR PDumpCBP(PPVRSRV_KERNEL_MEM_INFO psROffMemInfo, } +/************************************************************************** + * Function Name : PDumpIDLWithFlags + * Inputs : Idle time in clocks + * Outputs : None + * Returns : Error + * Description : Dump IDL command to script +**************************************************************************/ PVRSRV_ERROR PDumpIDLWithFlags(IMG_UINT32 ui32Clocks, IMG_UINT32 ui32Flags) { PVRSRV_ERROR eErr; @@ -1938,11 +2365,31 @@ PVRSRV_ERROR PDumpIDLWithFlags(IMG_UINT32 ui32Clocks, IMG_UINT32 ui32Flags) } +/************************************************************************** + * Function Name : PDumpIDL + * Inputs : Idle time in clocks + * Outputs : None + * Returns : Error + * Description : Dump IDL command to script +**************************************************************************/ PVRSRV_ERROR PDumpIDL(IMG_UINT32 ui32Clocks) { return PDumpIDLWithFlags(ui32Clocks, PDUMP_FLAGS_CONTINUOUS); } +/************************************************************************** + * Function Name : PDumpMemUM + * Inputs : pvAltLinAddrUM + * : pvLinAddrUM + * : psMemInfo + * : ui32Offset + * : ui32Bytes + * : ui32Flags + * : hUniqueTag + * Outputs : None + * Returns : PVRSRV_ERROR + * Description : Dump user mode memory +**************************************************************************/ PVRSRV_ERROR PDumpMemUM(PVRSRV_PER_PROCESS_DATA *psPerProc, IMG_PVOID pvAltLinAddrUM, IMG_PVOID pvLinAddrUM, @@ -1954,12 +2401,14 @@ PVRSRV_ERROR PDumpMemUM(PVRSRV_PER_PROCESS_DATA *psPerProc, { IMG_VOID *pvAddrUM; IMG_VOID *pvAddrKM; - IMG_UINT32 ui32BytesDumped; - IMG_UINT32 ui32CurrentOffset; + PVRSRV_ERROR eError; if (psMemInfo->pvLinAddrKM != IMG_NULL && pvAltLinAddrUM == IMG_NULL) { - + /* + * There is a kernel virtual address for the memory that is + * being dumped, and no alternate user mode linear address. + */ return PDumpMemKM(IMG_NULL, psMemInfo, ui32Offset, @@ -1972,7 +2421,10 @@ PVRSRV_ERROR PDumpMemUM(PVRSRV_PER_PROCESS_DATA *psPerProc, pvAddrKM = GetTempBuffer(); - + /* + * The memory to be dumped needs to be copied in from + * the client. Dump the memory, a buffer at a time. + */ PVR_ASSERT(pvAddrUM != IMG_NULL && pvAddrKM != IMG_NULL); if (pvAddrUM == IMG_NULL || pvAddrKM == IMG_NULL) { @@ -1985,59 +2437,131 @@ PVRSRV_ERROR PDumpMemUM(PVRSRV_PER_PROCESS_DATA *psPerProc, PDumpCommentWithFlags(ui32Flags, "Dumping 0x%08x bytes of memory, in blocks of 0x%08x bytes", ui32Bytes, (IMG_UINT32)PDUMP_TEMP_BUFFER_SIZE); } - ui32CurrentOffset = ui32Offset; - for (ui32BytesDumped = 0; ui32BytesDumped < ui32Bytes;) + if (psMemInfo->ui32Flags & PVRSRV_MEM_SPARSE) { - PVRSRV_ERROR eError; - IMG_UINT32 ui32BytesToDump = MIN(PDUMP_TEMP_BUFFER_SIZE, ui32Bytes - ui32BytesDumped); + /* + In case of sparse mappings we can't just copy the full range as not + all pages are valid, instead we walk a page at a time only dumping + if the a page exists at that address + */ + IMG_UINT32 ui32BytesRemain = ui32Bytes; + IMG_UINT32 ui32InPageStart = ui32Offset & (~HOST_PAGEMASK); + IMG_UINT32 ui32PageOffset = ui32Offset & (HOST_PAGEMASK); + IMG_UINT32 ui32BytesToCopy = MIN(HOST_PAGESIZE() - ui32InPageStart, ui32BytesRemain); - eError = OSCopyFromUser(psPerProc, - pvAddrKM, - pvAddrUM, - ui32BytesToDump); - if (eError != PVRSRV_OK) + do { - PVR_DPF((PVR_DBG_ERROR, "PDumpMemUM: OSCopyFromUser failed (%d)", eError)); - return eError; - } + if (BM_MapPageAtOffset(BM_MappingHandleFromBuffer(psMemInfo->sMemBlk.hBuffer), ui32PageOffset)) + { + eError = OSCopyFromUser(psPerProc, + pvAddrKM, + pvAddrUM, + ui32BytesToCopy); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "PDumpMemUM: OSCopyFromUser failed (%d)", eError)); + return eError; + } - eError = PDumpMemKM(pvAddrKM, - psMemInfo, - ui32CurrentOffset, - ui32BytesToDump, - ui32Flags, - hUniqueTag); + /* + At this point we know we're dumping a valid page so call + the internal function + */ + eError = _PDumpMemIntKM(pvAddrKM, + psMemInfo, + ui32PageOffset + ui32InPageStart, + ui32BytesToCopy, + ui32Flags, + hUniqueTag); + + if (eError != PVRSRV_OK) + { + /* + * If writing fails part way through, then some + * investigation is needed. + */ + if (ui32BytesToCopy != 0) + { + PVR_DPF((PVR_DBG_ERROR, "PDumpMemUM: PDumpMemKM failed (%d)", eError)); + } + PVR_ASSERT(ui32BytesToCopy == 0); + return eError; + } + } - if (eError != PVRSRV_OK) + VPTR_INC(pvAddrUM, ui32BytesToCopy); + ui32BytesRemain -= ui32BytesToCopy; + ui32InPageStart = 0; + ui32PageOffset += HOST_PAGESIZE(); + } while(ui32BytesRemain); + } + else + { + IMG_UINT32 ui32CurrentOffset = ui32Offset; + IMG_UINT32 ui32BytesDumped; + + for (ui32BytesDumped = 0; ui32BytesDumped < ui32Bytes;) { - - if (ui32BytesDumped != 0) + IMG_UINT32 ui32BytesToDump = MIN(PDUMP_TEMP_BUFFER_SIZE, ui32Bytes - ui32BytesDumped); + + eError = OSCopyFromUser(psPerProc, + pvAddrKM, + pvAddrUM, + ui32BytesToDump); + if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, "PDumpMemUM: PDumpMemKM failed (%d)", eError)); + PVR_DPF((PVR_DBG_ERROR, "PDumpMemUM: OSCopyFromUser failed (%d)", eError)); + return eError; } - PVR_ASSERT(ui32BytesDumped == 0); - return eError; + + eError = PDumpMemKM(pvAddrKM, + psMemInfo, + ui32CurrentOffset, + ui32BytesToDump, + ui32Flags, + hUniqueTag); + + if (eError != PVRSRV_OK) + { + /* + * If writing fails part way through, then some + * investigation is needed. + */ + if (ui32BytesDumped != 0) + { + PVR_DPF((PVR_DBG_ERROR, "PDumpMemUM: PDumpMemKM failed (%d)", eError)); + } + PVR_ASSERT(ui32BytesDumped == 0); + return eError; + } + + VPTR_INC(pvAddrUM, ui32BytesToDump); + ui32CurrentOffset += ui32BytesToDump; + ui32BytesDumped += ui32BytesToDump; } - - VPTR_INC(pvAddrUM, ui32BytesToDump); - ui32CurrentOffset += ui32BytesToDump; - ui32BytesDumped += ui32BytesToDump; } return PVRSRV_OK; } +/************************************************************************** + * Function Name : _PdumpAllocMMUContext + * Inputs : pui32MMUContextID + * Outputs : None + * Returns : PVRSRV_ERROR + * Description : pdump util to allocate MMU contexts +**************************************************************************/ static PVRSRV_ERROR _PdumpAllocMMUContext(IMG_UINT32 *pui32MMUContextID) { IMG_UINT32 i; - + /* there are MAX_PDUMP_MMU_CONTEXTS contexts available, find one */ for(i=0; i<MAX_PDUMP_MMU_CONTEXTS; i++) { if((gui16MMUContextUsage & (1U << i)) == 0) { - + /* mark in use */ gui16MMUContextUsage |= 1U << i; *pui32MMUContextID = i; return PVRSRV_OK; @@ -2050,11 +2574,18 @@ static PVRSRV_ERROR _PdumpAllocMMUContext(IMG_UINT32 *pui32MMUContextID) } +/************************************************************************** + * Function Name : _PdumpFreeMMUContext + * Inputs : ui32MMUContextID + * Outputs : None + * Returns : PVRSRV_ERROR + * Description : pdump util to free MMU contexts +**************************************************************************/ static PVRSRV_ERROR _PdumpFreeMMUContext(IMG_UINT32 ui32MMUContextID) { if(ui32MMUContextID < MAX_PDUMP_MMU_CONTEXTS) { - + /* free the id */ gui16MMUContextUsage &= ~(1U << ui32MMUContextID); return PVRSRV_OK; } @@ -2065,6 +2596,13 @@ static PVRSRV_ERROR _PdumpFreeMMUContext(IMG_UINT32 ui32MMUContextID) } +/************************************************************************** + * Function Name : PDumpSetMMUContext + * Inputs : + * Outputs : None + * Returns : PVRSRV_ERROR + * Description : Set MMU Context +**************************************************************************/ PVRSRV_ERROR PDumpSetMMUContext(PVRSRV_DEVICE_TYPE eDeviceType, IMG_CHAR *pszMemSpace, IMG_UINT32 *pui32MMUContextID, @@ -2087,11 +2625,11 @@ PVRSRV_ERROR PDumpSetMMUContext(PVRSRV_DEVICE_TYPE eDeviceType, return eErr; } - - + /* derive the DevPAddr */ + /* FIXME: if we used OSMemHandleToCPUPAddr() here, we could lose the lin addr arg */ sCpuPAddr = OSMapLinToCPUPhys(hOSMemHandle, pui8LinAddr); sDevPAddr = SysCpuPAddrToDevPAddr(eDeviceType, sCpuPAddr); - + /* and round to 4k page */ sDevPAddr.uiAddr &= ~((PVRSRV_4K_PAGE_SIZE) -1); eErr = PDumpOSBufprintf(hScript, @@ -2109,13 +2647,20 @@ PVRSRV_ERROR PDumpSetMMUContext(PVRSRV_DEVICE_TYPE eDeviceType, } PDumpOSWriteString2(hScript, PDUMP_FLAGS_CONTINUOUS); - + /* return the MMU Context ID */ *pui32MMUContextID = ui32MMUContextID; return PVRSRV_OK; } +/************************************************************************** + * Function Name : PDumpClearMMUContext + * Inputs : + * Outputs : None + * Returns : PVRSRV_ERROR + * Description : Clear MMU Context +**************************************************************************/ PVRSRV_ERROR PDumpClearMMUContext(PVRSRV_DEVICE_TYPE eDeviceType, IMG_CHAR *pszMemSpace, IMG_UINT32 ui32MMUContextID, @@ -2126,7 +2671,9 @@ PVRSRV_ERROR PDumpClearMMUContext(PVRSRV_DEVICE_TYPE eDeviceType, PVR_UNREFERENCED_PARAMETER(eDeviceType); PVR_UNREFERENCED_PARAMETER(ui32MMUType); - + /* FIXME: Propagate error from PDumpComment once it's supported on + * all OSes and platforms + */ PDumpComment("Clear MMU Context for memory space %s\r\n", pszMemSpace); eErr = PDumpOSBufprintf(hScript, ui32MaxLen, @@ -2149,6 +2696,15 @@ PVRSRV_ERROR PDumpClearMMUContext(PVRSRV_DEVICE_TYPE eDeviceType, return PVRSRV_OK; } +/***************************************************************************** + FUNCTION : PDumpStoreMemToFile + + PURPOSE : Dumps a given addr:size to a file + + PARAMETERS : + + RETURNS : +*****************************************************************************/ PVRSRV_ERROR PDumpStoreMemToFile(PDUMP_MMU_ATTRIB *psMMUAttrib, IMG_CHAR *pszFileName, IMG_UINT32 ui32FileOffset, @@ -2164,18 +2720,19 @@ PVRSRV_ERROR PDumpStoreMemToFile(PDUMP_MMU_ATTRIB *psMMUAttrib, PDUMP_GET_SCRIPT_STRING(); - - - + /* + query the buffer manager for the physical pages that back the + virtual address + */ ui32PageOffset = (IMG_UINT32)((IMG_UINTPTR_T)psMemInfo->pvLinAddrKM & psMMUAttrib->ui32DataPageMask); - + /* calculate the DevV page address */ sDevVPageAddr.uiAddr = uiAddr - ui32PageOffset; - + /* get the physical page address based on the device virtual address */ BM_GetPhysPageAddr(psMemInfo, sDevVPageAddr, &sDevPAddr); - + /* convert DevP page address to byte address */ sDevPAddr.uiAddr += ui32PageOffset; PDumpOSBufprintf(hScript, @@ -2194,6 +2751,15 @@ PVRSRV_ERROR PDumpStoreMemToFile(PDUMP_MMU_ATTRIB *psMMUAttrib, return PVRSRV_OK; } +/***************************************************************************** + FUNCTION : PDumpRegBasedCBP + + PURPOSE : Dump CBP command to script + + PARAMETERS : + + RETURNS : None +*****************************************************************************/ PVRSRV_ERROR PDumpRegBasedCBP(IMG_CHAR *pszPDumpRegName, IMG_UINT32 ui32RegOffset, IMG_UINT32 ui32WPosVal, @@ -2217,16 +2783,26 @@ PVRSRV_ERROR PDumpRegBasedCBP(IMG_CHAR *pszPDumpRegName, } - +/**************************************************** + * Non-uitron code here. + * For example, code communicating with dbg driver. + ***************************************************/ +/* PRQA S 5087 1 */ /* include file needed here */ #include "syscommon.h" +/************************************************************************** + * Function Name : PDumpConnectionNotify + * Description : Called by the debugdrv to tell Services that pdump has + * connected + * NOTE: No debugdrv on uitron. + **************************************************************************/ IMG_EXPORT IMG_VOID PDumpConnectionNotify(IMG_VOID) { SYS_DATA *psSysData; PVRSRV_DEVICE_NODE *psThis; PVR_DPF((PVR_DBG_WARNING, "PDump has connected.")); - + /* Loop over all known devices */ SysAcquireData(&psSysData); psThis = psSysData->psDeviceNodeList; @@ -2234,27 +2810,39 @@ IMG_EXPORT IMG_VOID PDumpConnectionNotify(IMG_VOID) { if (psThis->pfnPDumpInitDevice) { - + /* Reset pdump according to connected device */ psThis->pfnPDumpInitDevice(psThis); } psThis = psThis->psNext; } } +/***************************************************************************** + * Function Name : DbgWrite + * Inputs : psStream - debug stream to write to + pui8Data - buffer + ui32BCount - buffer length + ui32Flags - flags, e.g. continuous, LF + * Outputs : None + * Returns : Bytes written + * Description : Write a block of data to a debug stream + * NOTE: No debugdrv on uitron. + *****************************************************************************/ IMG_UINT32 DbgWrite(PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_UINT32 ui32BCount, IMG_UINT32 ui32Flags) { IMG_UINT32 ui32BytesWritten = 0; IMG_UINT32 ui32Off = 0; PDBG_STREAM_CONTROL psCtrl = psStream->psCtrl; - + /* Return immediately if marked as "never" */ if ((ui32Flags & PDUMP_FLAGS_NEVER) != 0) { return ui32BCount; } #if defined(SUPPORT_PDUMP_MULTI_PROCESS) - + /* Return if process is not marked for pdumping, unless it's persistent. + */ if ( (_PDumpIsProcessActive() == IMG_FALSE ) && ((ui32Flags & PDUMP_FLAGS_PERSISTENT) == 0) ) { @@ -2262,14 +2850,18 @@ IMG_UINT32 DbgWrite(PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_UINT32 ui32BC } #endif - + /* Send persistent data first ... + * If we're still initialising the params will be captured to the + * init stream in the call to pfnDBGDrivWrite2 below. + */ if ( ((ui32Flags & PDUMP_FLAGS_PERSISTENT) != 0) && (psCtrl->bInitPhaseComplete) ) { while (ui32BCount > 0) { - - - + /* + Params marked as persistent should be appended to the init phase. + For example window system mem mapping of the primary surface. + */ ui32BytesWritten = PDumpOSDebugDriverWrite( psStream, PDUMP_WRITE_MODE_PERSISTENT, &pui8Data[ui32Off], ui32BCount, 1, 0); @@ -2289,14 +2881,14 @@ IMG_UINT32 DbgWrite(PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_UINT32 ui32BC PVR_DPF((PVR_DBG_ERROR, "DbgWrite: Failed to send persistent data")); if( (psCtrl->ui32Flags & DEBUG_FLAGS_READONLY) != 0) { - + /* suspend pdump to prevent flooding kernel log buffer */ PDumpSuspendKM(); } return 0xFFFFFFFFU; } } - + /* reset buffer counters */ ui32BCount = ui32Off; ui32Off = 0; ui32BytesWritten = 0; } @@ -2304,8 +2896,9 @@ IMG_UINT32 DbgWrite(PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_UINT32 ui32BC { if ((ui32Flags & PDUMP_FLAGS_CONTINUOUS) != 0) { - - + /* + If pdump client (or its equivalent) isn't running then throw continuous data away. + */ if (((psCtrl->ui32CapMode & DEBUG_CAPMODE_FRAMED) != 0) && (psCtrl->ui32Start == 0xFFFFFFFFU) && (psCtrl->ui32End == 0xFFFFFFFFU) && @@ -2344,9 +2937,10 @@ IMG_UINT32 DbgWrite(PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_UINT32 ui32BC } } - - - + /* + If the debug driver's buffers are full so no data could be written then yield + execution so pdump can run and empty them. + */ if (ui32BytesWritten == 0) { PDumpOSReleaseExecution(); @@ -2358,15 +2952,17 @@ IMG_UINT32 DbgWrite(PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_UINT32 ui32BC ui32BCount -= ui32BytesWritten; } - + /* loop exits when i) all data is written, or ii) an unrecoverable error occurs */ } - - return ui32BytesWritten; } -#else -#endif +#else /* defined(PDUMP) */ +/* disable warning about empty module */ +#endif /* defined(PDUMP) */ +/***************************************************************************** + End of file (pdump_common.c) +*****************************************************************************/ diff --git a/sgx/services4/srvkm/common/perproc.c b/sgx/services4/srvkm/common/perproc.c index eb73166..f228828 100644 --- a/sgx/services4/srvkm/common/perproc.c +++ b/sgx/services4/srvkm/common/perproc.c @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Per-process storage +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Manage per-process storage +@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 "services_headers.h" #include "resman.h" @@ -37,6 +54,18 @@ static HASH_TABLE *psHashTab = IMG_NULL; +/*! +****************************************************************************** + + @Function FreePerProcData + + @Description Free a per-process data area + + @Input psPerProc - pointer to per-process data area + + @Return Error code, or PVRSRV_OK + +******************************************************************************/ static PVRSRV_ERROR FreePerProcessData(PVRSRV_PER_PROCESS_DATA *psPerProc) { PVRSRV_ERROR eError; @@ -54,7 +83,10 @@ static PVRSRV_ERROR FreePerProcessData(PVRSRV_PER_PROCESS_DATA *psPerProc) if (uiPerProc == 0) { PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't find process in per-process data hash table")); - + /* + * We must have failed early in the per-process data area + * creation, before the process ID was set. + */ PVR_ASSERT(psPerProc->ui32PID == 0); } else @@ -63,7 +95,7 @@ static PVRSRV_ERROR FreePerProcessData(PVRSRV_PER_PROCESS_DATA *psPerProc) PVR_ASSERT(((PVRSRV_PER_PROCESS_DATA *)uiPerProc)->ui32PID == psPerProc->ui32PID); } - + /* Free handle base for this process */ if (psPerProc->psHandleBase != IMG_NULL) { eError = PVRSRVFreeHandleBase(psPerProc->psHandleBase); @@ -74,7 +106,7 @@ static PVRSRV_ERROR FreePerProcessData(PVRSRV_PER_PROCESS_DATA *psPerProc) } } - + /* Release handle for per-process data area */ if (psPerProc->hPerProcData != IMG_NULL) { eError = PVRSRVReleaseHandle(KERNEL_HANDLE_BASE, psPerProc->hPerProcData, PVRSRV_HANDLE_TYPE_PERPROC_DATA); @@ -86,7 +118,7 @@ static PVRSRV_ERROR FreePerProcessData(PVRSRV_PER_PROCESS_DATA *psPerProc) } } - + /* Call environment specific per process deinit function */ eError = OSPerProcessPrivateDataDeInit(psPerProc->hOsPrivateData); if (eError != PVRSRV_OK) { @@ -98,7 +130,7 @@ static PVRSRV_ERROR FreePerProcessData(PVRSRV_PER_PROCESS_DATA *psPerProc) sizeof(*psPerProc), psPerProc, psPerProc->hBlockAlloc); - + /*not nulling pointer, copy on stack*/ if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "FreePerProcessData: Couldn't free per-process data (%d)", eError)); @@ -109,18 +141,44 @@ static PVRSRV_ERROR FreePerProcessData(PVRSRV_PER_PROCESS_DATA *psPerProc) } +/*! +****************************************************************************** + + @Function PVRSRVPerProcessData + + @Description Return per-process data area + + @Input ui32PID - process ID + + @Return Pointer to per-process data area, or IMG_NULL on error. + +******************************************************************************/ PVRSRV_PER_PROCESS_DATA *PVRSRVPerProcessData(IMG_UINT32 ui32PID) { PVRSRV_PER_PROCESS_DATA *psPerProc; PVR_ASSERT(psHashTab != IMG_NULL); - + /* Look for existing per-process data area */ psPerProc = (PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab, (IMG_UINTPTR_T)ui32PID); return psPerProc; } +/*! +****************************************************************************** + + @Function PVRSRVPerProcessDataConnect + + @Description Allocate per-process data area, or increment refcount if one + already exists for this PID. + + @Input ui32PID - process ID + ppsPerProc - Pointer to per-process data area + + @Return PVRSRV_ERROR + +******************************************************************************/ PVRSRV_ERROR PVRSRVPerProcessDataConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flags) { PVRSRV_PER_PROCESS_DATA *psPerProc; @@ -132,12 +190,12 @@ PVRSRV_ERROR PVRSRVPerProcessDataConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flag return PVRSRV_ERROR_INIT_FAILURE; } - + /* Look for existing per-process data area */ psPerProc = (PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab, (IMG_UINTPTR_T)ui32PID); if (psPerProc == IMG_NULL) { - + /* Allocate per-process data area */ eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(*psPerProc), (IMG_PVOID *)&psPerProc, @@ -170,7 +228,7 @@ PVRSRV_ERROR PVRSRVPerProcessDataConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flag PVR_UNREFERENCED_PARAMETER(ui32Flags); #endif - + /* Call environment specific per process init function */ eError = OSPerProcessPrivateDataInit(&psPerProc->hOsPrivateData); if (eError != PVRSRV_OK) { @@ -178,7 +236,7 @@ PVRSRV_ERROR PVRSRVPerProcessDataConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flag goto failure; } - + /* Allocate a handle for the per-process data area */ eError = PVRSRVAllocHandle(KERNEL_HANDLE_BASE, &psPerProc->hPerProcData, psPerProc, @@ -190,7 +248,7 @@ PVRSRV_ERROR PVRSRVPerProcessDataConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flag goto failure; } - + /* Allocate handle base for this process */ eError = PVRSRVAllocHandleBase(&psPerProc->psHandleBase); if (eError != PVRSRV_OK) { @@ -198,7 +256,7 @@ PVRSRV_ERROR PVRSRVPerProcessDataConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flag goto failure; } - + /* Set per-process handle options */ eError = OSPerProcessSetHandleOptions(psPerProc->psHandleBase); if (eError != PVRSRV_OK) { @@ -206,7 +264,7 @@ PVRSRV_ERROR PVRSRVPerProcessDataConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flag goto failure; } - + /* Create a resource manager context for the process */ eError = PVRSRVResManConnect(psPerProc, &psPerProc->hResManContext); if (eError != PVRSRV_OK) { @@ -231,6 +289,19 @@ failure: } +/*! +****************************************************************************** + + @Function PVRSRVPerProcessDataDisconnect + + @Description Decrement refcount for per-process data area, + and free the resources if necessary. + + @Input ui32PID - process ID + + @Return IMG_VOID + +******************************************************************************/ IMG_VOID PVRSRVPerProcessDataDisconnect(IMG_UINT32 ui32PID) { PVRSRV_ERROR eError; @@ -255,10 +326,10 @@ IMG_VOID PVRSRVPerProcessDataDisconnect(IMG_UINT32 ui32PID) PVRSRVTimeTraceBufferDestroy(ui32PID); #endif - + /* Close the Resource Manager connection */ PVRSRVResManDisconnect(psPerProc->hResManContext, IMG_FALSE); - + /* Free the per-process data */ eError = FreePerProcessData(psPerProc); if (eError != PVRSRV_OK) { @@ -275,11 +346,21 @@ IMG_VOID PVRSRVPerProcessDataDisconnect(IMG_UINT32 ui32PID) } +/*! +****************************************************************************** + + @Function PVRSRVPerProcessDataInit + + @Description Initialise per-process data management + + @Return Error code, or PVRSRV_OK + +******************************************************************************/ PVRSRV_ERROR PVRSRVPerProcessDataInit(IMG_VOID) { PVR_ASSERT(psHashTab == IMG_NULL); - + /* Create hash table */ psHashTab = HASH_Create(HASH_TAB_INIT_SIZE); if (psHashTab == IMG_NULL) { @@ -290,12 +371,22 @@ PVRSRV_ERROR PVRSRVPerProcessDataInit(IMG_VOID) return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVPerProcessDataDeInit + + @Description De-initialise per-process data management + + @Return Error code, or PVRSRV_OK + +******************************************************************************/ PVRSRV_ERROR PVRSRVPerProcessDataDeInit(IMG_VOID) { - + /* Destroy per-process data area hash table */ if (psHashTab != IMG_NULL) { - + /* Free the hash table */ HASH_Delete(psHashTab); psHashTab = IMG_NULL; } @@ -303,3 +394,6 @@ PVRSRV_ERROR PVRSRVPerProcessDataDeInit(IMG_VOID) return PVRSRV_OK; } +/****************************************************************************** + End of file (perproc.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/common/power.c b/sgx/services4/srvkm/common/power.c index 21d7ad4..93661ed 100644 --- a/sgx/services4/srvkm/common/power.c +++ b/sgx/services4/srvkm/common/power.c @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Power management functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Main APIs for power management functions +@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 "services_headers.h" #include "pdump_km.h" @@ -33,6 +50,19 @@ static IMG_BOOL gbInitServerRunning = IMG_FALSE; static IMG_BOOL gbInitServerRan = IMG_FALSE; static IMG_BOOL gbInitSuccessful = IMG_FALSE; +/*! +****************************************************************************** + + @Function PVRSRVSetInitServerState + + @Description Sets given services init state. + + @Input eInitServerState : a services init state + @Input bState : a state to set + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVSetInitServerState(PVRSRV_INIT_SERVER_STATE eInitServerState, IMG_BOOL bState) { @@ -57,6 +87,18 @@ PVRSRV_ERROR PVRSRVSetInitServerState(PVRSRV_INIT_SERVER_STATE eInitServerState, return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVGetInitServerState + + @Description Tests whether a given services init state was run. + + @Input eInitServerState : a services init state + + @Return IMG_BOOL + +******************************************************************************/ IMG_EXPORT IMG_BOOL PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_STATE eInitServerState) { @@ -82,12 +124,38 @@ IMG_BOOL PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_STATE eInitServerState) return bReturnVal; } +/*! +****************************************************************************** + + @Function _IsSystemStatePowered + + @Description Tests whether a given system state represents powered-up. + + @Input eSystemPowerState : a system power state + + @Return IMG_BOOL + +******************************************************************************/ static IMG_BOOL _IsSystemStatePowered(PVRSRV_SYS_POWER_STATE eSystemPowerState) { return (IMG_BOOL)(eSystemPowerState < PVRSRV_SYS_POWER_STATE_D2); } +/*! +****************************************************************************** + + @Function PVRSRVPowerLock + + @Description Obtain the mutex for power transitions + + @Input ui32CallerID : KERNEL_ID or ISR_ID + @Input bSystemPowerEvent : Only pass IMG_TRUE if the lock is for a + system power state change + + @Return PVRSRV_ERROR IMG_CALLCONV + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVPowerLock(IMG_UINT32 ui32CallerID, IMG_BOOL bSystemPowerEvent) @@ -115,8 +183,9 @@ PVRSRV_ERROR PVRSRVPowerLock(IMG_UINT32 ui32CallerID, } else if (bTryLock) { - - + /* + ISR failed to acquire lock so it must be held by a kernel thread. + */ eError = PVRSRV_ERROR_RETRY; break; } @@ -130,12 +199,12 @@ PVRSRV_ERROR PVRSRVPowerLock(IMG_UINT32 ui32CallerID, OSPowerLockUnwrap(); } - + /* PRQA S 3415 3 */ /* side effects desired */ if ((eError == PVRSRV_OK) && !bSystemPowerEvent && !_IsSystemStatePowered(psSysData->eCurrentPowerState)) { - + /* Reject device power state change due to system power state. */ PVRSRVPowerUnlock(ui32CallerID); eError = PVRSRV_ERROR_RETRY; } @@ -144,6 +213,18 @@ PVRSRV_ERROR PVRSRVPowerLock(IMG_UINT32 ui32CallerID, } +/*! +****************************************************************************** + + @Function PVRSRVPowerUnlock + + @Description Release the mutex for power transitions + + @Input ui32CallerID : KERNEL_ID or ISR_ID + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT IMG_VOID PVRSRVPowerUnlock(IMG_UINT32 ui32CallerID) { @@ -152,17 +233,36 @@ IMG_VOID PVRSRVPowerUnlock(IMG_UINT32 ui32CallerID) } +/*! +****************************************************************************** + + @Function PVRSRVDevicePrePowerStateKM_AnyVaCb + + @Description + + Perform device-specific processing required before a power transition + + @Input psPowerDevice : the device + @Input va : variable argument list with: + bAllDevices : IMG_TRUE - All devices + IMG_FALSE - Use ui32DeviceIndex + ui32DeviceIndex : device index + eNewPowerState : New power state + + @Return PVRSRV_ERROR + +******************************************************************************/ static PVRSRV_ERROR PVRSRVDevicePrePowerStateKM_AnyVaCb(PVRSRV_POWER_DEV *psPowerDevice, va_list va) { PVRSRV_DEV_POWER_STATE eNewDevicePowerState; PVRSRV_ERROR eError; - + /*Variable Argument variables*/ IMG_BOOL bAllDevices; IMG_UINT32 ui32DeviceIndex; PVRSRV_DEV_POWER_STATE eNewPowerState; - + /* WARNING: if types were not aligned to 4 bytes, this could be dangerous. */ bAllDevices = va_arg(va, IMG_BOOL); ui32DeviceIndex = va_arg(va, IMG_UINT32); eNewPowerState = va_arg(va, PVRSRV_DEV_POWER_STATE); @@ -176,7 +276,7 @@ static PVRSRV_ERROR PVRSRVDevicePrePowerStateKM_AnyVaCb(PVRSRV_POWER_DEV *psPowe { if (psPowerDevice->pfnPrePower != IMG_NULL) { - + /* Call the device's power callback. */ eError = psPowerDevice->pfnPrePower(psPowerDevice->hDevCookie, eNewDevicePowerState, psPowerDevice->eCurrentPowerState); @@ -186,7 +286,7 @@ static PVRSRV_ERROR PVRSRVDevicePrePowerStateKM_AnyVaCb(PVRSRV_POWER_DEV *psPowe } } - + /* Do any required system-layer processing. */ eError = SysDevicePrePowerState(psPowerDevice->ui32DeviceIndex, eNewDevicePowerState, psPowerDevice->eCurrentPowerState); @@ -200,6 +300,23 @@ static PVRSRV_ERROR PVRSRVDevicePrePowerStateKM_AnyVaCb(PVRSRV_POWER_DEV *psPowe return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVDevicePrePowerStateKM + + @Description + + Perform device-specific processing required before a power transition + + @Input bAllDevices : IMG_TRUE - All devices + IMG_FALSE - Use ui32DeviceIndex + @Input ui32DeviceIndex : device index + @Input eNewPowerState : New power state + + @Return PVRSRV_ERROR + +******************************************************************************/ static PVRSRV_ERROR PVRSRVDevicePrePowerStateKM(IMG_BOOL bAllDevices, IMG_UINT32 ui32DeviceIndex, @@ -210,7 +327,7 @@ PVRSRV_ERROR PVRSRVDevicePrePowerStateKM(IMG_BOOL bAllDevices, SysAcquireData(&psSysData); - + /* Loop through the power devices. */ eError = List_PVRSRV_POWER_DEV_PVRSRV_ERROR_Any_va(psSysData->psPowerDeviceList, &PVRSRVDevicePrePowerStateKM_AnyVaCb, bAllDevices, @@ -220,17 +337,36 @@ PVRSRV_ERROR PVRSRVDevicePrePowerStateKM(IMG_BOOL bAllDevices, return eError; } +/*! +****************************************************************************** + + @Function PVRSRVDevicePostPowerStateKM_AnyVaCb + + @Description + + Perform device-specific processing required after a power transition + + @Input psPowerDevice : the device + @Input va : variable argument list with: + bAllDevices : IMG_TRUE - All devices + IMG_FALSE - Use ui32DeviceIndex + ui32DeviceIndex : device index + eNewPowerState : New power state + + @Return PVRSRV_ERROR + +******************************************************************************/ static PVRSRV_ERROR PVRSRVDevicePostPowerStateKM_AnyVaCb(PVRSRV_POWER_DEV *psPowerDevice, va_list va) { PVRSRV_DEV_POWER_STATE eNewDevicePowerState; PVRSRV_ERROR eError; - + /*Variable Argument variables*/ IMG_BOOL bAllDevices; IMG_UINT32 ui32DeviceIndex; PVRSRV_DEV_POWER_STATE eNewPowerState; - + /* WARNING: if types were not aligned to 4 bytes, this could be dangerous. */ bAllDevices = va_arg(va, IMG_BOOL); ui32DeviceIndex = va_arg(va, IMG_UINT32); eNewPowerState = va_arg(va, PVRSRV_DEV_POWER_STATE); @@ -242,7 +378,7 @@ static PVRSRV_ERROR PVRSRVDevicePostPowerStateKM_AnyVaCb(PVRSRV_POWER_DEV *psPow if (psPowerDevice->eCurrentPowerState != eNewDevicePowerState) { - + /* Do any required system-layer processing. */ eError = SysDevicePostPowerState(psPowerDevice->ui32DeviceIndex, eNewDevicePowerState, psPowerDevice->eCurrentPowerState); @@ -253,7 +389,7 @@ static PVRSRV_ERROR PVRSRVDevicePostPowerStateKM_AnyVaCb(PVRSRV_POWER_DEV *psPow if (psPowerDevice->pfnPostPower != IMG_NULL) { - + /* Call the device's power callback. */ eError = psPowerDevice->pfnPostPower(psPowerDevice->hDevCookie, eNewDevicePowerState, psPowerDevice->eCurrentPowerState); @@ -269,6 +405,23 @@ static PVRSRV_ERROR PVRSRVDevicePostPowerStateKM_AnyVaCb(PVRSRV_POWER_DEV *psPow return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVDevicePostPowerStateKM + + @Description + + Perform device-specific processing required after a power transition + + @Input bAllDevices : IMG_TRUE - All devices + IMG_FALSE - Use ui32DeviceIndex + @Input ui32DeviceIndex : device index + @Input eNewPowerState : New power state + + @Return PVRSRV_ERROR + +******************************************************************************/ static PVRSRV_ERROR PVRSRVDevicePostPowerStateKM(IMG_BOOL bAllDevices, IMG_UINT32 ui32DeviceIndex, @@ -279,7 +432,7 @@ PVRSRV_ERROR PVRSRVDevicePostPowerStateKM(IMG_BOOL bAllDevices, SysAcquireData(&psSysData); - + /* Loop through the power devices. */ eError = List_PVRSRV_POWER_DEV_PVRSRV_ERROR_Any_va(psSysData->psPowerDeviceList, &PVRSRVDevicePostPowerStateKM_AnyVaCb, bAllDevices, @@ -290,30 +443,38 @@ PVRSRV_ERROR PVRSRVDevicePostPowerStateKM(IMG_BOOL bAllDevices, } +/*! +****************************************************************************** + + @Function PVRSRVSetDevicePowerStateKM + + @Description Set the Device into a new state + + @Input ui32DeviceIndex : device index + @Input eNewPowerState : New power state + @Input ui32CallerID : KERNEL_ID or ISR_ID + @Input bRetainMutex : If true, the power mutex is retained on exit + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVSetDevicePowerStateKM(IMG_UINT32 ui32DeviceIndex, - PVRSRV_DEV_POWER_STATE eNewPowerState, - IMG_UINT32 ui32CallerID, - IMG_BOOL bRetainMutex) + PVRSRV_DEV_POWER_STATE eNewPowerState) { PVRSRV_ERROR eError; SYS_DATA *psSysData; SysAcquireData(&psSysData); - eError = PVRSRVPowerLock(ui32CallerID, IMG_FALSE); - if(eError != PVRSRV_OK) - { - return eError; - } - #if defined(PDUMP) if (eNewPowerState == PVRSRV_DEV_POWER_STATE_DEFAULT) { - - - - + /* + Pdump a power-up regardless of the default state. + Then disable pdump and transition to the default power state. + This ensures that a power-up is always present in the pdump when necessary. + */ eError = PVRSRVDevicePrePowerStateKM(IMG_FALSE, ui32DeviceIndex, PVRSRV_DEV_POWER_STATE_ON); if(eError != PVRSRV_OK) { @@ -329,7 +490,7 @@ PVRSRV_ERROR PVRSRVSetDevicePowerStateKM(IMG_UINT32 ui32DeviceIndex, PDUMPSUSPEND(); } - #endif + #endif /* PDUMP */ eError = PVRSRVDevicePrePowerStateKM(IMG_FALSE, ui32DeviceIndex, eNewPowerState); if(eError != PVRSRV_OK) @@ -356,15 +517,22 @@ Exit: "PVRSRVSetDevicePowerStateKM : Transition to %d FAILED 0x%x", eNewPowerState, eError)); } - if (!bRetainMutex || (eError != PVRSRV_OK)) - { - PVRSRVPowerUnlock(ui32CallerID); - } - return eError; } +/*! +****************************************************************************** + + @Function PVRSRVSystemPrePowerStateKM + + @Description Perform processing required before a system power transition + + @Input eNewSysPowerState : + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVSystemPrePowerStateKM(PVRSRV_SYS_POWER_STATE eNewSysPowerState) { @@ -374,7 +542,7 @@ PVRSRV_ERROR PVRSRVSystemPrePowerStateKM(PVRSRV_SYS_POWER_STATE eNewSysPowerStat SysAcquireData(&psSysData); - + /* This mutex is unlocked in PVRSRVSystemPostPowerStateKM() */ eError = PVRSRVPowerLock(KERNEL_ID, IMG_TRUE); if(eError != PVRSRV_OK) { @@ -386,7 +554,7 @@ PVRSRV_ERROR PVRSRVSystemPrePowerStateKM(PVRSRV_SYS_POWER_STATE eNewSysPowerStat { if (_IsSystemStatePowered(eNewSysPowerState)) { - + /* Return device back to its default state. */ eNewDevicePowerState = PVRSRV_DEV_POWER_STATE_DEFAULT; } else @@ -394,7 +562,7 @@ PVRSRV_ERROR PVRSRVSystemPrePowerStateKM(PVRSRV_SYS_POWER_STATE eNewSysPowerStat eNewDevicePowerState = PVRSRV_DEV_POWER_STATE_OFF; } - + /* Perform device-specific transitions. */ eError = PVRSRVDevicePrePowerStateKM(IMG_TRUE, 0, eNewDevicePowerState); if (eError != PVRSRV_OK) { @@ -404,7 +572,7 @@ PVRSRV_ERROR PVRSRVSystemPrePowerStateKM(PVRSRV_SYS_POWER_STATE eNewSysPowerStat if (eNewSysPowerState != psSysData->eCurrentPowerState) { - + /* Perform system-specific power transitions. */ eError = SysSystemPrePowerState(eNewSysPowerState); if (eError != PVRSRV_OK) { @@ -420,7 +588,7 @@ ErrorExit: "PVRSRVSystemPrePowerStateKM: Transition from %d to %d FAILED 0x%x", psSysData->eCurrentPowerState, eNewSysPowerState, eError)); - + /* save the power state for the re-attempt */ psSysData->eFailedPowerState = eNewSysPowerState; PVRSRVPowerUnlock(KERNEL_ID); @@ -429,6 +597,18 @@ ErrorExit: } +/*! +****************************************************************************** + + @Function PVRSRVSystemPostPowerStateKM + + @Description Perform processing required after a system power transition + + @Input eNewSysPowerState : + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVSystemPostPowerStateKM(PVRSRV_SYS_POWER_STATE eNewSysPowerState) { @@ -440,7 +620,7 @@ PVRSRV_ERROR PVRSRVSystemPostPowerStateKM(PVRSRV_SYS_POWER_STATE eNewSysPowerSta if (eNewSysPowerState != psSysData->eCurrentPowerState) { - + /* Perform system-specific power transitions. */ eError = SysSystemPostPowerState(eNewSysPowerState); if (eError != PVRSRV_OK) { @@ -453,7 +633,7 @@ PVRSRV_ERROR PVRSRVSystemPostPowerStateKM(PVRSRV_SYS_POWER_STATE eNewSysPowerSta { if (_IsSystemStatePowered(eNewSysPowerState)) { - + /* Return device back to its default state. */ eNewDevicePowerState = PVRSRV_DEV_POWER_STATE_DEFAULT; } else @@ -461,7 +641,7 @@ PVRSRV_ERROR PVRSRVSystemPostPowerStateKM(PVRSRV_SYS_POWER_STATE eNewSysPowerSta eNewDevicePowerState = PVRSRV_DEV_POWER_STATE_OFF; } - + /* Perform device-specific power transitions. */ eError = PVRSRVDevicePostPowerStateKM(IMG_TRUE, 0, eNewDevicePowerState); if (eError != PVRSRV_OK) { @@ -479,13 +659,14 @@ Exit: PVRSRVPowerUnlock(KERNEL_ID); - + /* PRQA S 3415 2 */ /* side effects desired */ if (_IsSystemStatePowered(eNewSysPowerState) && PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_SUCCESSFUL)) { - - - + /* + Reprocess the devices' queues in case commands were blocked during + the power transition. + */ PVRSRVScheduleDeviceCallbacks(); } @@ -493,6 +674,18 @@ Exit: } +/*! +****************************************************************************** + + @Function PVRSRVSetPowerStateKM + + @Description Set the system into a new state + + @Input eNewPowerState : + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE eNewSysPowerState) { @@ -513,7 +706,7 @@ PVRSRV_ERROR PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE eNewSysPowerState) goto ErrorExit; } - + /* save new power state */ psSysData->eFailedPowerState = PVRSRV_SYS_POWER_STATE_Unspecified; return PVRSRV_OK; @@ -524,13 +717,35 @@ ErrorExit: "PVRSRVSetPowerStateKM: Transition from %d to %d FAILED 0x%x", psSysData->eCurrentPowerState, eNewSysPowerState, eError)); - + /* save the power state for the re-attempt */ psSysData->eFailedPowerState = eNewSysPowerState; return eError; } +/*! +****************************************************************************** + + @Function PVRSRVRegisterPowerDevice + + @Description + + Registers a device with the power manager. Passes Pre/Post Power handlers + and private device handle to be passed to power handlers + + @Input ui32DeviceIndex : device index + @Input pfnPrePower : Pre power transition handler + @Input pfnPostPower : Post power transition handler + @Input pfnPreClockSpeedChange : Pre clock speed transition handler (if required) + @Input pfnPostClockSpeedChange : Post clock speed transition handler (if required) + @Input hDevCookie : Dev cookie for dev power handlers + @Input eCurrentPowerState : Current power state of the device + @Input eDefaultPowerState : Default power state of the device + + @Return PVRSRV_ERROR + +******************************************************************************/ PVRSRV_ERROR PVRSRVRegisterPowerDevice(IMG_UINT32 ui32DeviceIndex, PFN_PRE_POWER pfnPrePower, PFN_POST_POWER pfnPostPower, @@ -562,7 +777,7 @@ PVRSRV_ERROR PVRSRVRegisterPowerDevice(IMG_UINT32 ui32DeviceIndex, return eError; } - + /* setup device for power manager */ psPowerDevice->pfnPrePower = pfnPrePower; psPowerDevice->pfnPostPower = pfnPostPower; psPowerDevice->pfnPreClockSpeedChange = pfnPreClockSpeedChange; @@ -572,13 +787,27 @@ PVRSRV_ERROR PVRSRVRegisterPowerDevice(IMG_UINT32 ui32DeviceIndex, psPowerDevice->eCurrentPowerState = eCurrentPowerState; psPowerDevice->eDefaultPowerState = eDefaultPowerState; - + /* insert into power device list */ List_PVRSRV_POWER_DEV_Insert(&(psSysData->psPowerDeviceList), psPowerDevice); return (PVRSRV_OK); } +/*! +****************************************************************************** + + @Function PVRSRVRemovePowerDevice + + @Description + + Removes device from power management register. Device is located by Device Index + + @Input ui32DeviceIndex : device index + + @Return PVRSRV_ERROR + +******************************************************************************/ PVRSRV_ERROR PVRSRVRemovePowerDevice (IMG_UINT32 ui32DeviceIndex) { SYS_DATA *psSysData; @@ -586,7 +815,7 @@ PVRSRV_ERROR PVRSRVRemovePowerDevice (IMG_UINT32 ui32DeviceIndex) SysAcquireData(&psSysData); - + /* find device in list and remove it */ psPowerDev = (PVRSRV_POWER_DEV*) List_PVRSRV_POWER_DEV_Any_va(psSysData->psPowerDeviceList, &MatchPowerDeviceIndex_AnyVaCb, @@ -596,13 +825,27 @@ PVRSRV_ERROR PVRSRVRemovePowerDevice (IMG_UINT32 ui32DeviceIndex) { List_PVRSRV_POWER_DEV_Remove(psPowerDev); OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_POWER_DEV), psPowerDev, IMG_NULL); - + /*not nulling pointer, copy on stack*/ } return (PVRSRV_OK); } +/*! +****************************************************************************** + + @Function PVRSRVIsDevicePowered + + @Description + + Whether the device is powered, for the purposes of lockup detection. + + @Input ui32DeviceIndex : device index + + @Return IMG_BOOL + +******************************************************************************/ IMG_EXPORT IMG_BOOL PVRSRVIsDevicePowered(IMG_UINT32 ui32DeviceIndex) { @@ -611,7 +854,7 @@ IMG_BOOL PVRSRVIsDevicePowered(IMG_UINT32 ui32DeviceIndex) SysAcquireData(&psSysData); - + /* PRQA S 3415 2 */ /* order not important */ if (OSIsResourceLocked(&psSysData->sPowerStateChangeResource, KERNEL_ID) || OSIsResourceLocked(&psSysData->sPowerStateChangeResource, ISR_ID)) { @@ -627,6 +870,22 @@ IMG_BOOL PVRSRVIsDevicePowered(IMG_UINT32 ui32DeviceIndex) } +/*! +****************************************************************************** + + @Function PVRSRVDevicePreClockSpeedChange + + @Description + + Notification from system layer that a device clock speed change is about to happen. + + @Input ui32DeviceIndex : device index + @Input bIdleDevice : whether the device should be idled + @Input pvInfo + + @Return IMG_VOID + +******************************************************************************/ PVRSRV_ERROR PVRSRVDevicePreClockSpeedChange(IMG_UINT32 ui32DeviceIndex, IMG_BOOL bIdleDevice, IMG_VOID *pvInfo) @@ -641,7 +900,7 @@ PVRSRV_ERROR PVRSRVDevicePreClockSpeedChange(IMG_UINT32 ui32DeviceIndex, if (bIdleDevice) { - + /* This mutex is released in PVRSRVDevicePostClockSpeedChange. */ eError = PVRSRVPowerLock(KERNEL_ID, IMG_FALSE); if (eError != PVRSRV_OK) { @@ -650,7 +909,7 @@ PVRSRV_ERROR PVRSRVDevicePreClockSpeedChange(IMG_UINT32 ui32DeviceIndex, } } - + /*search the device and then do the pre clock speed change*/ psPowerDevice = (PVRSRV_POWER_DEV*) List_PVRSRV_POWER_DEV_Any_va(psSysData->psPowerDeviceList, &MatchPowerDeviceIndex_AnyVaCb, @@ -678,6 +937,22 @@ PVRSRV_ERROR PVRSRVDevicePreClockSpeedChange(IMG_UINT32 ui32DeviceIndex, } +/*! +****************************************************************************** + + @Function PVRSRVDevicePostClockSpeedChange + + @Description + + Notification from system layer that a device clock speed change has just happened. + + @Input ui32DeviceIndex : device index + @Input bIdleDevice : whether the device had been idled + @Input pvInfo + + @Return IMG_VOID + +******************************************************************************/ IMG_VOID PVRSRVDevicePostClockSpeedChange(IMG_UINT32 ui32DeviceIndex, IMG_BOOL bIdleDevice, IMG_VOID *pvInfo) @@ -690,7 +965,7 @@ IMG_VOID PVRSRVDevicePostClockSpeedChange(IMG_UINT32 ui32DeviceIndex, SysAcquireData(&psSysData); - + /*search the device and then do the post clock speed change*/ psPowerDevice = (PVRSRV_POWER_DEV*) List_PVRSRV_POWER_DEV_Any_va(psSysData->psPowerDeviceList, &MatchPowerDeviceIndex_AnyVaCb, @@ -712,8 +987,11 @@ IMG_VOID PVRSRVDevicePostClockSpeedChange(IMG_UINT32 ui32DeviceIndex, if (bIdleDevice) { - + /* This mutex was acquired in PVRSRVDevicePreClockSpeedChange. */ PVRSRVPowerUnlock(KERNEL_ID); } } +/****************************************************************************** + End of file (power.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/common/pvrsrv.c b/sgx/services4/srvkm/common/pvrsrv.c index c0c2349..b9c3253 100644 --- a/sgx/services4/srvkm/common/pvrsrv.c +++ b/sgx/services4/srvkm/common/pvrsrv.c @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title core services functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Main APIs for core services functions +@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 <linux/slab.h> #include "services_headers.h" @@ -36,6 +53,7 @@ #if defined(TTRACE) #include "ttrace.h" #endif +#include "perfkm.h" #include "pvrversion.h" @@ -47,9 +65,26 @@ IMG_UINT32 g_ui32InitFlags; +/* mark which parts of Services were initialised */ #define INIT_DATA_ENABLE_PDUMPINIT 0x1U #define INIT_DATA_ENABLE_TTARCE 0x2U +/*! +****************************************************************************** + + @Function AllocateDeviceID + + @Description + + allocates a device id from the pool of valid ids + + @input psSysData : system data + + @input pui32DevID : device id to return + + @Return device id + +******************************************************************************/ PVRSRV_ERROR AllocateDeviceID(SYS_DATA *psSysData, IMG_UINT32 *pui32DevID) { SYS_DEVICE_ID* psDeviceWalker; @@ -58,7 +93,7 @@ PVRSRV_ERROR AllocateDeviceID(SYS_DATA *psSysData, IMG_UINT32 *pui32DevID) psDeviceWalker = &psSysData->sDeviceID[0]; psDeviceEnd = psDeviceWalker + psSysData->ui32NumDevices; - + /* find a free ID */ while (psDeviceWalker < psDeviceEnd) { if (!psDeviceWalker->bInUse) @@ -72,13 +107,29 @@ PVRSRV_ERROR AllocateDeviceID(SYS_DATA *psSysData, IMG_UINT32 *pui32DevID) PVR_DPF((PVR_DBG_ERROR,"AllocateDeviceID: No free and valid device IDs available!")); - + /* Should never get here: sDeviceID[] may have been setup too small */ PVR_ASSERT(psDeviceWalker < psDeviceEnd); return PVRSRV_ERROR_NO_FREE_DEVICEIDS_AVALIABLE; } +/*! +****************************************************************************** + + @Function FreeDeviceID + + @Description + + frees a device id from the pool of valid ids + + @input psSysData : system data + + @input ui32DevID : device id to free + + @Return device id + +******************************************************************************/ PVRSRV_ERROR FreeDeviceID(SYS_DATA *psSysData, IMG_UINT32 ui32DevID) { SYS_DEVICE_ID* psDeviceWalker; @@ -87,10 +138,10 @@ PVRSRV_ERROR FreeDeviceID(SYS_DATA *psSysData, IMG_UINT32 ui32DevID) psDeviceWalker = &psSysData->sDeviceID[0]; psDeviceEnd = psDeviceWalker + psSysData->ui32NumDevices; - + /* find the ID to free */ while (psDeviceWalker < psDeviceEnd) { - + /* if matching id and in use, free */ if ( (psDeviceWalker->uiID == ui32DevID) && (psDeviceWalker->bInUse) @@ -104,13 +155,29 @@ PVRSRV_ERROR FreeDeviceID(SYS_DATA *psSysData, IMG_UINT32 ui32DevID) PVR_DPF((PVR_DBG_ERROR,"FreeDeviceID: no matching dev ID that is in use!")); - + /* should never get here */ PVR_ASSERT(psDeviceWalker < psDeviceEnd); return PVRSRV_ERROR_INVALID_DEVICEID; } +/*! +****************************************************************************** + + @Function ReadHWReg + + @Description + + register access function + + @input pvLinRegBaseAddr : lin addr of register block base + + @input ui32Offset : byte offset from register base + + @Return register value + +******************************************************************************/ #ifndef ReadHWReg IMG_EXPORT IMG_UINT32 ReadHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset) @@ -120,6 +187,24 @@ IMG_UINT32 ReadHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset) #endif +/*! +****************************************************************************** + + @Function WriteHWReg + + @Description + + register access function + + @input pvLinRegBaseAddr : lin addr of register block base + + @input ui32Offset : byte offset from register base + + @input ui32Value : value to write to register + + @Return register value : original reg. value + +******************************************************************************/ #ifndef WriteHWReg IMG_EXPORT IMG_VOID WriteHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UINT32 ui32Value) @@ -132,6 +217,24 @@ IMG_VOID WriteHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UINT3 #endif +/*! +****************************************************************************** + + @Function WriteHWRegs + + @Description + + register access function + + @input pvLinRegBaseAddr : lin addr of register block base + + @input ui32Count : register count + + @input psHWRegs : address/value register list + + @Return none + +******************************************************************************/ #ifndef WriteHWRegs IMG_EXPORT IMG_VOID WriteHWRegs(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Count, PVRSRV_HWREG *psHWRegs) @@ -145,6 +248,19 @@ IMG_VOID WriteHWRegs(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Count, PVRSRV_HW } #endif +/*! +****************************************************************************** + @Function PVRSRVEnumerateDCKM_ForEachVaCb + + @Description + + Enumerates the device node (if is of the same class as given). + + @Input psDeviceNode - The device node to be enumerated + va - variable arguments list, with: + pui32DevCount - The device count pointer (to be increased) + ppui32DevID - The pointer to the device IDs pointer (to be updated and increased) +******************************************************************************/ static IMG_VOID PVRSRVEnumerateDevicesKM_ForEachVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va) { IMG_UINT *pui32DevCount; @@ -163,11 +279,43 @@ static IMG_VOID PVRSRVEnumerateDevicesKM_ForEachVaCb(PVRSRV_DEVICE_NODE *psDevic +/*! +****************************************************************************** + + @Function PVRSRVEnumerateDevicesKM + + @Description + This function will enumerate all the devices supported by the + PowerVR services within the target system. + The function returns a list of the device ID strcutres stored either in + the services or constructed in the user mode glue component in certain + environments. The number of devices in the list is also returned. + + In a binary layered component which does not support dynamic runtime selection, + the glue code should compile to return the supported devices statically, + e.g. multiple instances of the same device if multiple devices are supported, + or the target combination of MBX and display device. + + In the case of an environment (for instance) where one MBX1 may connect to two + display devices this code would enumerate all three devices and even + non-dynamic MBX1 selection code should retain the facility to parse the list + to find the index of the MBX device + + @output pui32NumDevices : On success, contains the number of devices present + in the system + + @output psDevIdList : Pointer to called supplied buffer to receive the + list of PVRSRV_DEVICE_IDENTIFIER + + @return PVRSRV_ERROR : PVRSRV_NO_ERROR + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR IMG_CALLCONV PVRSRVEnumerateDevicesKM(IMG_UINT32 *pui32NumDevices, PVRSRV_DEVICE_IDENTIFIER *psDevIdList) { SYS_DATA *psSysData; +/* PVRSRV_DEVICE_NODE *psDeviceNode; */ IMG_UINT32 i; if (!pui32NumDevices || !psDevIdList) @@ -178,20 +326,22 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVEnumerateDevicesKM(IMG_UINT32 *pui32NumDevices, SysAcquireData(&psSysData); - - + /* + setup input buffer to be `empty' + */ for (i=0; i<PVRSRV_MAX_DEVICES; i++) { psDevIdList[i].eDeviceType = PVRSRV_DEVICE_TYPE_UNKNOWN; } - + /* and zero device count */ *pui32NumDevices = 0; - - - - + /* + Search through the device list for services managed devices + return id info for each device and the number of devices + available + */ List_PVRSRV_DEVICE_NODE_ForEach_va(psSysData->psDeviceNodeList, &PVRSRVEnumerateDevicesKM_ForEachVaCb, pui32NumDevices, @@ -202,11 +352,23 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVEnumerateDevicesKM(IMG_UINT32 *pui32NumDevices, } +/*! +****************************************************************************** + + @Function PVRSRVInit + + @Description Initialise services + + @Input psSysData : sysdata structure + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR IMG_CALLCONV PVRSRVInit(PSYS_DATA psSysData) { PVRSRV_ERROR eError; - + /* Initialise Resource Manager */ eError = ResManInit(); if (eError != PVRSRV_OK) { @@ -219,25 +381,25 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVInit(PSYS_DATA psSysData) goto Error; } - + /* Initialise handles */ eError = PVRSRVHandleInit(); if(eError != PVRSRV_OK) { goto Error; } - + /* Initialise Power Manager Lock */ eError = OSCreateResource(&psSysData->sPowerStateChangeResource); if (eError != PVRSRV_OK) { goto Error; } - + /* Initialise system power state */ psSysData->eCurrentPowerState = PVRSRV_SYS_POWER_STATE_D0; psSysData->eFailedPowerState = PVRSRV_SYS_POWER_STATE_Unspecified; - + /* Create an event object */ if(OSAllocMem( PVRSRV_PAGEABLE_SELECT, sizeof(PVRSRV_EVENTOBJECT) , (IMG_VOID **)&psSysData->psGlobalEventObject, 0, @@ -252,7 +414,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVInit(PSYS_DATA psSysData) goto Error; } - + /* Store OS high res timer fallbacks, the system is free to overide these */ psSysData->pfnHighResTimerCreate = OSFuncHighResTimerCreate; psSysData->pfnHighResTimerGetus = OSFuncHighResTimerGetus; psSysData->pfnHighResTimerDestroy = OSFuncHighResTimerDestroy; @@ -264,10 +426,11 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVInit(PSYS_DATA psSysData) g_ui32InitFlags |= INIT_DATA_ENABLE_TTARCE; #endif - + /* Initialise pdump */ PDUMPINIT(); g_ui32InitFlags |= INIT_DATA_ENABLE_PDUMPINIT; + PERFINIT(); return eError; Error: @@ -277,6 +440,18 @@ Error: +/*! +****************************************************************************** + + @Function PVRSRVDeInit + + @Description De-Initialise services + + @Input psSysData : sysdata structure + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_VOID IMG_CALLCONV PVRSRVDeInit(PSYS_DATA psSysData) { PVRSRV_ERROR eError; @@ -288,20 +463,23 @@ IMG_VOID IMG_CALLCONV PVRSRVDeInit(PSYS_DATA psSysData) PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeInit: PVRSRVHandleDeInit failed - invalid param")); return; } + + PERFDEINIT(); + #if defined(TTRACE) - + /* deinitialise ttrace */ if ((g_ui32InitFlags & INIT_DATA_ENABLE_TTARCE) > 0) { PVRSRVTimeTraceDeinit(); } #endif - + /* deinitialise pdump */ if( (g_ui32InitFlags & INIT_DATA_ENABLE_PDUMPINIT) > 0) { PDUMPDEINIT(); } - + /* destroy event object */ if(psSysData->psGlobalEventObject) { OSEventObjectDestroyKM(psSysData->psGlobalEventObject); @@ -328,6 +506,26 @@ IMG_VOID IMG_CALLCONV PVRSRVDeInit(PSYS_DATA psSysData) } +/*! +****************************************************************************** + + @Function PVRSRVRegisterDevice + + @Description + + registers a device with the system + + @Input psSysData : sysdata structure + + @Input pfnRegisterDevice : device registration function + + @Input ui32SOCInterruptBit : SoC interrupt bit for this device + + @Output pui32DeviceIndex : unique device key (for case of multiple identical devices) + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR IMG_CALLCONV PVRSRVRegisterDevice(PSYS_DATA psSysData, PVRSRV_ERROR (*pfnRegisterDevice)(PVRSRV_DEVICE_NODE*), IMG_UINT32 ui32SOCInterruptBit, @@ -336,7 +534,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVRegisterDevice(PSYS_DATA psSysData, PVRSRV_ERROR eError; PVRSRV_DEVICE_NODE *psDeviceNode; - + /* Allocate device node */ if(OSAllocMem( PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_DEVICE_NODE), (IMG_VOID **)&psDeviceNode, IMG_NULL, @@ -352,33 +550,48 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVRegisterDevice(PSYS_DATA psSysData, { OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_DEVICE_NODE), psDeviceNode, IMG_NULL); - + /*not nulling pointer, out of scope*/ PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterDevice : Failed to register device")); return (PVRSRV_ERROR_DEVICE_REGISTER_FAILED); } - - - - - + /* + make the refcount 1 and test on this to initialise device + at acquiredevinfo. On release if refcount is 1, deinitialise + and when refcount is 0 (sysdata de-alloc) deallocate the device + structures + */ psDeviceNode->ui32RefCount = 1; psDeviceNode->psSysData = psSysData; psDeviceNode->ui32SOCInterruptBit = ui32SOCInterruptBit; - + /* all devices need a unique identifier */ AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex); - + /* and finally insert the device into the dev-list */ List_PVRSRV_DEVICE_NODE_Insert(&psSysData->psDeviceNodeList, psDeviceNode); - + /* and copy back index */ *pui32DeviceIndex = psDeviceNode->sDevId.ui32DeviceIndex; return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVInitialiseDevice + + @Description + + initialises device by index + + @Input ui32DevIndex : Index to the required device + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR IMG_CALLCONV PVRSRVInitialiseDevice (IMG_UINT32 ui32DevIndex) { PVRSRV_DEVICE_NODE *psDeviceNode; @@ -389,7 +602,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVInitialiseDevice (IMG_UINT32 ui32DevIndex) SysAcquireData(&psSysData); - + /* Find device in the list */ psDeviceNode = (PVRSRV_DEVICE_NODE*) List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, &MatchDeviceKM_AnyVaCb, @@ -397,14 +610,19 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVInitialiseDevice (IMG_UINT32 ui32DevIndex) IMG_TRUE); if(!psDeviceNode) { - + /* Devinfo not in the list */ PVR_DPF((PVR_DBG_ERROR,"PVRSRVInitialiseDevice: requested device is not present")); return PVRSRV_ERROR_INIT_FAILURE; } - PVR_ASSERT (psDeviceNode->ui32RefCount > 0); +/* +FoundDevice: +*/ - + PVR_ASSERT (psDeviceNode->ui32RefCount > 0); + /* + Create the device's resource manager context. + */ eError = PVRSRVResManConnect(IMG_NULL, &psDeviceNode->hResManContext); if (eError != PVRSRV_OK) { @@ -412,7 +630,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVInitialiseDevice (IMG_UINT32 ui32DevIndex) return eError; } - + /* Initialise the device */ if(psDeviceNode->pfnInitDevice != IMG_NULL) { eError = psDeviceNode->pfnInitDevice(psDeviceNode); @@ -430,9 +648,17 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVInitialiseDevice (IMG_UINT32 ui32DevIndex) static PVRSRV_ERROR PVRSRVFinaliseSystem_SetPowerState_AnyCb(PVRSRV_DEVICE_NODE *psDeviceNode) { PVRSRV_ERROR eError; + + eError = PVRSRVPowerLock(KERNEL_ID, IMG_FALSE); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVFinaliseSystem: Failed PVRSRVPowerLock call (device index: %d)", psDeviceNode->sDevId.ui32DeviceIndex)); + return eError; + } + eError = PVRSRVSetDevicePowerStateKM(psDeviceNode->sDevId.ui32DeviceIndex, - PVRSRV_DEV_POWER_STATE_DEFAULT, - KERNEL_ID, IMG_FALSE); + PVRSRV_DEV_POWER_STATE_DEFAULT); + PVRSRVPowerUnlock(KERNEL_ID); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVFinaliseSystem: Failed PVRSRVSetDevicePowerStateKM call (device index: %d)", psDeviceNode->sDevId.ui32DeviceIndex)); @@ -440,6 +666,7 @@ static PVRSRV_ERROR PVRSRVFinaliseSystem_SetPowerState_AnyCb(PVRSRV_DEVICE_NODE return eError; } +/*wraps the PVRSRVDevInitCompatCheck call and prints a debugging message if failed*/ static PVRSRV_ERROR PVRSRVFinaliseSystem_CompatCheck_AnyCb(PVRSRV_DEVICE_NODE *psDeviceNode) { PVRSRV_ERROR eError; @@ -452,8 +679,23 @@ static PVRSRV_ERROR PVRSRVFinaliseSystem_CompatCheck_AnyCb(PVRSRV_DEVICE_NODE *p } +/*! +****************************************************************************** + + @Function PVRSRVFinaliseSystem + + @Description + + Final part of system initialisation. + + @Input ui32DevIndex : Index to the required device + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR IMG_CALLCONV PVRSRVFinaliseSystem(IMG_BOOL bInitSuccessful) { +/* PVRSRV_DEVICE_NODE *psDeviceNode;*/ SYS_DATA *psSysData; PVRSRV_ERROR eError; @@ -470,7 +712,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVFinaliseSystem(IMG_BOOL bInitSuccessful) return eError; } - + /* Place all devices into their default power state. */ eError = List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any(psSysData->psDeviceNodeList, &PVRSRVFinaliseSystem_SetPowerState_AnyCb); if (eError != PVRSRV_OK) @@ -478,7 +720,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVFinaliseSystem(IMG_BOOL bInitSuccessful) return eError; } - + /* Verify microkernel compatibility for devices */ eError = List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any(psSysData->psDeviceNodeList, &PVRSRVFinaliseSystem_CompatCheck_AnyCb); if (eError != PVRSRV_OK) @@ -487,10 +729,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVFinaliseSystem(IMG_BOOL bInitSuccessful) } } - - - - + /* Some platforms call this too early in the boot phase. */ #if !defined(__QNXNTO__) PDUMPENDINITPHASE(); #endif @@ -501,13 +740,34 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVFinaliseSystem(IMG_BOOL bInitSuccessful) PVRSRV_ERROR PVRSRVDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode) { - + /* Only check devices which specify a compatibility check callback */ if (psDeviceNode->pfnInitDeviceCompatCheck) return psDeviceNode->pfnInitDeviceCompatCheck(psDeviceNode); else return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVAcquireDeviceDataKM + + @Description + + Matchs a device given a device type and a device index. + + @input psDeviceNode :The device node to be matched. + + @Input va : Variable argument list with: + eDeviceType : Required device type. If type is unknown use ui32DevIndex + to locate device data + + ui32DevIndex : Index to the required device obtained from the + PVRSRVEnumerateDevice function + + @Return PVRSRV_ERROR : + +******************************************************************************/ static IMG_VOID * PVRSRVAcquireDeviceDataKM_Match_AnyVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va) { PVRSRV_DEVICE_TYPE eDeviceType; @@ -529,6 +789,27 @@ static IMG_VOID * PVRSRVAcquireDeviceDataKM_Match_AnyVaCb(PVRSRV_DEVICE_NODE *ps } } +/*! +****************************************************************************** + + @Function PVRSRVAcquireDeviceDataKM + + @Description + + Returns device information + + @Input ui32DevIndex : Index to the required device obtained from the + PVRSRVEnumerateDevice function + + @Input eDeviceType : Required device type. If type is unknown use ui32DevIndex + to locate device data + + @Output *phDevCookie : Dev Cookie + + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR IMG_CALLCONV PVRSRVAcquireDeviceDataKM (IMG_UINT32 ui32DevIndex, PVRSRV_DEVICE_TYPE eDeviceType, @@ -541,7 +822,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVAcquireDeviceDataKM (IMG_UINT32 ui32DevIndex, SysAcquireData(&psSysData); - + /* Find device in the list */ psDeviceNode = List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, &PVRSRVAcquireDeviceDataKM_Match_AnyVaCb, eDeviceType, @@ -550,14 +831,16 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVAcquireDeviceDataKM (IMG_UINT32 ui32DevIndex, if (!psDeviceNode) { - + /* device can't be found in the list so it isn't in the system */ PVR_DPF((PVR_DBG_ERROR,"PVRSRVAcquireDeviceDataKM: requested device is not present")); return PVRSRV_ERROR_INIT_FAILURE; } +/*FoundDevice:*/ + PVR_ASSERT (psDeviceNode->ui32RefCount > 0); - + /* return the dev cookie? */ if (phDevCookie) { *phDevCookie = (IMG_HANDLE)psDeviceNode; @@ -567,6 +850,20 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVAcquireDeviceDataKM (IMG_UINT32 ui32DevIndex, } +/*! +****************************************************************************** + + @Function PVRSRVDeinitialiseDevice + + @Description + + This De-inits device + + @Input ui32DevIndex : Index to the required device + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR IMG_CALLCONV PVRSRVDeinitialiseDevice(IMG_UINT32 ui32DevIndex) { PVRSRV_DEVICE_NODE *psDeviceNode; @@ -587,20 +884,28 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVDeinitialiseDevice(IMG_UINT32 ui32DevIndex) return PVRSRV_ERROR_DEVICEID_NOT_FOUND; } - + eError = PVRSRVPowerLock(KERNEL_ID, IMG_FALSE); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: Failed PVRSRVPowerLock call")); + return eError; + } + /* + Power down the device if necessary. + */ eError = PVRSRVSetDevicePowerStateKM(ui32DevIndex, - PVRSRV_DEV_POWER_STATE_OFF, - KERNEL_ID, - IMG_FALSE); + PVRSRV_DEV_POWER_STATE_OFF); + PVRSRVPowerUnlock(KERNEL_ID); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: Failed PVRSRVSetDevicePowerStateKM call")); return eError; } - - + /* + Free the dissociated device memory. + */ eError = ResManFreeResByCriteria(psDeviceNode->hResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_DEVICEMEM_ALLOCATION, @@ -611,8 +916,9 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVDeinitialiseDevice(IMG_UINT32 ui32DevIndex) return eError; } - - + /* + De-init the device. + */ if(psDeviceNode->pfnDeInitDevice != IMG_NULL) { eError = psDeviceNode->pfnDeInitDevice(psDeviceNode); @@ -623,19 +929,20 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVDeinitialiseDevice(IMG_UINT32 ui32DevIndex) } } - - + /* + Close the device's resource manager context. + */ PVRSRVResManDisconnect(psDeviceNode->hResManContext, IMG_TRUE); psDeviceNode->hResManContext = IMG_NULL; - + /* remove node from list */ List_PVRSRV_DEVICE_NODE_Remove(psDeviceNode); - + /* deallocate id and memory */ (IMG_VOID)FreeDeviceID(psSysData, ui32DevIndex); OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_DEVICE_NODE), psDeviceNode, IMG_NULL); - + /*not nulling pointer, out of scope*/ return (PVRSRV_OK); } @@ -656,8 +963,9 @@ PVRSRV_ERROR IMG_CALLCONV PollForValueKM (volatile IMG_UINT32* pui32LinMemAddr, PVR_UNREFERENCED_PARAMETER(ui32PollPeriodus); #endif - - + /* For the Emulator we want the system to stop when a lock-up is detected so the state can be analysed. + * Also the Emulator is much slower than real silicon so timeouts are not valid. + */ do { if((*pui32LinMemAddr & ui32Mask) == ui32Value) @@ -671,18 +979,18 @@ PVRSRV_ERROR IMG_CALLCONV PollForValueKM (volatile IMG_UINT32* pui32LinMemAddr, OSReleaseThreadQuanta(); #endif - } while (ui32Timeoutus); + } while (ui32Timeoutus); /* Endless loop only for the Emulator */ } #else { - IMG_UINT32 ui32ActualValue = 0xFFFFFFFFU; + IMG_UINT32 ui32ActualValue = 0xFFFFFFFFU; /* Initialiser only required to prevent incorrect warning */ if (bAllowPreemption) { PVR_ASSERT(ui32PollPeriodus >= 1000); } - + /* PRQA S 3415,4109 1 */ /* macro format critical - leave alone */ LOOP_UNTIL_TIMEOUT(ui32Timeoutus) { ui32ActualValue = (*pui32LinMemAddr & ui32Mask); @@ -704,12 +1012,13 @@ PVRSRV_ERROR IMG_CALLCONV PollForValueKM (volatile IMG_UINT32* pui32LinMemAddr, PVR_DPF((PVR_DBG_ERROR,"PollForValueKM: Timeout. Expected 0x%x but found 0x%x (mask 0x%x).", ui32Value, ui32ActualValue, ui32Mask)); } -#endif +#endif /* #if defined (EMULATOR) */ return PVRSRV_ERROR_TIMEOUT; } +/*Level 3 of the loop nesting*/ static IMG_VOID PVRSRVGetMiscInfoKM_RA_GetStats_ForEachVaCb(BM_HEAP *psBMHeap, va_list va) { IMG_CHAR **ppszStr; @@ -721,7 +1030,10 @@ static IMG_VOID PVRSRVGetMiscInfoKM_RA_GetStats_ForEachVaCb(BM_HEAP *psBMHeap, v pui32StrLen = va_arg(va, IMG_UINT32*); ui32Mode = va_arg(va, IMG_UINT32); - + /* Would be better to pass fn pointer in the variable args list + * but MS C compiler complains with error C2066: In ANSI C, + * it is not legal to cast between a function pointer and a data pointer. + */ switch(ui32Mode) { case PVRSRV_MISC_INFO_MEMSTATS_PRESENT: @@ -749,6 +1061,7 @@ static IMG_VOID PVRSRVGetMiscInfoKM_RA_GetStats_ForEachVaCb(BM_HEAP *psBMHeap, v } } +/*Level 2 of the loop nesting*/ static PVRSRV_ERROR PVRSRVGetMiscInfoKM_BMContext_AnyVaCb(BM_CONTEXT *psBMContext, va_list va) { @@ -776,6 +1089,7 @@ static PVRSRV_ERROR PVRSRVGetMiscInfoKM_BMContext_AnyVaCb(BM_CONTEXT *psBMContex } +/*level 1 of the loop nesting*/ static PVRSRV_ERROR PVRSRVGetMiscInfoKM_Device_AnyVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va) { IMG_UINT32 *pui32StrLen; @@ -792,7 +1106,7 @@ static PVRSRV_ERROR PVRSRVGetMiscInfoKM_Device_AnyVaCb(PVRSRV_DEVICE_NODE *psDev *pi32Count = OSSNPrintf(*ppszStr, 100, "\n\nDevice Type %d:\n", psDeviceNode->sDevId.eDeviceType); UPDATE_SPACE(*ppszStr, *pi32Count, *pui32StrLen); - + /* kernel context: */ if(psDeviceNode->sDevMemoryInfo.pBMKernelContext) { CHECK_SPACE(*pui32StrLen); @@ -806,7 +1120,7 @@ static PVRSRV_ERROR PVRSRVGetMiscInfoKM_Device_AnyVaCb(PVRSRV_DEVICE_NODE *psDev ui32Mode); } - + /* double loop app contexts:heaps */ return List_BM_CONTEXT_PVRSRV_ERROR_Any_va(psDeviceNode->sDevMemoryInfo.pBMContext, &PVRSRVGetMiscInfoKM_BMContext_AnyVaCb, pui32StrLen, @@ -816,6 +1130,19 @@ static PVRSRV_ERROR PVRSRVGetMiscInfoKM_Device_AnyVaCb(PVRSRV_DEVICE_NODE *psDev } +/*! +****************************************************************************** + + @Function PVRSRVGetMiscInfoKM + + @Description + Retrieves misc. info. + + @Output PVRSRV_MISC_INFO + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO_KM *psMiscInfo) @@ -833,7 +1160,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) psMiscInfo->ui32StatePresent = 0; - + /* do a basic check for uninitialised request flag */ if(psMiscInfo->ui32StateRequest & ~(PVRSRV_MISC_INFO_TIMER_PRESENT |PVRSRV_MISC_INFO_CLOCKGATE_PRESENT |PVRSRV_MISC_INFO_MEMSTATS_PRESENT @@ -841,7 +1168,10 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) |PVRSRV_MISC_INFO_DDKVERSION_PRESENT |PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT |PVRSRV_MISC_INFO_RESET_PRESENT - |PVRSRV_MISC_INFO_FREEMEM_PRESENT)) + |PVRSRV_MISC_INFO_FREEMEM_PRESENT + |PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT + |PVRSRV_MISC_INFO_GET_PAGE_SIZE_PRESENT + |PVRSRV_MISC_INFO_FORCE_SWAP_TO_SYSTEM_PRESENT)) { PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid state request flags")); return PVRSRV_ERROR_INVALID_PARAMS; @@ -849,7 +1179,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) SysAcquireData(&psSysData); - + /* return SOC Timer registers */ if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_TIMER_PRESENT) != 0UL) && (psSysData->pvSOCTimerRegisterKM != IMG_NULL)) { @@ -863,7 +1193,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) psMiscInfo->hSOCTimerRegisterOSMemHandle = IMG_NULL; } - + /* return SOC Clock Gating registers */ if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CLOCKGATE_PRESENT) != 0UL) && (psSysData->pvSOCClockGateRegsBase != IMG_NULL)) { @@ -872,11 +1202,14 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) psMiscInfo->ui32SOCClockGateRegsSize = psSysData->ui32SOCClockGateRegsSize; } - + /* memory stats */ if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0UL) && (psMiscInfo->pszMemoryStr != IMG_NULL)) { RA_ARENA **ppArena; +/* BM_HEAP *psBMHeap; + BM_CONTEXT *psBMContext; + PVRSRV_DEVICE_NODE *psDeviceNode;*/ IMG_CHAR *pszStr; IMG_UINT32 ui32StrLen; IMG_INT32 i32Count; @@ -886,7 +1219,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_MEMSTATS_PRESENT; - + /* Local backing stores */ ppArena = &psSysData->apsLocalDevMemArena[0]; while(*ppArena) { @@ -897,12 +1230,14 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) RA_GetStats(*ppArena, &pszStr, &ui32StrLen); - + /* advance through the array */ ppArena++; } - - + /* per device */ +/* psDeviceNode = psSysData->psDeviceNodeList;*/ + + /*triple loop; devices:contexts:heaps*/ List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList, &PVRSRVGetMiscInfoKM_Device_AnyVaCb, &ui32StrLen, @@ -910,12 +1245,12 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) &pszStr, PVRSRV_MISC_INFO_MEMSTATS_PRESENT); - + /* attach a new line and string terminate */ i32Count = OSSNPrintf(pszStr, 100, "\n"); UPDATE_SPACE(pszStr, i32Count, ui32StrLen); } - + /* Lean version of mem stats: only show free mem on each RA */ if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_FREEMEM_PRESENT) != 0) && psMiscInfo->pszMemoryStr) { @@ -928,7 +1263,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_FREEMEM_PRESENT; - + /* triple loop over devices:contexts:heaps */ List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList, &PVRSRVGetMiscInfoKM_Device_AnyVaCb, &ui32StrLen, @@ -947,7 +1282,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) psMiscInfo->sGlobalEventObject = *psSysData->psGlobalEventObject; } - + /* DDK version and memstats not supported in same call to GetMiscInfo */ if (((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0UL) && ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) == 0UL) @@ -955,16 +1290,16 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) { IMG_CHAR *pszStr; IMG_UINT32 ui32StrLen; - IMG_UINT32 ui32LenStrPerNum = 12; + IMG_UINT32 ui32LenStrPerNum = 12; /* string length per UI32: 10 digits + '.' + '\0' = 12 bytes */ IMG_INT32 i32Count; IMG_INT i; psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_DDKVERSION_PRESENT; - + /* construct DDK string */ psMiscInfo->aui32DDKVersion[0] = PVRVERSION_MAJ; psMiscInfo->aui32DDKVersion[1] = PVRVERSION_MIN; - psMiscInfo->aui32DDKVersion[2] = PVRVERSION_BRANCH; - psMiscInfo->aui32DDKVersion[3] = PVRVERSION_BUILD; + psMiscInfo->aui32DDKVersion[2] = PVRVERSION_BUILD_HI; + psMiscInfo->aui32DDKVersion[3] = PVRVERSION_BUILD_LO; pszStr = psMiscInfo->pszMemoryStr; ui32StrLen = psMiscInfo->ui32MemoryStrLen; @@ -992,7 +1327,9 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) if(psMiscInfo->sCacheOpCtl.bDeferOp) { - + /* For now, assume deferred ops are "full" cache ops, + * and we don't need (or expect) a meminfo. + */ psSysData->ePendingCacheOpType = psMiscInfo->sCacheOpCtl.eCacheOpType; } else @@ -1023,7 +1360,6 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) #if defined (SUPPORT_SID_INTERFACE) PVR_DBG_BREAK #else - psPerProc = PVRSRVFindPerProcessData(); if(PVRSRVLookupHandle(psPerProc->psHandleBase, @@ -1040,6 +1376,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_FLUSH) { if(!OSFlushCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle, + 0, psMiscInfo->sCacheOpCtl.pvBaseVAddr, psMiscInfo->sCacheOpCtl.ui32Length)) { @@ -1050,7 +1387,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) if ((psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_CLEAN_REGIONS) || (psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_INV_REGIONS)) { - IMG_BOOL (*op)(IMG_HANDLE hOSMemHandle, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length); + IMG_BOOL (*op)(IMG_HANDLE hOSMemHandle, IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length); IMG_HANDLE hOSMemHandle = psKernelMemInfo->sMemBlk.hOSMemHandle; IMG_VOID *pvEndVAddr = psMiscInfo->sCacheOpCtl.pvBaseVAddr + psMiscInfo->sCacheOpCtl.ui32Length; @@ -1075,7 +1412,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) ui32Length *= psMiscInfo->sCacheOpCtl.sRegions[i].h; - if(!(*op)(hOSMemHandle, pvBaseVAddr, ui32Length)) + if(!(*op)(hOSMemHandle, 0, pvBaseVAddr, ui32Length)) { return PVRSRV_ERROR_CACHEOP_FAILED; } @@ -1099,7 +1436,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) ui32Length = pvEndVAddr - pvBaseVAddr; } - if(!(*op)(hOSMemHandle, pvBaseVAddr, ui32Length)) + if(!(*op)(hOSMemHandle, 0, pvBaseVAddr, ui32Length)) { printk(KERN_WARNING "op failed\n"); return PVRSRV_ERROR_CACHEOP_FAILED; @@ -1115,6 +1452,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) else if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_CLEAN) { if(!OSCleanCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle, + 0, psMiscInfo->sCacheOpCtl.pvBaseVAddr, psMiscInfo->sCacheOpCtl.ui32Length)) { @@ -1256,18 +1594,71 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) } } + if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT) != 0UL) + { +#if !defined (SUPPORT_SID_INTERFACE) + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + PVRSRV_PER_PROCESS_DATA *psPerProc; +#endif + + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT; + +#if defined (SUPPORT_SID_INTERFACE) + PVR_DBG_BREAK +#else + psPerProc = PVRSRVFindPerProcessData(); + + if(PVRSRVLookupHandle(psPerProc->psHandleBase, + (IMG_PVOID *)&psKernelMemInfo, + psMiscInfo->sGetRefCountCtl.u.psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetMiscInfoKM: " + "Can't find kernel meminfo")); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psMiscInfo->sGetRefCountCtl.ui32RefCount = psKernelMemInfo->ui32RefCount; +#endif + } + + if ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GET_PAGE_SIZE_PRESENT) != 0UL) + { + psMiscInfo->ui32PageSize = HOST_PAGESIZE(); + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GET_PAGE_SIZE_PRESENT; + } + #if defined(PVRSRV_RESET_ON_HWTIMEOUT) if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_RESET_PRESENT) != 0UL) { PVR_LOG(("User requested OS reset")); OSPanic(); } -#endif +#endif /* #if defined(PVRSRV_RESET_ON_HWTIMEOUT) */ + + if ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_FORCE_SWAP_TO_SYSTEM_PRESENT) != 0UL) + { + PVRSRVSetDCState(DC_STATE_FORCE_SWAP_TO_SYSTEM); + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_FORCE_SWAP_TO_SYSTEM_PRESENT; + } return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function PVRSRVDeviceLISR + + @Description + OS-independent Device Low-level Interrupt Service Routine + + @Input psDeviceNode + + @Return IMG_BOOL : Whether any interrupts were serviced + +******************************************************************************/ IMG_BOOL IMG_CALLCONV PVRSRVDeviceLISR(PVRSRV_DEVICE_NODE *psDeviceNode) { SYS_DATA *psSysData; @@ -1281,7 +1672,7 @@ IMG_BOOL IMG_CALLCONV PVRSRVDeviceLISR(PVRSRV_DEVICE_NODE *psDeviceNode) } psSysData = psDeviceNode->psSysData; - + /* query the SOC/system to see whether this device was the source of the interrupt */ ui32InterruptSource = SysGetInterruptSource(psSysData, psDeviceNode); if(ui32InterruptSource & psDeviceNode->ui32SOCInterruptBit) { @@ -1315,34 +1706,50 @@ static IMG_VOID PVRSRVSystemLISR_ForEachVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, v { if((*psDeviceNode->pfnDeviceISR)(psDeviceNode->pvISRData)) { - + /* Record if serviced any interrupts. */ *pbStatus = IMG_TRUE; } - + /* Combine the SOC clear bits. */ *pui32ClearInterrupts |= psDeviceNode->ui32SOCInterruptBit; } } } +/*! +****************************************************************************** + + @Function PVRSRVSystemLISR + + @Description + OS-independent System Low-level Interrupt Service Routine + + @Input pvSysData + + @Return IMG_BOOL : Whether any interrupts were serviced + +******************************************************************************/ IMG_BOOL IMG_CALLCONV PVRSRVSystemLISR(IMG_VOID *pvSysData) { SYS_DATA *psSysData = pvSysData; IMG_BOOL bStatus = IMG_FALSE; IMG_UINT32 ui32InterruptSource; IMG_UINT32 ui32ClearInterrupts = 0; +/* PVRSRV_DEVICE_NODE *psDeviceNode;*/ + if(!psSysData) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVSystemLISR: Invalid params\n")); +/* goto out; */ } else { - + /* query SOC for source of interrupts */ ui32InterruptSource = SysGetInterruptSource(psSysData, IMG_NULL); - + /* only proceed if PVR interrupts */ if(ui32InterruptSource) { - + /* traverse the devices' ISR handlers */ List_PVRSRV_DEVICE_NODE_ForEach_va(psSysData->psDeviceNodeList, &PVRSRVSystemLISR_ForEachVaCb, &bStatus, @@ -1351,6 +1758,7 @@ IMG_BOOL IMG_CALLCONV PVRSRVSystemLISR(IMG_VOID *pvSysData) SysClearInterrupts(psSysData, ui32ClearInterrupts); } +/*out:*/ } return bStatus; } @@ -1364,9 +1772,21 @@ static IMG_VOID PVRSRVMISR_ForEachCb(PVRSRV_DEVICE_NODE *psDeviceNode) } } +/*! +****************************************************************************** + + @Function PVRSRVMISR + + @Input pvSysData + + @Description + OS-independent Medium-level Interrupt Service Routine + +******************************************************************************/ IMG_VOID IMG_CALLCONV PVRSRVMISR(IMG_VOID *pvSysData) { SYS_DATA *psSysData = pvSysData; +/* PVRSRV_DEVICE_NODE *psDeviceNode; */ #ifdef SUPPORT_DRI_DRM_EXTERNAL omap_gem_op_update(); @@ -1378,17 +1798,17 @@ IMG_VOID IMG_CALLCONV PVRSRVMISR(IMG_VOID *pvSysData) return; } - + /* Traverse the devices' MISR handlers. */ List_PVRSRV_DEVICE_NODE_ForEach(psSysData->psDeviceNodeList, &PVRSRVMISR_ForEachCb); - + /* Process the queues. */ if (PVRSRVProcessQueues(IMG_FALSE) == PVRSRV_ERROR_PROCESSING_BLOCKED) { PVRSRVProcessQueues(IMG_FALSE); } - + /* signal global event object */ if (psSysData->psGlobalEventObject) { IMG_HANDLE hOSEventKM = psSysData->psGlobalEventObject->hOSEventKM; @@ -1400,6 +1820,18 @@ IMG_VOID IMG_CALLCONV PVRSRVMISR(IMG_VOID *pvSysData) } +/*! +****************************************************************************** + + @Function PVRSRVProcessConnect + + @Description Inform services that a process has connected. + + @Input ui32PID - process ID + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR IMG_CALLCONV PVRSRVProcessConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flags) { @@ -1407,6 +1839,18 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVProcessConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui } +/*! +****************************************************************************** + + @Function PVRSRVProcessDisconnect + + @Description Inform services that a process has disconnected. + + @Input ui32PID - process ID + + @Return IMG_VOID + +******************************************************************************/ IMG_EXPORT IMG_VOID IMG_CALLCONV PVRSRVProcessDisconnect(IMG_UINT32 ui32PID) { @@ -1414,6 +1858,20 @@ IMG_VOID IMG_CALLCONV PVRSRVProcessDisconnect(IMG_UINT32 ui32PID) } +/*! +****************************************************************************** + + @Function PVRSRVSaveRestoreLiveSegments + + @Input pArena - the arena the segment was originally allocated from. + pbyBuffer - the system memory buffer set to null to get the size needed. + puiBufSize - size of system memory buffer. + bSave - IMG_TRUE if a save is required + + @Description + Function to save or restore Resources Live segments + +******************************************************************************/ PVRSRV_ERROR IMG_CALLCONV PVRSRVSaveRestoreLiveSegments(IMG_HANDLE hArena, IMG_PBYTE pbyBuffer, IMG_SIZE_T *puiBufSize, IMG_BOOL bSave) { @@ -1430,12 +1888,12 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVSaveRestoreLiveSegments(IMG_HANDLE hArena, IMG_P sSegDetails.sCpuPhyAddr.uiAddr = 0; sSegDetails.hSegment = 0; - + /* walk the arena segments and write live one to the buffer */ while (RA_GetNextLiveSegment(hArena, &sSegDetails)) { if (pbyBuffer == IMG_NULL) { - + /* calc buffer required */ uiBytesSaved += sizeof(sSegDetails.uiSize) + sSegDetails.uiSize; } else @@ -1447,7 +1905,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVSaveRestoreLiveSegments(IMG_HANDLE hArena, IMG_P PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVSaveRestoreLiveSegments: Base %08x size %08x", sSegDetails.sCpuPhyAddr.uiAddr, sSegDetails.uiSize)); - + /* Map the device's local memory area onto the host. */ pvLocalMemCPUVAddr = OSMapPhysToLin(sSegDetails.sCpuPhyAddr, sSegDetails.uiSize, PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED, @@ -1460,7 +1918,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVSaveRestoreLiveSegments(IMG_HANDLE hArena, IMG_P if (bSave) { - + /* write segment size then segment data */ OSMemCopy(pbyBuffer, &sSegDetails.uiSize, sizeof(sSegDetails.uiSize)); pbyBuffer += sizeof(sSegDetails.uiSize); @@ -1470,7 +1928,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVSaveRestoreLiveSegments(IMG_HANDLE hArena, IMG_P else { IMG_UINT32 uiSize; - + /* reag segment size and validate */ OSMemCopy(&uiSize, pbyBuffer, sizeof(sSegDetails.uiSize)); if (uiSize != sSegDetails.uiSize) @@ -1505,10 +1963,28 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVSaveRestoreLiveSegments(IMG_HANDLE hArena, IMG_P } +/*! + ****************************************************************************** + + @Function PVRSRVGetErrorStringKM + + @Description Returns a text string relating to the PVRSRV_ERROR enum. + + @Note case statement used rather than an indexed arrary to ensure text is + synchronised with the correct enum + + @Input eError : PVRSRV_ERROR enum + + @Return const IMG_CHAR * : Text string + + @Note Must be kept in sync with servicesext.h + +******************************************************************************/ + IMG_EXPORT const IMG_CHAR *PVRSRVGetErrorStringKM(PVRSRV_ERROR eError) { - +/* PRQA S 5087 1 */ /* include file required here */ #include "pvrsrv_errors.h" } @@ -1516,23 +1992,52 @@ static IMG_VOID PVRSRVCommandCompleteCallbacks_ForEachCb(PVRSRV_DEVICE_NODE *psD { if(psDeviceNode->pfnDeviceCommandComplete != IMG_NULL) { - + /* Call the device's callback function. */ (*psDeviceNode->pfnDeviceCommandComplete)(psDeviceNode); } } +/*! +****************************************************************************** + + @Function PVRSRVScheduleDeviceCallbacks + + @Description Schedule all device callbacks + + @Return IMG_VOID + +******************************************************************************/ IMG_VOID PVRSRVScheduleDeviceCallbacks(IMG_VOID) { SYS_DATA *psSysData; +/* PVRSRV_DEVICE_NODE *psDeviceNode;*/ + SysAcquireData(&psSysData); - + /*for all the device, invoke the callback function*/ List_PVRSRV_DEVICE_NODE_ForEach(psSysData->psDeviceNodeList, &PVRSRVCommandCompleteCallbacks_ForEachCb); } +/*! +****************************************************************************** + + @Function PVRSRVScheduleDevices + + @Description Schedules all Services-Managed Devices to check their pending + command queues. The intention is that ScheduleDevices be called by the + 3rd party BC driver after it has finished writing new data to its output + texture. + + @Return IMG_VOID + +******************************************************************************/ IMG_EXPORT IMG_VOID PVRSRVScheduleDevicesKM(IMG_VOID) { PVRSRVScheduleDeviceCallbacks(); } + +/***************************************************************************** + End of file (pvrsrv.c) +*****************************************************************************/ diff --git a/sgx/services4/srvkm/common/queue.c b/sgx/services4/srvkm/common/queue.c index 5a1e9b4..762c952 100644 --- a/sgx/services4/srvkm/common/queue.c +++ b/sgx/services4/srvkm/common/queue.c @@ -1,41 +1,73 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Kernel side command queue functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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 "services_headers.h" +#include "pvr_bridge_km.h" #include "lists.h" #include "ttrace.h" +/* + * The number of commands of each type which can be in flight at once. + */ +#if defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED) +#define DC_NUM_COMMANDS_PER_TYPE 2 +#else #define DC_NUM_COMMANDS_PER_TYPE 1 - +#endif + +/* + * List of private command processing function pointer tables and command + * complete tables for a device in the system. + * Each table is allocated when the device registers its private command + * processing functions. + */ typedef struct _DEVICE_COMMAND_DATA_ { PFN_CMD_PROC pfnCmdProc; PCOMMAND_COMPLETE_DATA apsCmdCompleteData[DC_NUM_COMMANDS_PER_TYPE]; IMG_UINT32 ui32CCBOffset; + IMG_UINT32 ui32MaxDstSyncCount; /*!< Maximum number of dest syncs */ + IMG_UINT32 ui32MaxSrcSyncCount; /*!< Maximum number of source syncs */ } DEVICE_COMMAND_DATA; @@ -43,6 +75,15 @@ typedef struct _DEVICE_COMMAND_DATA_ #include "proc.h" +/***************************************************************************** + FUNCTION : ProcSeqShowQueue + + PURPOSE : Print the content of queue element to /proc file + (See env/linux/proc.c:CreateProcReadEntrySeq) + + PARAMETERS : sfile - /proc seq_file + el - Element to print +*****************************************************************************/ void ProcSeqShowQueue(struct seq_file *sfile,void* el) { PVRSRV_QUEUE_INFO *psQueue = (PVRSRV_QUEUE_INFO*)el; @@ -83,16 +124,16 @@ void ProcSeqShowQueue(struct seq_file *sfile,void* el) PVRSRV_SYNC_DATA *psSyncData = psCmd->psSrcSync[i].psKernelSyncInfoKM->psSyncData; seq_printf(sfile, " Sync %u: ROP/ROC: 0x%x/0x%x WOP/WOC: 0x%x/0x%x ROC-VA: 0x%x WOC-VA: 0x%x\n", i, - psCmd->psSrcSync[i].ui32ReadOpsPending, - psSyncData->ui32ReadOpsComplete, + psCmd->psSrcSync[i].ui32ReadOps2Pending, + psSyncData->ui32ReadOps2Complete, psCmd->psSrcSync[i].ui32WriteOpsPending, psSyncData->ui32WriteOpsComplete, - psCmd->psSrcSync[i].psKernelSyncInfoKM->sReadOpsCompleteDevVAddr.uiAddr, + psCmd->psSrcSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr, psCmd->psSrcSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr); } } - + /* taken from UPDATE_QUEUE_ROFF in queue.h */ ui32ReadOffset += psCmd->uCmdSize; ui32ReadOffset &= psQueue->ui32QueueSize - 1; cmds++; @@ -104,6 +145,16 @@ void ProcSeqShowQueue(struct seq_file *sfile,void* el) } } +/***************************************************************************** + FUNCTION : ProcSeqOff2ElementQueue + + PURPOSE : Transale offset to element (/proc stuff) + + PARAMETERS : sfile - /proc seq_file + off - the offset into the buffer + + RETURNS : element to print +*****************************************************************************/ void* ProcSeqOff2ElementQueue(struct seq_file * sfile, loff_t off) { PVRSRV_QUEUE_INFO *psQueue = IMG_NULL; @@ -125,19 +176,94 @@ void* ProcSeqOff2ElementQueue(struct seq_file * sfile, loff_t off) return psQueue; } -#endif +#endif /* __linux__ && __KERNEL__ */ +/*! + * Macro to return space in given command queue + */ #define GET_SPACE_IN_CMDQ(psQueue) \ ((((psQueue)->ui32ReadOffset - (psQueue)->ui32WriteOffset) \ + ((psQueue)->ui32QueueSize - 1)) & ((psQueue)->ui32QueueSize - 1)) +/*! + * Macro to Write Offset in given command queue + */ #define UPDATE_QUEUE_WOFF(psQueue, ui32Size) \ (psQueue)->ui32WriteOffset = ((psQueue)->ui32WriteOffset + (ui32Size)) \ & ((psQueue)->ui32QueueSize - 1); +/*! + * Check if an ops complete value has gone past the pending value. + * This can happen when dummy processing multiple operations, e.g. hardware recovery. + */ #define SYNCOPS_STALE(ui32OpsComplete, ui32OpsPending) \ ((ui32OpsComplete) >= (ui32OpsPending)) +/*! +**************************************************************************** + @Function : PVRSRVGetWriteOpsPending + + @Description : Gets the next operation to wait for in a sync object + + @Input : psSyncInfo - pointer to sync information struct + @Input : bIsReadOp - Is this a read or write op + + @Return : Next op value +*****************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(PVRSRVGetWriteOpsPending) +#endif +static INLINE +IMG_UINT32 PVRSRVGetWriteOpsPending(PVRSRV_KERNEL_SYNC_INFO *psSyncInfo, IMG_BOOL bIsReadOp) +{ + IMG_UINT32 ui32WriteOpsPending; + + if(bIsReadOp) + { + ui32WriteOpsPending = psSyncInfo->psSyncData->ui32WriteOpsPending; + } + else + { + /* + Note: This needs to be atomic and is provided the + kernel driver is single threaded (non-rentrant) + */ + ui32WriteOpsPending = psSyncInfo->psSyncData->ui32WriteOpsPending++; + } + + return ui32WriteOpsPending; +} + +/*! +***************************************************************************** + @Function : PVRSRVGetReadOpsPending + + @Description : Gets the number of pending read ops + + @Input : psSyncInfo - pointer to sync information struct + @Input : bIsReadOp - Is this a read or write op + + @Return : Next op value +*****************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(PVRSRVGetReadOpsPending) +#endif +static INLINE +IMG_UINT32 PVRSRVGetReadOpsPending(PVRSRV_KERNEL_SYNC_INFO *psSyncInfo, IMG_BOOL bIsReadOp) +{ + IMG_UINT32 ui32ReadOpsPending; + + if(bIsReadOp) + { + ui32ReadOpsPending = psSyncInfo->psSyncData->ui32ReadOps2Pending++; + } + else + { + ui32ReadOpsPending = psSyncInfo->psSyncData->ui32ReadOps2Pending; + } + + return ui32ReadOpsPending; +} static IMG_VOID QueueDumpCmdComplete(COMMAND_COMPLETE_DATA *psCmdCompleteData, IMG_UINT32 i, @@ -151,9 +277,9 @@ static IMG_VOID QueueDumpCmdComplete(COMMAND_COMPLETE_DATA *psCmdCompleteData, { PVR_LOG(("\t%s %u: ROC DevVAddr:0x%X ROP:0x%x ROC:0x%x, WOC DevVAddr:0x%X WOP:0x%x WOC:0x%x", bIsSrc ? "SRC" : "DEST", i, - psSyncObject[i].psKernelSyncInfoKM->sReadOpsCompleteDevVAddr.uiAddr, - psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32ReadOpsPending, - psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32ReadOpsComplete, + psSyncObject[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr, + psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32ReadOps2Pending, + psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32ReadOps2Complete, psSyncObject[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr, psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32WriteOpsPending, psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32WriteOpsComplete)) @@ -218,6 +344,10 @@ IMG_VOID QueueDumpDebugInfo(IMG_VOID) } +/***************************************************************************** + Kernel-side functions of User->Kernel transitions +******************************************************************************/ + static IMG_SIZE_T NearestPower2(IMG_SIZE_T ui32Value) { IMG_SIZE_T ui32Temp, ui32Result = 1; @@ -236,6 +366,22 @@ static IMG_SIZE_T NearestPower2(IMG_SIZE_T ui32Value) } +/*! +****************************************************************************** + + @Function PVRSRVCreateCommandQueueKM + + @Description + Creates a new command queue into which render/blt commands etc can be + inserted. + + @Input ui32QueueSize : + + @Output ppsQueueInfo : + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateCommandQueueKM(IMG_SIZE_T ui32QueueSize, PVRSRV_QUEUE_INFO **ppsQueueInfo) @@ -248,7 +394,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateCommandQueueKM(IMG_SIZE_T ui32QueueSize, SysAcquireData(&psSysData); - + /* allocate an internal queue info structure */ eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_QUEUE_INFO), (IMG_VOID **)&psQueueInfo, &hMemBlock, @@ -263,7 +409,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateCommandQueueKM(IMG_SIZE_T ui32QueueSize, psQueueInfo->hMemBlock[0] = hMemBlock; psQueueInfo->ui32ProcessID = OSGetCurrentProcessIDKM(); - + /* allocate the command queue buffer - allow for overrun */ eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, ui32Power2QueueSize + PVRSRV_MAX_CMD_SIZE, &psQueueInfo->pvLinQueueKM, &hMemBlock, @@ -277,13 +423,13 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateCommandQueueKM(IMG_SIZE_T ui32QueueSize, psQueueInfo->hMemBlock[1] = hMemBlock; psQueueInfo->pvLinQueueUM = psQueueInfo->pvLinQueueKM; - + /* Sanity check: Should be zeroed by OSMemSet */ PVR_ASSERT(psQueueInfo->ui32ReadOffset == 0); PVR_ASSERT(psQueueInfo->ui32WriteOffset == 0); psQueueInfo->ui32QueueSize = ui32Power2QueueSize; - + /* if this is the first q, create a lock resource for the q list */ if (psSysData->psQueueList == IMG_NULL) { eError = OSCreateResource(&psSysData->sQProcessResource); @@ -293,7 +439,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateCommandQueueKM(IMG_SIZE_T ui32QueueSize, } } - + /* Ensure we don't corrupt queue list, by blocking access */ eError = OSLockResource(&psSysData->sQProcessResource, KERNEL_ID); if (eError != PVRSRV_OK) @@ -331,13 +477,25 @@ ErrorExit: sizeof(PVRSRV_QUEUE_INFO), psQueueInfo, psQueueInfo->hMemBlock[0]); - + /*not nulling pointer, out of scope*/ } return eError; } +/*! +****************************************************************************** + + @Function PVRSRVDestroyCommandQueueKM + + @Description Destroys a command queue + + @Input psQueueInfo : + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroyCommandQueueKM(PVRSRV_QUEUE_INFO *psQueueInfo) { @@ -350,7 +508,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroyCommandQueueKM(PVRSRV_QUEUE_INFO *psQueue psQueue = psSysData->psQueueList; - + /* PRQA S 3415,4109 1 */ /* macro format critical - leave alone */ LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { if(psQueueInfo->ui32ReadOffset == psQueueInfo->ui32WriteOffset) @@ -363,13 +521,14 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroyCommandQueueKM(PVRSRV_QUEUE_INFO *psQueue if (bTimeout) { - + /* The command queue could not be flushed within the timeout period. + Allow the queue to be destroyed before returning the error code. */ PVR_DPF((PVR_DBG_ERROR,"PVRSRVDestroyCommandQueueKM : Failed to empty queue")); eError = PVRSRV_ERROR_CANNOT_FLUSH_QUEUE; goto ErrorExit; } - + /* Ensure we don't corrupt queue list, by blocking access */ eError = OSLockResource(&psSysData->sQProcessResource, KERNEL_ID); if (eError != PVRSRV_OK) @@ -390,8 +549,8 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroyCommandQueueKM(PVRSRV_QUEUE_INFO *psQueue sizeof(PVRSRV_QUEUE_INFO), psQueueInfo, psQueueInfo->hMemBlock[0]); - - psQueueInfo = IMG_NULL; + /* PRQA S 3199 1 */ /* see note */ + psQueueInfo = IMG_NULL; /*it's a copy on stack, but null it because the function doesn't end right here*/ } else { @@ -410,8 +569,8 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroyCommandQueueKM(PVRSRV_QUEUE_INFO *psQueue sizeof(PVRSRV_QUEUE_INFO), psQueueInfo, psQueueInfo->hMemBlock[0]); - - psQueueInfo = IMG_NULL; + /* PRQA S 3199 1 */ /* see note */ + psQueueInfo = IMG_NULL; /*it's a copy on stack, but null it because the function doesn't end right here*/ break; } psQueue = psQueue->psNextKM; @@ -429,14 +588,14 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroyCommandQueueKM(PVRSRV_QUEUE_INFO *psQueue } } - + /* unlock the Q list lock resource */ eError = OSUnlockResource(&psSysData->sQProcessResource, KERNEL_ID); if (eError != PVRSRV_OK) { goto ErrorExit; } - + /* if the Q list is now empty, destroy the Q list lock resource */ if (psSysData->psQueueList == IMG_NULL) { eError = OSDestroyResource(&psSysData->sQProcessResource); @@ -452,6 +611,20 @@ ErrorExit: } +/*! +***************************************************************************** + + @Function : PVRSRVGetQueueSpaceKM + + @Description : Waits for queue access rights and checks for available space in + queue for task param structure + + @Input : psQueue - pointer to queue information struct + @Input : ui32ParamSize - size of task data structure + @Output : ppvSpace + + @Return : PVRSRV_ERROR +*****************************************************************************/ IMG_EXPORT PVRSRV_ERROR IMG_CALLCONV PVRSRVGetQueueSpaceKM(PVRSRV_QUEUE_INFO *psQueue, IMG_SIZE_T ui32ParamSize, @@ -459,7 +632,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetQueueSpaceKM(PVRSRV_QUEUE_INFO *psQueue, { IMG_BOOL bTimeout = IMG_TRUE; - + /* round to 4byte units */ ui32ParamSize = (ui32ParamSize+3) & 0xFFFFFFFC; if (ui32ParamSize > PVRSRV_MAX_CMD_SIZE) @@ -468,7 +641,7 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetQueueSpaceKM(PVRSRV_QUEUE_INFO *psQueue, return PVRSRV_ERROR_CMD_TOO_BIG; } - + /* PRQA S 3415,4109 1 */ /* macro format critical - leave alone */ LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { if (GET_SPACE_IN_CMDQ(psQueue) > ui32ParamSize) @@ -494,6 +667,26 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVGetQueueSpaceKM(PVRSRV_QUEUE_INFO *psQueue, } +/*! +***************************************************************************** + @Function PVRSRVInsertCommandKM + + @Description : + command insertion utility + - waits for space in the queue for a new command + - fills in generic command information + - returns a pointer to the caller who's expected to then fill + in the private data. + The caller should follow PVRSRVInsertCommand with PVRSRVSubmitCommand + which will update the queue's write offset so the command can be + executed. + + @Input psQueue : pointer to queue information struct + + @Output ppvCmdData : holds pointer to space in queue for private cmd data + + @Return PVRSRV_ERROR +*****************************************************************************/ IMG_EXPORT PVRSRV_ERROR IMG_CALLCONV PVRSRVInsertCommandKM(PVRSRV_QUEUE_INFO *psQueue, PVRSRV_COMMAND **ppsCommand, @@ -503,22 +696,37 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVInsertCommandKM(PVRSRV_QUEUE_INFO *psQueue, PVRSRV_KERNEL_SYNC_INFO *apsDstSync[], IMG_UINT32 ui32SrcSyncCount, PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[], - IMG_SIZE_T ui32DataByteSize ) + IMG_SIZE_T ui32DataByteSize, + PFN_QUEUE_COMMAND_COMPLETE pfnCommandComplete, + IMG_HANDLE hCallbackData) { PVRSRV_ERROR eError; PVRSRV_COMMAND *psCommand; IMG_SIZE_T ui32CommandSize; IMG_UINT32 i; + SYS_DATA *psSysData; + DEVICE_COMMAND_DATA *psDeviceCommandData; - + /* Check that we've got enough space in our command complete data for this command */ + SysAcquireData(&psSysData); + psDeviceCommandData = psSysData->apsDeviceCommandData[ui32DevIndex]; + + if ((psDeviceCommandData[CommandType].ui32MaxDstSyncCount < ui32DstSyncCount) || + (psDeviceCommandData[CommandType].ui32MaxSrcSyncCount < ui32SrcSyncCount)) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVInsertCommandKM: Too many syncs")); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + /* Round up to nearest 32 bit size so pointer arithmetic works */ ui32DataByteSize = (ui32DataByteSize + 3UL) & ~3UL; - + /* calc. command size */ ui32CommandSize = sizeof(PVRSRV_COMMAND) + ((ui32DstSyncCount + ui32SrcSyncCount) * sizeof(PVRSRV_SYNC_OBJECT)) + ui32DataByteSize; - + /* wait for space in queue */ eError = PVRSRVGetQueueSpaceKM (psQueue, ui32CommandSize, (IMG_VOID**)&psCommand); if(eError != PVRSRV_OK) { @@ -527,14 +735,14 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVInsertCommandKM(PVRSRV_QUEUE_INFO *psQueue, psCommand->ui32ProcessID = OSGetCurrentProcessIDKM(); - - psCommand->uCmdSize = ui32CommandSize; + /* setup the command */ + psCommand->uCmdSize = ui32CommandSize; /* this may change if cmd shrinks */ psCommand->ui32DevIndex = ui32DevIndex; psCommand->CommandType = CommandType; psCommand->ui32DstSyncCount = ui32DstSyncCount; psCommand->ui32SrcSyncCount = ui32SrcSyncCount; - - + /* override QAC warning about stricter pointers */ + /* PRQA S 3305 END_PTR_ASSIGNMENTS */ psCommand->psDstSync = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psCommand) + sizeof(PVRSRV_COMMAND)); @@ -543,13 +751,18 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVInsertCommandKM(PVRSRV_QUEUE_INFO *psQueue, psCommand->pvData = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psCommand->psSrcSync) + (ui32SrcSyncCount * sizeof(PVRSRV_SYNC_OBJECT))); - psCommand->uDataSize = ui32DataByteSize; +/* PRQA L:END_PTR_ASSIGNMENTS */ + + psCommand->uDataSize = ui32DataByteSize;/* this may change if cmd shrinks */ + + psCommand->pfnCommandComplete = pfnCommandComplete; + psCommand->hCallbackData = hCallbackData; PVR_TTRACE(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_CMD_START, QUEUE_TOKEN_INSERTKM); PVR_TTRACE_UI32(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_NONE, QUEUE_TOKEN_COMMAND_TYPE, CommandType); - + /* setup dst sync objects and their sync dependencies */ for (i=0; i<ui32DstSyncCount; i++) { PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_QUEUE, QUEUE_TOKEN_DST_SYNC, @@ -557,16 +770,18 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVInsertCommandKM(PVRSRV_QUEUE_INFO *psQueue, psCommand->psDstSync[i].psKernelSyncInfoKM = apsDstSync[i]; psCommand->psDstSync[i].ui32WriteOpsPending = PVRSRVGetWriteOpsPending(apsDstSync[i], IMG_FALSE); - psCommand->psDstSync[i].ui32ReadOpsPending = PVRSRVGetReadOpsPending(apsDstSync[i], IMG_FALSE); + psCommand->psDstSync[i].ui32ReadOps2Pending = PVRSRVGetReadOpsPending(apsDstSync[i], IMG_FALSE); + + PVRSRVKernelSyncInfoIncRef(apsDstSync[i], IMG_NULL); PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVInsertCommandKM: Dst %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x", - i, psCommand->psDstSync[i].psKernelSyncInfoKM->sReadOpsCompleteDevVAddr.uiAddr, + i, psCommand->psDstSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr, psCommand->psDstSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr, - psCommand->psDstSync[i].ui32ReadOpsPending, + psCommand->psDstSync[i].ui32ReadOps2Pending, psCommand->psDstSync[i].ui32WriteOpsPending)); } - + /* setup src sync objects and their sync dependencies */ for (i=0; i<ui32SrcSyncCount; i++) { PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_QUEUE, QUEUE_TOKEN_DST_SYNC, @@ -574,30 +789,44 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVInsertCommandKM(PVRSRV_QUEUE_INFO *psQueue, psCommand->psSrcSync[i].psKernelSyncInfoKM = apsSrcSync[i]; psCommand->psSrcSync[i].ui32WriteOpsPending = PVRSRVGetWriteOpsPending(apsSrcSync[i], IMG_TRUE); - psCommand->psSrcSync[i].ui32ReadOpsPending = PVRSRVGetReadOpsPending(apsSrcSync[i], IMG_TRUE); + psCommand->psSrcSync[i].ui32ReadOps2Pending = PVRSRVGetReadOpsPending(apsSrcSync[i], IMG_TRUE); + + PVRSRVKernelSyncInfoIncRef(apsSrcSync[i], IMG_NULL); PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVInsertCommandKM: Src %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x", - i, psCommand->psSrcSync[i].psKernelSyncInfoKM->sReadOpsCompleteDevVAddr.uiAddr, + i, psCommand->psSrcSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr, psCommand->psSrcSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr, - psCommand->psSrcSync[i].ui32ReadOpsPending, + psCommand->psSrcSync[i].ui32ReadOps2Pending, psCommand->psSrcSync[i].ui32WriteOpsPending)); } PVR_TTRACE(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_CMD_END, QUEUE_TOKEN_INSERTKM); - + /* return pointer to caller to fill out private data */ *ppsCommand = psCommand; return PVRSRV_OK; } +/*! +******************************************************************************* + @Function : PVRSRVSubmitCommandKM + + @Description : + updates the queue's write offset so the command can be executed. + + @Input : psQueue - queue command is in + @Input : psCommand + + @Return : PVRSRV_ERROR +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR IMG_CALLCONV PVRSRVSubmitCommandKM(PVRSRV_QUEUE_INFO *psQueue, PVRSRV_COMMAND *psCommand) { - - - + /* override QAC warnings about stricter pointers */ + /* PRQA S 3305 END_PTR_ASSIGNMENTS2 */ + /* patch pointers in the command to be kernel pointers */ if (psCommand->ui32DstSyncCount > 0) { psCommand->psDstSync = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psQueue->pvLinQueueKM) @@ -616,14 +845,84 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVSubmitCommandKM(PVRSRV_QUEUE_INFO *psQueue, + (psCommand->ui32DstSyncCount * sizeof(PVRSRV_SYNC_OBJECT)) + (psCommand->ui32SrcSyncCount * sizeof(PVRSRV_SYNC_OBJECT))); - +/* PRQA L:END_PTR_ASSIGNMENTS2 */ + + /* update write offset before releasing access lock */ UPDATE_QUEUE_WOFF(psQueue, psCommand->uCmdSize); return PVRSRV_OK; } +/*! +****************************************************************************** + @Function CheckIfSyncIsQueued + @Description Check if the specificed sync object is already queued and + can safely be given to the display controller. + This check is required as a 3rd party displayclass device can + have several flips "in flight" and we need to ensure that we + keep their pipeline full and don't deadlock waiting for them + to complete an operation on a surface. + + @Input psSysData : system data + @Input psCmdData : COMMAND_COMPLETE_DATA structure + + @Return PVRSRV_ERROR + +******************************************************************************/ +static +PVRSRV_ERROR CheckIfSyncIsQueued(PVRSRV_SYNC_OBJECT *psSync, COMMAND_COMPLETE_DATA *psCmdData) +{ + IMG_UINT32 k; + + if (psCmdData->bInUse) + { + for (k=0;k<psCmdData->ui32SrcSyncCount;k++) + { + if (psSync->psKernelSyncInfoKM == psCmdData->psSrcSync[k].psKernelSyncInfoKM) + { + PVRSRV_SYNC_DATA *psSyncData = psSync->psKernelSyncInfoKM->psSyncData; + IMG_UINT32 ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete; + + /* + We still need to ensure that we don't we don't give a command + to the display controller if writes are outstanding on it + */ + if (ui32WriteOpsComplete == psSync->ui32WriteOpsPending) + { + return PVRSRV_OK; + } + else + { + if (SYNCOPS_STALE(ui32WriteOpsComplete, psSync->ui32WriteOpsPending)) + { + PVR_DPF((PVR_DBG_WARNING, + "CheckIfSyncIsQueued: Stale syncops psSyncData:0x%x ui32WriteOpsComplete:0x%x ui32WriteOpsPending:0x%x", + (IMG_UINTPTR_T)psSyncData, ui32WriteOpsComplete, psSync->ui32WriteOpsPending)); + return PVRSRV_OK; + } + } + } + } + } + return PVRSRV_ERROR_FAILED_DEPENDENCIES; +} + +/*! +****************************************************************************** + + @Function PVRSRVProcessCommand + + @Description Tries to process a command + + @Input psSysData : system data + @Input psCommand : PVRSRV_COMMAND structure + @Input bFlush : Check for stale dependencies (only used for HW recovery) + + @Return PVRSRV_ERROR + +******************************************************************************/ static PVRSRV_ERROR PVRSRVProcessCommand(SYS_DATA *psSysData, PVRSRV_COMMAND *psCommand, @@ -639,7 +938,7 @@ PVRSRV_ERROR PVRSRVProcessCommand(SYS_DATA *psSysData, DEVICE_COMMAND_DATA *psDeviceCommandData; IMG_UINT32 ui32CCBOffset; - + /* satisfy sync dependencies on the DST(s) */ psWalkerObj = psCommand->psDstSync; psEndObj = psWalkerObj + psCommand->ui32DstSyncCount; while (psWalkerObj < psEndObj) @@ -647,14 +946,14 @@ PVRSRV_ERROR PVRSRVProcessCommand(SYS_DATA *psSysData, PVRSRV_SYNC_DATA *psSyncData = psWalkerObj->psKernelSyncInfoKM->psSyncData; ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete; - ui32ReadOpsComplete = psSyncData->ui32ReadOpsComplete; - + ui32ReadOpsComplete = psSyncData->ui32ReadOps2Complete; + /* fail if reads or writes are not up to date */ if ((ui32WriteOpsComplete != psWalkerObj->ui32WriteOpsPending) - || (ui32ReadOpsComplete != psWalkerObj->ui32ReadOpsPending)) + || (ui32ReadOpsComplete != psWalkerObj->ui32ReadOps2Pending)) { if (!bFlush || !SYNCOPS_STALE(ui32WriteOpsComplete, psWalkerObj->ui32WriteOpsPending) || - !SYNCOPS_STALE(ui32ReadOpsComplete, psWalkerObj->ui32ReadOpsPending)) + !SYNCOPS_STALE(ui32ReadOpsComplete, psWalkerObj->ui32ReadOps2Pending)) { return PVRSRV_ERROR_FAILED_DEPENDENCIES; } @@ -663,22 +962,22 @@ PVRSRV_ERROR PVRSRVProcessCommand(SYS_DATA *psSysData, psWalkerObj++; } - + /* satisfy sync dependencies on the SRC(s) */ psWalkerObj = psCommand->psSrcSync; psEndObj = psWalkerObj + psCommand->ui32SrcSyncCount; while (psWalkerObj < psEndObj) { PVRSRV_SYNC_DATA *psSyncData = psWalkerObj->psKernelSyncInfoKM->psSyncData; - ui32ReadOpsComplete = psSyncData->ui32ReadOpsComplete; + ui32ReadOpsComplete = psSyncData->ui32ReadOps2Complete; ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete; - + /* fail if writes are not up to date */ if ((ui32WriteOpsComplete != psWalkerObj->ui32WriteOpsPending) - || (ui32ReadOpsComplete != psWalkerObj->ui32ReadOpsPending)) + || (ui32ReadOpsComplete != psWalkerObj->ui32ReadOps2Pending)) { if (!bFlush && SYNCOPS_STALE(ui32WriteOpsComplete, psWalkerObj->ui32WriteOpsPending) && - SYNCOPS_STALE(ui32ReadOpsComplete, psWalkerObj->ui32ReadOpsPending)) + SYNCOPS_STALE(ui32ReadOpsComplete, psWalkerObj->ui32ReadOps2Pending)) { PVR_DPF((PVR_DBG_WARNING, "PVRSRVProcessCommand: Stale syncops psSyncData:0x%x ui32WriteOpsComplete:0x%x ui32WriteOpsPending:0x%x", @@ -687,15 +986,30 @@ PVRSRV_ERROR PVRSRVProcessCommand(SYS_DATA *psSysData, if (!bFlush || !SYNCOPS_STALE(ui32WriteOpsComplete, psWalkerObj->ui32WriteOpsPending) || - !SYNCOPS_STALE(ui32ReadOpsComplete, psWalkerObj->ui32ReadOpsPending)) + !SYNCOPS_STALE(ui32ReadOpsComplete, psWalkerObj->ui32ReadOps2Pending)) { - return PVRSRV_ERROR_FAILED_DEPENDENCIES; + IMG_UINT32 j; + PVRSRV_ERROR eError; + IMG_BOOL bFound = IMG_FALSE; + + psDeviceCommandData = psSysData->apsDeviceCommandData[psCommand->ui32DevIndex]; + for (j=0;j<DC_NUM_COMMANDS_PER_TYPE;j++) + { + eError = CheckIfSyncIsQueued(psWalkerObj, psDeviceCommandData[psCommand->CommandType].apsCmdCompleteData[j]); + + if (eError == PVRSRV_OK) + { + bFound = IMG_TRUE; + } + } + if (!bFound) + return PVRSRV_ERROR_FAILED_DEPENDENCIES; } } psWalkerObj++; } - + /* validate device type */ if (psCommand->ui32DevIndex >= SYS_DEVICE_COUNT) { PVR_DPF((PVR_DBG_ERROR, @@ -704,70 +1018,74 @@ PVRSRV_ERROR PVRSRVProcessCommand(SYS_DATA *psSysData, return PVRSRV_ERROR_INVALID_PARAMS; } - + /* fish out the appropriate storage structure for the duration of the command */ psDeviceCommandData = psSysData->apsDeviceCommandData[psCommand->ui32DevIndex]; ui32CCBOffset = psDeviceCommandData[psCommand->CommandType].ui32CCBOffset; psCmdCompleteData = psDeviceCommandData[psCommand->CommandType].apsCmdCompleteData[ui32CCBOffset]; if (psCmdCompleteData->bInUse) { - + /* can use this to protect against concurrent execution of same command */ return PVRSRV_ERROR_FAILED_DEPENDENCIES; } - + /* mark the structure as in use */ psCmdCompleteData->bInUse = IMG_TRUE; - + /* copy src updates over */ psCmdCompleteData->ui32DstSyncCount = psCommand->ui32DstSyncCount; for (i=0; i<psCommand->ui32DstSyncCount; i++) { psCmdCompleteData->psDstSync[i] = psCommand->psDstSync[i]; PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVProcessCommand: Dst %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x (CCB:%u)", - i, psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sReadOpsCompleteDevVAddr.uiAddr, + i, psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr, psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr, - psCmdCompleteData->psDstSync[i].ui32ReadOpsPending, + psCmdCompleteData->psDstSync[i].ui32ReadOps2Pending, psCmdCompleteData->psDstSync[i].ui32WriteOpsPending, ui32CCBOffset)); } + psCmdCompleteData->pfnCommandComplete = psCommand->pfnCommandComplete; + psCmdCompleteData->hCallbackData = psCommand->hCallbackData; - + /* copy dst updates over */ psCmdCompleteData->ui32SrcSyncCount = psCommand->ui32SrcSyncCount; for (i=0; i<psCommand->ui32SrcSyncCount; i++) { psCmdCompleteData->psSrcSync[i] = psCommand->psSrcSync[i]; PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVProcessCommand: Src %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x (CCB:%u)", - i, psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sReadOpsCompleteDevVAddr.uiAddr, + i, psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr, psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr, - psCmdCompleteData->psSrcSync[i].ui32ReadOpsPending, + psCmdCompleteData->psSrcSync[i].ui32ReadOps2Pending, psCmdCompleteData->psSrcSync[i].ui32WriteOpsPending, ui32CCBOffset)); } - - - - - - - - - - + /* + call the cmd specific handler: + it should: + - check the cmd specific dependencies + - setup private cmd complete structure + - execute cmd on HW + - store psCmdCompleteData `cookie' and later pass as + argument to Generic Command Complete Callback + + n.b. ui32DataSize (packet size) is useful for packet validation + */ if (psDeviceCommandData[psCommand->CommandType].pfnCmdProc((IMG_HANDLE)psCmdCompleteData, (IMG_UINT32)psCommand->uDataSize, psCommand->pvData) == IMG_FALSE) { - - - + /* + clean-up: + free cmd complete structure + */ psCmdCompleteData->bInUse = IMG_FALSE; eError = PVRSRV_ERROR_CMD_NOT_PROCESSED; } - + /* Increment the CCB offset */ psDeviceCommandData[psCommand->CommandType].ui32CCBOffset = (ui32CCBOffset + 1) % DC_NUM_COMMANDS_PER_TYPE; return eError; @@ -783,19 +1101,37 @@ static IMG_VOID PVRSRVProcessQueues_ForEachCb(PVRSRV_DEVICE_NODE *psDeviceNode) } } +/*! +****************************************************************************** + + @Function PVRSRVProcessQueues + + @Description Tries to process a command from each Q + + @input ui32CallerID - used to distinguish between async ISR/DPC type calls + the synchronous services driver + @input bFlush - flush commands with stale dependencies (only used for HW recovery) + + @Return PVRSRV_ERROR + +******************************************************************************/ + IMG_EXPORT PVRSRV_ERROR PVRSRVProcessQueues(IMG_BOOL bFlush) { PVRSRV_QUEUE_INFO *psQueue; SYS_DATA *psSysData; PVRSRV_COMMAND *psCommand; - SysAcquireData(&psSysData); +/* PVRSRV_DEVICE_NODE *psDeviceNode;*/ - + SysAcquireData(&psSysData); + /* Ensure we don't corrupt queue list, by blocking access. This is required for OSs where + multiple ISR threads may exist simultaneously (eg WinXP DPC routines) + */ while (OSLockResource(&psSysData->sQProcessResource, ISR_ID) != PVRSRV_OK) { - OSSleepms(1); + OSWaitus(1); }; psQueue = psSysData->psQueueList; @@ -818,7 +1154,7 @@ PVRSRV_ERROR PVRSRVProcessQueues(IMG_BOOL bFlush) if (PVRSRVProcessCommand(psSysData, psCommand, bFlush) == PVRSRV_OK) { - + /* processed cmd so update queue */ UPDATE_QUEUE_ROFF(psQueue, psCommand->uCmdSize) continue; } @@ -833,7 +1169,7 @@ PVRSRV_ERROR PVRSRVProcessQueues(IMG_BOOL bFlush) PVRSRVSetDCState(DC_STATE_NO_FLUSH_COMMANDS); } - + /* Re-process command complete handlers if necessary. */ List_PVRSRV_DEVICE_NODE_ForEach(psSysData->psDeviceNodeList, &PVRSRVProcessQueues_ForEachCb); @@ -843,6 +1179,19 @@ PVRSRV_ERROR PVRSRVProcessQueues(IMG_BOOL bFlush) } #if defined(SUPPORT_CUSTOM_SWAP_OPERATIONS) +/*! +****************************************************************************** + + @Function PVRSRVCommandCompleteKM + + @Description Updates non-private command complete sync objects + + @Input hCmdCookie : command cookie + @Input bScheduleMISR : obsolete parameter + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_INTERNAL IMG_VOID PVRSRVFreeCommandCompletePacketKM(IMG_HANDLE hCmdCookie, IMG_BOOL bScheduleMISR) @@ -850,23 +1199,36 @@ IMG_VOID PVRSRVFreeCommandCompletePacketKM(IMG_HANDLE hCmdCookie, COMMAND_COMPLETE_DATA *psCmdCompleteData = (COMMAND_COMPLETE_DATA *)hCmdCookie; SYS_DATA *psSysData; + PVR_UNREFERENCED_PARAMETER(bScheduleMISR); + SysAcquireData(&psSysData); - + /* free command complete storage */ psCmdCompleteData->bInUse = IMG_FALSE; - + /* FIXME: This may cause unrelated devices to be woken up. */ PVRSRVScheduleDeviceCallbacks(); - if(bScheduleMISR) - { - OSScheduleMISR(psSysData); - } + /* the MISR is always scheduled, regardless of bScheduleMISR */ + OSScheduleMISR(psSysData); } -#endif +#endif /* (SUPPORT_CUSTOM_SWAP_OPERATIONS) */ + + +/*! +****************************************************************************** + + @Function PVRSRVCommandCompleteKM + + @Description Updates non-private command complete sync objects + @Input hCmdCookie : command cookie + @Input bScheduleMISR : boolean to schedule MISR + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT IMG_VOID PVRSRVCommandCompleteKM(IMG_HANDLE hCmdCookie, IMG_BOOL bScheduleMISR) @@ -880,45 +1242,54 @@ IMG_VOID PVRSRVCommandCompleteKM(IMG_HANDLE hCmdCookie, PVR_TTRACE(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_CMD_COMP_START, QUEUE_TOKEN_COMMAND_COMPLETE); - + /* update DST(s) syncs */ for (i=0; i<psCmdCompleteData->ui32DstSyncCount; i++) { psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->psSyncData->ui32WriteOpsComplete++; + PVRSRVKernelSyncInfoDecRef(psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM, IMG_NULL); + PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_QUEUE, QUEUE_TOKEN_UPDATE_DST, psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM, PVRSRV_SYNCOP_COMPLETE); PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVCommandCompleteKM: Dst %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x", - i, psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sReadOpsCompleteDevVAddr.uiAddr, + i, psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr, psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr, - psCmdCompleteData->psDstSync[i].ui32ReadOpsPending, + psCmdCompleteData->psDstSync[i].ui32ReadOps2Pending, psCmdCompleteData->psDstSync[i].ui32WriteOpsPending)); } - + /* update SRC(s) syncs */ for (i=0; i<psCmdCompleteData->ui32SrcSyncCount; i++) { - psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->psSyncData->ui32ReadOpsComplete++; + psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->psSyncData->ui32ReadOps2Complete++; + + PVRSRVKernelSyncInfoDecRef(psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM, IMG_NULL); PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_QUEUE, QUEUE_TOKEN_UPDATE_SRC, psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM, PVRSRV_SYNCOP_COMPLETE); PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVCommandCompleteKM: Src %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x", - i, psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sReadOpsCompleteDevVAddr.uiAddr, + i, psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr, psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr, - psCmdCompleteData->psSrcSync[i].ui32ReadOpsPending, + psCmdCompleteData->psSrcSync[i].ui32ReadOps2Pending, psCmdCompleteData->psSrcSync[i].ui32WriteOpsPending)); } PVR_TTRACE(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_CMD_COMP_END, QUEUE_TOKEN_COMMAND_COMPLETE); - + if (psCmdCompleteData->pfnCommandComplete) + { + psCmdCompleteData->pfnCommandComplete(psCmdCompleteData->hCallbackData); + } + + /* free command complete storage */ psCmdCompleteData->bInUse = IMG_FALSE; - + /* FIXME: This may cause unrelated devices to be woken up. */ PVRSRVScheduleDeviceCallbacks(); if(bScheduleMISR) @@ -930,6 +1301,27 @@ IMG_VOID PVRSRVCommandCompleteKM(IMG_HANDLE hCmdCookie, +/*! +****************************************************************************** + + @Function PVRSRVRegisterCmdProcListKM + + @Description + + registers a list of private command processing functions with the Command + Queue Manager + + @Input ui32DevIndex : device index + + @Input ppfnCmdProcList : function ptr table of private command processors + + @Input ui32MaxSyncsPerCmd : max number of syncobjects used by command + + @Input ui32CmdCount : number of entries in function ptr table + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVRegisterCmdProcListKM(IMG_UINT32 ui32DevIndex, PFN_CMD_PROC *ppfnCmdProcList, @@ -943,7 +1335,7 @@ PVRSRV_ERROR PVRSRVRegisterCmdProcListKM(IMG_UINT32 ui32DevIndex, DEVICE_COMMAND_DATA *psDeviceCommandData; COMMAND_COMPLETE_DATA *psCmdCompleteData; - + /* validate device type */ if(ui32DevIndex >= SYS_DEVICE_COUNT) { PVR_DPF((PVR_DBG_ERROR, @@ -952,10 +1344,10 @@ PVRSRV_ERROR PVRSRVRegisterCmdProcListKM(IMG_UINT32 ui32DevIndex, return PVRSRV_ERROR_INVALID_PARAMS; } - + /* acquire system data structure */ SysAcquireData(&psSysData); - + /* array of pointers for each command store */ ui32AllocSize = ui32CmdCount * sizeof(*psDeviceCommandData); eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, ui32AllocSize, @@ -973,15 +1365,17 @@ PVRSRV_ERROR PVRSRVRegisterCmdProcListKM(IMG_UINT32 ui32DevIndex, { psDeviceCommandData[ui32CmdTypeCounter].pfnCmdProc = ppfnCmdProcList[ui32CmdTypeCounter]; psDeviceCommandData[ui32CmdTypeCounter].ui32CCBOffset = 0; - + psDeviceCommandData[ui32CmdTypeCounter].ui32MaxDstSyncCount = ui32MaxSyncsPerCmd[ui32CmdTypeCounter][0]; + psDeviceCommandData[ui32CmdTypeCounter].ui32MaxSrcSyncCount = ui32MaxSyncsPerCmd[ui32CmdTypeCounter][1]; for (ui32CmdCounter = 0; ui32CmdCounter < DC_NUM_COMMANDS_PER_TYPE; ui32CmdCounter++) { - - - ui32AllocSize = sizeof(COMMAND_COMPLETE_DATA) + /* + allocate storage for the sync update on command complete + */ + ui32AllocSize = sizeof(COMMAND_COMPLETE_DATA) /* space for one GENERIC_CMD_COMPLETE */ + ((ui32MaxSyncsPerCmd[ui32CmdTypeCounter][0] + ui32MaxSyncsPerCmd[ui32CmdTypeCounter][1]) - * sizeof(PVRSRV_SYNC_OBJECT)); + * sizeof(PVRSRV_SYNC_OBJECT)); /* space for max sync objects */ eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, ui32AllocSize, @@ -996,10 +1390,10 @@ PVRSRV_ERROR PVRSRVRegisterCmdProcListKM(IMG_UINT32 ui32DevIndex, psDeviceCommandData[ui32CmdTypeCounter].apsCmdCompleteData[ui32CmdCounter] = psCmdCompleteData; - + /* clear memory */ OSMemSet(psCmdCompleteData, 0x00, ui32AllocSize); - + /* setup sync pointers */ psCmdCompleteData->psDstSync = (PVRSRV_SYNC_OBJECT*) (((IMG_UINTPTR_T)psCmdCompleteData) + sizeof(COMMAND_COMPLETE_DATA)); @@ -1015,7 +1409,7 @@ PVRSRV_ERROR PVRSRVRegisterCmdProcListKM(IMG_UINT32 ui32DevIndex, ErrorExit: - + /* clean-up if things went wrong */ if (PVRSRVRemoveCmdProcListKM(ui32DevIndex, ui32CmdCount) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, @@ -1027,6 +1421,23 @@ ErrorExit: } +/*! +****************************************************************************** + + @Function PVRSRVRemoveCmdProcListKM + + @Description + + removes a list of private command processing functions and data from the + Queue Manager + + @Input ui32DevIndex : device index + + @Input ui32CmdCount : number of entries in function ptr table + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR PVRSRVRemoveCmdProcListKM(IMG_UINT32 ui32DevIndex, IMG_UINT32 ui32CmdCount) @@ -1037,7 +1448,7 @@ PVRSRV_ERROR PVRSRVRemoveCmdProcListKM(IMG_UINT32 ui32DevIndex, COMMAND_COMPLETE_DATA *psCmdCompleteData; IMG_SIZE_T ui32AllocSize; - + /* validate device type */ if(ui32DevIndex >= SYS_DEVICE_COUNT) { PVR_DPF((PVR_DBG_ERROR, @@ -1046,7 +1457,7 @@ PVRSRV_ERROR PVRSRVRemoveCmdProcListKM(IMG_UINT32 ui32DevIndex, return PVRSRV_ERROR_INVALID_PARAMS; } - + /* acquire system data structure */ SysAcquireData(&psSysData); psDeviceCommandData = psSysData->apsDeviceCommandData[ui32DevIndex]; @@ -1058,9 +1469,10 @@ PVRSRV_ERROR PVRSRVRemoveCmdProcListKM(IMG_UINT32 ui32DevIndex, { psCmdCompleteData = psDeviceCommandData[ui32CmdTypeCounter].apsCmdCompleteData[ui32CmdCounter]; - + /* free the cmd complete structure array entries */ if (psCmdCompleteData != IMG_NULL) { + PVR_ASSERT(psCmdCompleteData->bInUse == IMG_FALSE); OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, psCmdCompleteData->ui32AllocSize, psCmdCompleteData, IMG_NULL); psDeviceCommandData[ui32CmdTypeCounter].apsCmdCompleteData[ui32CmdCounter] = IMG_NULL; @@ -1068,7 +1480,7 @@ PVRSRV_ERROR PVRSRVRemoveCmdProcListKM(IMG_UINT32 ui32DevIndex, } } - + /* free the cmd complete structure array for the device */ ui32AllocSize = ui32CmdCount * sizeof(*psDeviceCommandData); OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, ui32AllocSize, psDeviceCommandData, IMG_NULL); psSysData->apsDeviceCommandData[ui32DevIndex] = IMG_NULL; @@ -1077,3 +1489,6 @@ PVRSRV_ERROR PVRSRVRemoveCmdProcListKM(IMG_UINT32 ui32DevIndex, return PVRSRV_OK; } +/****************************************************************************** + End of file (queue.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/common/ra.c b/sgx/services4/srvkm/common/ra.c index e93f05f..819c36a 100644 --- a/sgx/services4/srvkm/common/ra.c +++ b/sgx/services4/srvkm/common/ra.c @@ -1,28 +1,90 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Resource Allocator +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +@Description + Implements generic resource allocation. The resource + allocator was originally intended to manage address spaces in + practice the resource allocator is generic and can manages arbitrary + sets of integers. + + Resources are allocated from arenas. Arena's can be created with an + initial span of resources. Further resources spans can be added to + arenas. A call back mechanism allows an arena to request further + resource spans on demand. + + Each arena maintains an ordered list of resource segments each + described by a boundary tag. Each boundary tag describes a segment + of resources which are either 'free', available for allocation, or + 'busy' currently allocated. Adjacent 'free' segments are always + coallesced to avoid fragmentation. + + For allocation, all 'free' segments are kept on lists of 'free' + segments in a table index by pvr_log2(segment size). ie Each table index + n holds 'free' segments in the size range 2**(n-1) -> 2**n. + + Allocation policy is based on an *almost* best fit + stratedy. Choosing any segment from the appropriate table entry + guarantees that we choose a segment which is with a power of 2 of + the size we are allocating. + + Allocated segments are inserted into a self scaling hash table which + maps the base resource of the span to the relevant boundary + tag. This allows the code to get back to the bounary tag without + exporting explicit boundary tag references through the API. + + Each arena has an associated quantum size, all allocations from the + arena are made in multiples of the basic quantum. + + On resource exhaustion in an arena, a callback if provided will be + used to request further resources. Resouces spans allocated by the + callback mechanism are delimited by special boundary tag markers of + zero span, 'span' markers. Span markers are never coallesced. Span + markers are used to detect when an imported span is completely free + and can be deallocated by the callback mechanism. +*/ /**************************************************************************/ + +/* Issues: + * - flags, flags are passed into the resource allocator but are not currently used. + * - determination, of import size, is currently braindead. + * - debug code should be moved out to own module and #ifdef'd + */ #include "services_headers.h" #include "hash.h" @@ -30,7 +92,7 @@ #include "buffer_manager.h" #include "osfunc.h" -#ifdef __linux__ +#if defined(__linux__) && defined(__KERNEL__) #include <linux/kernel.h> #include "proc.h" #endif @@ -39,10 +101,18 @@ #include <stdio.h> #endif +/* The initial, and minimum size of the live address -> boundary tag + structure hash table. The value 64 is a fairly arbitrary + choice. The hash table resizes on demand so the value choosen is + not critical. */ #define MINIMUM_HASH_SIZE (64) #if defined(VALIDATE_ARENA_TEST) +/* This test validates the doubly linked ordered list of boundary tags, by +checking that adjacent members of the list have compatible eResourceSpan +and eResourceType values. */ + typedef enum RESOURCE_DESCRIPTOR_TAG { RESOURCE_SPAN_LIVE = 10, @@ -67,33 +137,36 @@ static IMG_UINT32 ui32BoundaryTagID = 0; IMG_UINT32 ValidateArena(RA_ARENA *pArena); #endif +/* boundary tags, used to describe a resource segment */ struct _BT_ { enum bt_type { - btt_span, - btt_free, - btt_live + btt_span, /* span markers */ + btt_free, /* free resource segment */ + btt_live /* allocated resource segment */ } type; - + /* The base resource and extent of this segment */ IMG_UINTPTR_T base; IMG_SIZE_T uSize; - + /* doubly linked ordered list of all segments within the arena */ struct _BT_ *pNextSegment; struct _BT_ *pPrevSegment; - + /* doubly linked un-ordered list of free segments. */ struct _BT_ *pNextFree; struct _BT_ *pPrevFree; - + /* a user reference associated with this span, user references are + * currently only provided in the callback mechanism */ BM_MAPPING *psMapping; #if defined(VALIDATE_ARENA_TEST) RESOURCE_DESCRIPTOR eResourceSpan; RESOURCE_TYPE eResourceType; - + /* This variable provides a reference (used in debug messages) to incompatible + boundary tags within the doubly linked ordered list. */ IMG_UINT32 ui32BoundaryTagID; #endif @@ -101,40 +174,45 @@ struct _BT_ typedef struct _BT_ BT; +/* resource allocation arena */ struct _RA_ARENA_ { - + /* arena name for diagnostics output */ IMG_CHAR *name; - + /* allocations within this arena are quantum sized */ IMG_SIZE_T uQuantum; - + /* import interface, if provided */ IMG_BOOL (*pImportAlloc)(IMG_VOID *, IMG_SIZE_T uSize, IMG_SIZE_T *pActualSize, BM_MAPPING **ppsMapping, IMG_UINT32 uFlags, + IMG_PVOID pvPrivData, + IMG_UINT32 ui32PrivDataLength, IMG_UINTPTR_T *pBase); IMG_VOID (*pImportFree) (IMG_VOID *, IMG_UINTPTR_T, BM_MAPPING *psMapping); IMG_VOID (*pBackingStoreFree) (IMG_VOID *, IMG_SIZE_T, IMG_SIZE_T, IMG_HANDLE); - + /* arbitrary handle provided by arena owner to be passed into the + * import alloc and free hooks */ IMG_VOID *pImportHandle; - + /* head of list of free boundary tags for indexed by pvr_log2 of the + boundary tag size */ #define FREE_TABLE_LIMIT 32 - + /* power-of-two table of free lists */ BT *aHeadFree [FREE_TABLE_LIMIT]; - + /* resource ordered segment list */ BT *pHeadSegment; BT *pTailSegment; - + /* segment address to boundary tag hash table */ HASH_TABLE *pSegmentHash; #ifdef RA_STATS @@ -150,6 +228,7 @@ struct _RA_ARENA_ IMG_BOOL bInitProcEntry; #endif }; +/* #define ENABLE_RA_DUMP 1 */ #if defined(ENABLE_RA_DUMP) IMG_VOID RA_Dump (RA_ARENA *pArena); #endif @@ -162,7 +241,7 @@ static void* RA_ProcSeqOff2ElementInfo(struct seq_file * sfile, loff_t off); static void RA_ProcSeqShowRegs(struct seq_file *sfile, void* el); static void* RA_ProcSeqOff2ElementRegs(struct seq_file * sfile, loff_t off); -#endif +#endif /* defined(CONFIG_PROC_FS) && defined(DEBUG) */ #ifdef USE_BM_FREESPACE_CHECK IMG_VOID CheckBMFreespace(IMG_VOID); @@ -185,12 +264,33 @@ static IMG_CHAR *ReplaceSpaces(IMG_CHAR * const pS) } #endif +/*! +****************************************************************************** + @Function _RequestAllocFail + + @Description Default callback allocator used if no callback is + specified, always fails to allocate further resources to the + arena. + + @Input _h - callback handle + @Input _uSize - requested allocation size + @Output _pActualSize - actual allocation size + @Input _pRef - user reference + @Input _uflags - allocation flags + @Input _pvPrivData - private data + @Input _ui32PrivDataLength - private data length + @Input _pBase - receives allocated base + + @Return IMG_FALSE, this function always fails to allocate. +******************************************************************************/ static IMG_BOOL _RequestAllocFail (IMG_VOID *_h, IMG_SIZE_T _uSize, IMG_SIZE_T *_pActualSize, BM_MAPPING **_ppsMapping, IMG_UINT32 _uFlags, + IMG_PVOID _pvPrivData, + IMG_UINT32 _ui32PrivDataLength, IMG_UINTPTR_T *_pBase) { PVR_UNREFERENCED_PARAMETER (_h); @@ -199,10 +299,22 @@ _RequestAllocFail (IMG_VOID *_h, PVR_UNREFERENCED_PARAMETER (_ppsMapping); PVR_UNREFERENCED_PARAMETER (_uFlags); PVR_UNREFERENCED_PARAMETER (_pBase); + PVR_UNREFERENCED_PARAMETER (_pvPrivData); + PVR_UNREFERENCED_PARAMETER (_ui32PrivDataLength); return IMG_FALSE; } +/*! +****************************************************************************** + @Function pvr_log2 + + @Description Computes the floor of the log base 2 of a unsigned integer + + @Input n - unsigned integer + + @Return Floor(Log2(n)) +******************************************************************************/ static IMG_UINT32 pvr_log2 (IMG_SIZE_T n) { @@ -216,6 +328,19 @@ pvr_log2 (IMG_SIZE_T n) return l; } +/*! +****************************************************************************** + @Function _SegmentListInsertAfter + + @Description Insert a boundary tag into an arena segment list after a + specified boundary tag. + + @Input pArena - the arena. + @Input pInsertionPoint - the insertion point. + @Input pBT - the boundary tag to insert. + + @Return PVRSRV_ERROR +******************************************************************************/ static PVRSRV_ERROR _SegmentListInsertAfter (RA_ARENA *pArena, BT *pInsertionPoint, @@ -241,12 +366,24 @@ _SegmentListInsertAfter (RA_ARENA *pArena, return PVRSRV_OK; } +/*! +****************************************************************************** + @Function _SegmentListInsert + + @Description Insert a boundary tag into an arena segment list at the + appropriate point. + + @Input pArena - the arena. + @Input pBT - the boundary tag to insert. + + @Return None +******************************************************************************/ static PVRSRV_ERROR _SegmentListInsert (RA_ARENA *pArena, BT *pBT) { PVRSRV_ERROR eError = PVRSRV_OK; - + /* insert into the segment chain */ if (pArena->pHeadSegment == IMG_NULL) { pArena->pHeadSegment = pArena->pTailSegment = pBT; @@ -258,7 +395,8 @@ _SegmentListInsert (RA_ARENA *pArena, BT *pBT) if (pBT->base < pArena->pHeadSegment->base) { - + /* The base address of pBT is less than the base address of the boundary tag + at the head of the list - so insert this boundary tag at the head. */ pBT->pNextSegment = pArena->pHeadSegment; pArena->pHeadSegment->pPrevSegment = pBT; pArena->pHeadSegment = pBT; @@ -267,9 +405,10 @@ _SegmentListInsert (RA_ARENA *pArena, BT *pBT) else { - - - + /* The base address of pBT is greater than or equal to that of the boundary tag + at the head of the list. Search for the insertion point: pBT must be inserted + before the first boundary tag with a greater base value - or at the end of the list. + */ pBTScan = pArena->pHeadSegment; while ((pBTScan->pNextSegment != IMG_NULL) && (pBT->base >= pBTScan->pNextSegment->base)) @@ -287,6 +426,17 @@ _SegmentListInsert (RA_ARENA *pArena, BT *pBT) return eError; } +/*! +****************************************************************************** + @Function _SegmentListRemove + + @Description Remove a boundary tag from an arena segment list. + + @Input pArena - the arena. + @Input pBT - the boundary tag to remove. + + @Return None +******************************************************************************/ static IMG_VOID _SegmentListRemove (RA_ARENA *pArena, BT *pBT) { @@ -301,6 +451,23 @@ _SegmentListRemove (RA_ARENA *pArena, BT *pBT) pBT->pNextSegment->pPrevSegment = pBT->pPrevSegment; } +/*! +****************************************************************************** + @Function _SegmentSplit + + @Description Split a segment into two, maintain the arena segment list. The + boundary tag should not be in the free table. Neither the + original or the new neighbour bounary tag will be in the free + table. + + @Input pArena - the arena. + @Input pBT - the boundary tag to split. + @Input uSize - the required segment size of boundary tag after + splitting. + + @Return New neighbour boundary tag. + +******************************************************************************/ static BT * _SegmentSplit (RA_ARENA *pArena, BT *pBT, IMG_SIZE_T uSize) { @@ -363,6 +530,18 @@ _SegmentSplit (RA_ARENA *pArena, BT *pBT, IMG_SIZE_T uSize) return pNeighbour; } +/*! +****************************************************************************** + @Function _FreeListInsert + + @Description Insert a boundary tag into an arena free table. + + @Input pArena - the arena. + @Input pBT - the boundary tag. + + @Return None + +******************************************************************************/ static IMG_VOID _FreeListInsert (RA_ARENA *pArena, BT *pBT) { @@ -376,6 +555,18 @@ _FreeListInsert (RA_ARENA *pArena, BT *pBT) pArena->aHeadFree [uIndex] = pBT; } +/*! +****************************************************************************** + @Function _FreeListRemove + + @Description Remove a boundary tag from an arena free table. + + @Input pArena - the arena. + @Input pBT - the boundary tag. + + @Return None + +******************************************************************************/ static IMG_VOID _FreeListRemove (RA_ARENA *pArena, BT *pBT) { @@ -389,6 +580,18 @@ _FreeListRemove (RA_ARENA *pArena, BT *pBT) pBT->pPrevFree->pNextFree = pBT->pNextFree; } +/*! +****************************************************************************** + @Function _BuildSpanMarker + + @Description Construct a span marker boundary tag. + + @Input pArena - arena to contain span marker + @Input base - the base of the bounary tag. + + @Return span marker boundary tag + +******************************************************************************/ static BT * _BuildSpanMarker (IMG_UINTPTR_T base, IMG_SIZE_T uSize) { @@ -416,6 +619,18 @@ _BuildSpanMarker (IMG_UINTPTR_T base, IMG_SIZE_T uSize) return pBT; } +/*! +****************************************************************************** + @Function _BuildBT + + @Description Construct a boundary tag for a free segment. + + @Input base - the base of the resource segment. + @Input uSize - the extent of the resouce segment. + + @Return boundary tag + +******************************************************************************/ static BT * _BuildBT (IMG_UINTPTR_T base, IMG_SIZE_T uSize) { @@ -442,6 +657,20 @@ _BuildBT (IMG_UINTPTR_T base, IMG_SIZE_T uSize) return pBT; } +/*! +****************************************************************************** + @Function _InsertResource + + @Description Add a free resource segment to an arena. + + @Input pArena - the arena. + @Input base - the base of the resource segment. + @Input uSize - the extent of the resource segment. + + @Return New bucket pointer + IMG_NULL failure + +******************************************************************************/ static BT * _InsertResource (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize) { @@ -477,6 +706,19 @@ _InsertResource (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize) return pBT; } +/*! +****************************************************************************** + @Function _InsertResourceSpan + + @Description Add a free resource span to an arena, complete with span markers. + + @Input pArena - the arena. + @Input base - the base of the resource segment. + @Input uSize - the extent of the resource segment. + + @Return the boundary tag representing the free resource segment, + or IMG_NULL on failure. +******************************************************************************/ static BT * _InsertResourceSpan (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize) { @@ -551,22 +793,40 @@ _InsertResourceSpan (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize) #ifdef RA_STATS pArena->sStatistics.uTotalResourceCount+=uSize; +/* pArena->sStatistics.uFreeResourceCount+=uSize; + This has got to be wrong as uFreeResourceCount ends + up larger than uTotalResourceCount by uTotalResourceCount + - allocated memory +*/ #endif return pBT; fail_SegListInsert: OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pBT, IMG_NULL); - + /*not nulling pointer, out of scope*/ fail_bt: OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pSpanEnd, IMG_NULL); - + /*not nulling pointer, out of scope*/ fail_end: OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pSpanStart, IMG_NULL); - + /*not nulling pointer, out of scope*/ fail_start: return IMG_NULL; } +/*! +****************************************************************************** + @Function _FreeBT + + @Description Free a boundary tag taking care of the segment list and the + boundary tag free table. + + @Input pArena - the arena. + @Input pBT - the boundary tag to free. + @Input bFreeBackingStore - Should backing for the memory be freed + as well. + @Return None +******************************************************************************/ static IMG_VOID _FreeBT (RA_ARENA *pArena, BT *pBT, IMG_BOOL bFreeBackingStore) { @@ -592,7 +852,7 @@ _FreeBT (RA_ARENA *pArena, BT *pBT, IMG_BOOL bFreeBackingStore) uOrigBase = pBT->base; uOrigSize = pBT->uSize; - + /* try and coalesce with left neighbour */ pNeighbour = pBT->pPrevSegment; if (pNeighbour!=IMG_NULL && pNeighbour->type == btt_free @@ -603,13 +863,13 @@ _FreeBT (RA_ARENA *pArena, BT *pBT, IMG_BOOL bFreeBackingStore) pBT->base = pNeighbour->base; pBT->uSize += pNeighbour->uSize; OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pNeighbour, IMG_NULL); - + /*not nulling original pointer, already overwritten*/ #ifdef RA_STATS pArena->sStatistics.uFreeSegmentCount--; #endif } - + /* try to coalesce with right neighbour */ pNeighbour = pBT->pNextSegment; if (pNeighbour!=IMG_NULL && pNeighbour->type == btt_free @@ -619,28 +879,28 @@ _FreeBT (RA_ARENA *pArena, BT *pBT, IMG_BOOL bFreeBackingStore) _SegmentListRemove (pArena, pNeighbour); pBT->uSize += pNeighbour->uSize; OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pNeighbour, IMG_NULL); - + /*not nulling original pointer, already overwritten*/ #ifdef RA_STATS pArena->sStatistics.uFreeSegmentCount--; #endif } - + /* try to free backing store memory. */ if (pArena->pBackingStoreFree != IMG_NULL && bFreeBackingStore) { IMG_UINTPTR_T uRoundedStart, uRoundedEnd; - + /* Work out the first address we might be able to free. */ uRoundedStart = (uOrigBase / pArena->uQuantum) * pArena->uQuantum; - + /* If a span is still using that address then leave it. */ if (uRoundedStart < pBT->base) { uRoundedStart += pArena->uQuantum; } - + /* Work out the last address we might be able to free. */ uRoundedEnd = ((uOrigBase + uOrigSize + pArena->uQuantum - 1) / pArena->uQuantum) * pArena->uQuantum; - + /* If a span is still using that addres then leave it. */ if (uRoundedEnd > (pBT->base + pBT->uSize)) { uRoundedEnd -= pArena->uQuantum; @@ -669,17 +929,35 @@ _FreeBT (RA_ARENA *pArena, BT *pBT, IMG_BOOL bFreeBackingStore) pArena->sStatistics.uTotalResourceCount-=pBT->uSize; #endif OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), next, IMG_NULL); - + /*not nulling original pointer, already overwritten*/ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), prev, IMG_NULL); - + /*not nulling original pointer, already overwritten*/ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pBT, IMG_NULL); - + /*not nulling pointer, copy on stack*/ } else _FreeListInsert (pArena, pBT); } +/*! +****************************************************************************** + @Function _AttemptAllocAligned + + @Description Attempt an allocation from an arena. + + @Input pArena - the arena. + @Input uSize - the requested allocation size. + @Output ppsMapping - the user references associated with + the allocated segment. + @Input flags - allocation flags + @Input uAlignment - required uAlignment, or 0 + @Input uAlignmentOffset + @Output base - allocated resource base + + @Return IMG_FALSE failure + IMG_TRUE success +******************************************************************************/ static IMG_BOOL _AttemptAllocAligned (RA_ARENA *pArena, IMG_SIZE_T uSize, @@ -700,16 +978,11 @@ _AttemptAllocAligned (RA_ARENA *pArena, if (uAlignment>1) uAlignmentOffset %= uAlignment; - - + /* search for a near fit free boundary tag, start looking at the + pvr_log2 free table for our required size and work on up the + table. */ uIndex = pvr_log2 (uSize); -#if 0 - - if (1u<<uIndex < uSize) - uIndex++; -#endif - while (uIndex < FREE_TABLE_LIMIT && pArena->aHeadFree[uIndex]==IMG_NULL) uIndex++; @@ -717,7 +990,7 @@ _AttemptAllocAligned (RA_ARENA *pArena, { if (pArena->aHeadFree[uIndex]!=IMG_NULL) { - + /* we have a cached free boundary tag */ BT *pBT; pBT = pArena->aHeadFree [uIndex]; @@ -748,16 +1021,16 @@ _AttemptAllocAligned (RA_ARENA *pArena, pArena->sStatistics.uFreeResourceCount-=pBT->uSize; #endif - + /* with uAlignment we might need to discard the front of this segment */ if (aligned_base > pBT->base) { BT *pNeighbour; pNeighbour = _SegmentSplit (pArena, pBT, (IMG_SIZE_T)(aligned_base - pBT->base)); - + /* partition the buffer, create a new boundary tag */ if (pNeighbour==IMG_NULL) { PVR_DPF ((PVR_DBG_ERROR,"_AttemptAllocAligned: Front split failed")); - + /* Put pBT back in the list */ _FreeListInsert (pArena, pBT); return IMG_FALSE; } @@ -770,16 +1043,16 @@ _AttemptAllocAligned (RA_ARENA *pArena, pBT = pNeighbour; } - + /* the segment might be too big, if so, discard the back of the segment */ if (pBT->uSize > uSize) { BT *pNeighbour; pNeighbour = _SegmentSplit (pArena, pBT, uSize); - + /* partition the buffer, create a new boundary tag */ if (pNeighbour==IMG_NULL) { PVR_DPF ((PVR_DBG_ERROR,"_AttemptAllocAligned: Back split failed")); - + /* Put pBT back in the list */ _FreeListInsert (pArena, pBT); return IMG_FALSE; } @@ -840,6 +1113,23 @@ _AttemptAllocAligned (RA_ARENA *pArena, +/*! +****************************************************************************** + @Function RA_Create + + @Description To create a resource arena. + + @Input name - the name of the arena for diagnostic purposes. + @Input base - the base of an initial resource span or 0. + @Input uSize - the size of an initial resource span or 0. + @Input uQuantum - the arena allocation quantum. + @Input alloc - a resource allocation callback or 0. + @Input free - a resource de-allocation callback or 0. + @Input backingstore_free - a callback to free resources for spans or 0. + @Input pImportHandle - handle passed to alloc and free or 0. + + @Return arena handle, or IMG_NULL. +******************************************************************************/ RA_ARENA * RA_Create (IMG_CHAR *name, IMG_UINTPTR_T base, @@ -847,7 +1137,9 @@ RA_Create (IMG_CHAR *name, BM_MAPPING *psMapping, IMG_SIZE_T uQuantum, IMG_BOOL (*imp_alloc)(IMG_VOID *, IMG_SIZE_T uSize, IMG_SIZE_T *pActualSize, - BM_MAPPING **ppsMapping, IMG_UINT32 _flags, IMG_UINTPTR_T *pBase), + BM_MAPPING **ppsMapping, IMG_UINT32 _flags, + IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength, + IMG_UINTPTR_T *pBase), IMG_VOID (*imp_free) (IMG_VOID *, IMG_UINTPTR_T, BM_MAPPING *), IMG_VOID (*backingstore_free) (IMG_VOID*, IMG_SIZE_T, IMG_SIZE_T, IMG_HANDLE), IMG_VOID *pImportHandle) @@ -908,7 +1200,7 @@ RA_Create (IMG_CHAR *name, pArena->bInitProcEntry = !PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_SUCCESSFUL); - + /* Don't put shared heap info into a per process /proc subdirectory */ pfnCreateProcEntrySeq = pArena->bInitProcEntry ? CreateProcEntrySeq : CreatePerProcessProcEntrySeq; ret = snprintf(szProcInfoName, sizeof(szProcInfoName), "ra_info_%s", pArena->name); @@ -935,7 +1227,7 @@ RA_Create (IMG_CHAR *name, PVR_DPF((PVR_DBG_ERROR, "RA_Create: couldn't create ra_segs proc entry for arena %s", pArena->name)); } } -#endif +#endif /* defined(CONFIG_PROC_FS) && defined(DEBUG) */ pArena->pSegmentHash = HASH_Create (MINIMUM_HASH_SIZE); if (pArena->pSegmentHash==IMG_NULL) @@ -959,11 +1251,22 @@ insert_fail: HASH_Delete (pArena->pSegmentHash); hash_fail: OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(RA_ARENA), pArena, IMG_NULL); - + /*not nulling pointer, out of scope*/ arena_fail: return IMG_NULL; } +/*! +****************************************************************************** + @Function RA_Delete + + @Description To delete a resource arena. All resources allocated from + the arena must be freed before deleting the arena. + + @Input pArena - the arena to delete. + + @Return None +******************************************************************************/ IMG_VOID RA_Delete (RA_ARENA *pArena) { @@ -996,7 +1299,7 @@ RA_Delete (RA_ARENA *pArena) _SegmentListRemove (pArena, pBT); OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pBT, IMG_NULL); - + /*not nulling original pointer, it has changed*/ #ifdef RA_STATS pArena->sStatistics.uSpanCount--; #endif @@ -1020,9 +1323,20 @@ RA_Delete (RA_ARENA *pArena) #endif HASH_Delete (pArena->pSegmentHash); OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(RA_ARENA), pArena, IMG_NULL); - + /*not nulling pointer, copy on stack*/ } +/*! +****************************************************************************** + @Function RA_TestDelete + + @Description To test whether it is safe to delete a resource arena. If any + allocations have not been freed, the RA must not be deleted. + + @Input pArena - the arena to test. + + @Return IMG_BOOL - IMG_TRUE if is safe to go on and call RA_Delete. +******************************************************************************/ IMG_BOOL RA_TestDelete (RA_ARENA *pArena) { @@ -1045,6 +1359,20 @@ RA_TestDelete (RA_ARENA *pArena) return IMG_TRUE; } +/*! +****************************************************************************** + @Function RA_Add + + @Description To add a resource span to an arena. The span must not + overlapp with any span previously added to the arena. + + @Input pArena - the arena to add a span into. + @Input base - the base of the span. + @Input uSize - the extent of the span. + + @Return IMG_TRUE - Success + IMG_FALSE - failure +******************************************************************************/ IMG_BOOL RA_Add (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize) { @@ -1063,6 +1391,29 @@ RA_Add (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize) return ((IMG_BOOL)(_InsertResource (pArena, base, uSize) != IMG_NULL)); } +/*! +****************************************************************************** + @Function RA_Alloc + + @Description To allocate resource from an arena. + + @Input pArena - the arena + @Input uRequestSize - the size of resource segment requested. + @Output pActualSize - the actual size of resource segment + allocated, typcially rounded up by quantum. + @Output ppsMapping - the user reference associated with allocated resource span. + @Input uFlags - flags influencing allocation policy. + @Input uAlignment - the uAlignment constraint required for the + allocated segment, use 0 if uAlignment not required. + @Input uAlignmentOffset + @Input pvPrivData - opaque private data passed through to allocator + @Input ui32PrivDataLength - length of opaque private data + + @Output base - allocated base resource + + @Return IMG_TRUE - success + IMG_FALSE - failure +******************************************************************************/ IMG_BOOL RA_Alloc (RA_ARENA *pArena, IMG_SIZE_T uRequestSize, @@ -1071,6 +1422,8 @@ RA_Alloc (RA_ARENA *pArena, IMG_UINT32 uFlags, IMG_UINT32 uAlignment, IMG_UINT32 uAlignmentOffset, + IMG_PVOID pvPrivData, + IMG_UINT32 ui32PrivDataLength, IMG_UINTPTR_T *base) { IMG_BOOL bResult; @@ -1101,8 +1454,9 @@ RA_Alloc (RA_ARENA *pArena, "RA_Alloc: arena='%s', size=0x%x(0x%x), alignment=0x%x, offset=0x%x", pArena->name, uSize, uRequestSize, uAlignment, uAlignmentOffset)); - - + /* if allocation failed then we might have an import source which + can provide more resource, else we will have to fail the + allocation to the caller. */ bResult = _AttemptAllocAligned (pArena, uSize, ppsMapping, uFlags, uAlignment, uAlignmentOffset, base); if (!bResult) @@ -1111,34 +1465,38 @@ RA_Alloc (RA_ARENA *pArena, IMG_UINTPTR_T import_base; IMG_SIZE_T uImportSize = uSize; - - - + /* + Ensure that we allocate sufficient space to meet the uAlignment + constraint + */ if (uAlignment > pArena->uQuantum) { uImportSize += (uAlignment - 1); } - + /* ensure that we import according to the quanta of this arena */ uImportSize = ((uImportSize + pArena->uQuantum - 1)/pArena->uQuantum)*pArena->uQuantum; bResult = pArena->pImportAlloc (pArena->pImportHandle, uImportSize, &uImportSize, - &psImportMapping, uFlags, &import_base); + &psImportMapping, uFlags, + pvPrivData, ui32PrivDataLength, &import_base); if (bResult) { BT *pBT; pBT = _InsertResourceSpan (pArena, import_base, uImportSize); - + /* successfully import more resource, create a span to + represent it and retry the allocation attempt */ if (pBT == IMG_NULL) { - + /* insufficient resources to insert the newly acquired span, + so free it back again */ pArena->pImportFree(pArena->pImportHandle, import_base, psImportMapping); PVR_DPF ((PVR_DBG_MESSAGE, "RA_Alloc: name='%s', size=0x%x failed!", pArena->name, uSize)); - + /* RA_Dump (arena); */ return IMG_FALSE; } pBT->psMapping = psImportMapping; @@ -1168,7 +1526,9 @@ RA_Alloc (RA_ARENA *pArena, "RA_Alloc: name='%s', size=0x%x, *base=0x%x = %d", pArena->name, uSize, *base, bResult)); - + /* RA_Dump (pArena); + ra_stats (pArena); + */ #if defined(VALIDATE_ARENA_TEST) ValidateArena(pArena); @@ -1180,6 +1540,20 @@ RA_Alloc (RA_ARENA *pArena, #if defined(VALIDATE_ARENA_TEST) +/*! +****************************************************************************** + @Function ValidateArena + + @Description Validate an arena by checking that adjacent members of the + double linked ordered list are compatible. PVR_DBG_BREAK and + PVR_DPF messages are used when an error is detected. + NOTE: A DEBUG build is required for PVR_DBG_BREAK and PVR_DPF + to operate. + + @Input pArena - the arena + + @Return 0 +******************************************************************************/ IMG_UINT32 ValidateArena(RA_ARENA *pArena) { BT* pSegment; @@ -1208,7 +1582,7 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena) (eNextSpan == IMPORTED_RESOURCE_SPAN_FREE) || (eNextSpan == IMPORTED_RESOURCE_SPAN_END))) { - + /* error - next span must be live, free or end */ PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)", pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name)); @@ -1221,7 +1595,7 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena) if (!((eNextSpan == IMPORTED_RESOURCE_SPAN_LIVE) || (eNextSpan == IMPORTED_RESOURCE_SPAN_END))) { - + /* error - next span must be live or end */ PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)", pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name)); @@ -1235,7 +1609,7 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena) (eNextSpan == IMPORTED_RESOURCE_SPAN_FREE) || (eNextSpan == IMPORTED_RESOURCE_SPAN_END)) { - + /* error - next span cannot be live, free or end */ PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)", pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name)); @@ -1249,7 +1623,7 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena) if (!((eNextSpan == IMPORTED_RESOURCE_SPAN_LIVE) || (eNextSpan == IMPORTED_RESOURCE_SPAN_FREE))) { - + /* error - next span must be live or free */ PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)", pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name)); @@ -1282,7 +1656,7 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena) if (!((eNextSpan == RESOURCE_SPAN_FREE) || (eNextSpan == RESOURCE_SPAN_LIVE))) { - + /* error - next span must be free or live */ PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)", pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name)); @@ -1295,7 +1669,7 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena) if (!((eNextSpan == RESOURCE_SPAN_FREE) || (eNextSpan == RESOURCE_SPAN_LIVE))) { - + /* error - next span must be free or live */ PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)", pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name)); @@ -1327,6 +1701,18 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena) #endif +/*! +****************************************************************************** + @Function RA_Free + + @Description To free a resource segment. + + @Input pArena - the arena the segment was originally allocated from. + @Input base - the base of the resource span to free. + @Input bFreeBackingStore - Should backing store memory be freed. + + @Return None +******************************************************************************/ IMG_VOID RA_Free (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_BOOL bFreeBackingStore) { @@ -1386,6 +1772,17 @@ RA_Free (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_BOOL bFreeBackingStore) } +/*! +****************************************************************************** + @Function RA_GetNextLiveSegment + + @Description Returns details of the next live resource segments + + @Input pArena - the arena the segment was originally allocated from. + @InOut psSegDetails - rtn details of segments + + @Return IMG_TRUE if operation succeeded +******************************************************************************/ IMG_BOOL RA_GetNextLiveSegment(IMG_HANDLE hArena, RA_SEGMENT_DETAILS *psSegDetails) { BT *pBT; @@ -1400,7 +1797,7 @@ IMG_BOOL RA_GetNextLiveSegment(IMG_HANDLE hArena, RA_SEGMENT_DETAILS *psSegDetai pBT = pArena->pHeadSegment; } - + /* walk the arena segments and write live one to the buffer */ while (pBT != IMG_NULL) { if (pBT->type == btt_live) @@ -1479,9 +1876,19 @@ _BTType (IMG_INT eType) } return "junk"; } -#endif +#endif /*defined(CONFIG_PROC_FS) && defined(DEBUG)*/ #if defined(ENABLE_RA_DUMP) +/*! +****************************************************************************** + @Function RA_Dump + + @Description To dump a readable description of an arena. Diagnostic only. + + @Input pArena - the arena to dump. + + @Return None +******************************************************************************/ IMG_VOID RA_Dump (RA_ARENA *pArena) { @@ -1501,16 +1908,15 @@ RA_Dump (RA_ARENA *pArena) for (pBT=pArena->pHeadSegment; pBT!=IMG_NULL; pBT=pBT->pNextSegment) { - PVR_DPF ((PVR_DBG_MESSAGE,"\tbase=0x%x size=0x%x type=%s ref=%08X", - (IMG_UINT32) pBT->base, pBT->uSize, _BTType (pBT->type), - pBT->pRef)); + PVR_DPF ((PVR_DBG_MESSAGE,"\tbase=0x%x size=0x%x type=%s", + (IMG_UINT32) pBT->base, pBT->uSize, _BTType (pBT->type))); } #ifdef HASH_TRACE HASH_Dump (pArena->pSegmentHash); #endif } -#endif +#endif /* #if defined(ENABLE_RA_DUMP) */ #if defined(CONFIG_PROC_FS) && defined(DEBUG) @@ -1607,10 +2013,22 @@ static void* RA_ProcSeqOff2ElementRegs(struct seq_file * sfile, loff_t off) return (void*)pBT; } -#endif +#endif /* defined(CONFIG_PROC_FS) && defined(DEBUG) */ #ifdef RA_STATS +/*! +****************************************************************************** + @Function RA_GetStats + + @Description Gets the arena stats and places in client buffer + + @Input pArena - the arena to print statistics for. + @Input ppszStr - caller string to fill + @Input pui32StrLen - length of caller string + + @Return PVRSRV_ERROR +******************************************************************************/ PVRSRV_ERROR RA_GetStats(RA_ARENA *pArena, IMG_CHAR **ppszStr, IMG_UINT32 *pui32StrLen) @@ -1723,3 +2141,10 @@ PVRSRV_ERROR RA_GetStatsFreeMem(RA_ARENA *pArena, } #endif +/****************************************************************************** + End of file (ra.c) +******************************************************************************/ + + + + diff --git a/sgx/services4/srvkm/common/refcount.c b/sgx/services4/srvkm/common/refcount.c new file mode 100644 index 0000000..480428a --- /dev/null +++ b/sgx/services4/srvkm/common/refcount.c @@ -0,0 +1,584 @@ +/*************************************************************************/ /*! +@Title Services reference count debugging +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ + +#if defined(PVRSRV_REFCOUNT_DEBUG) + +#include "services_headers.h" + +#ifndef __linux__ +#warning Reference count debugging is not thread-safe on this platform +#define PVRSRV_LOCK_CCB() +#define PVRSRV_UNLOCK_CCB() +#else /* __linux__ */ +#include <linux/mutex.h> +static DEFINE_MUTEX(gsCCBLock); +#define PVRSRV_LOCK_CCB() mutex_lock(&gsCCBLock) +#define PVRSRV_UNLOCK_CCB() mutex_unlock(&gsCCBLock) +#endif /* __linux__ */ + +#define PVRSRV_REFCOUNT_CCB_MAX 512 +#define PVRSRV_REFCOUNT_CCB_MESG_MAX 80 + +#define PVRSRV_REFCOUNT_CCB_DEBUG_SYNCINFO (1U << 0) +#define PVRSRV_REFCOUNT_CCB_DEBUG_MEMINFO (1U << 1) +#define PVRSRV_REFCOUNT_CCB_DEBUG_BM_BUF (1U << 2) +#define PVRSRV_REFCOUNT_CCB_DEBUG_BM_BUF2 (1U << 3) +#define PVRSRV_REFCOUNT_CCB_DEBUG_BM_XPROC (1U << 4) + +#if defined(__linux__) +#define PVRSRV_REFCOUNT_CCB_DEBUG_MMAP (1U << 16) +#define PVRSRV_REFCOUNT_CCB_DEBUG_MMAP2 (1U << 17) +#else +#define PVRSRV_REFCOUNT_CCB_DEBUG_MMAP 0 +#define PVRSRV_REFCOUNT_CCB_DEBUG_MMAP2 0 +#endif + +#define PVRSRV_REFCOUNT_CCB_DEBUG_ALL ~0U + +/*static const IMG_UINT guiDebugMask = PVRSRV_REFCOUNT_CCB_DEBUG_ALL;*/ +static const IMG_UINT guiDebugMask = + PVRSRV_REFCOUNT_CCB_DEBUG_SYNCINFO | + PVRSRV_REFCOUNT_CCB_DEBUG_MMAP2; + +typedef struct +{ + const IMG_CHAR *pszFile; + IMG_INT iLine; + IMG_UINT32 ui32PID; + IMG_CHAR pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX]; +} +PVRSRV_REFCOUNT_CCB; + +static PVRSRV_REFCOUNT_CCB gsRefCountCCB[PVRSRV_REFCOUNT_CCB_MAX]; +static IMG_UINT giOffset; + +static const IMG_CHAR gszHeader[] = + /* 10 20 30 40 50 60 70 + * 345678901234567890123456789012345678901234567890123456789012345678901 + */ + "TYPE SYNCINFO MEMINFO MEMHANDLE OTHER REF REF' SIZE PID"; + /* NCINFO deadbeef deadbeef deadbeef deadbeef 1234 1234 deadbeef */ + +#define PVRSRV_REFCOUNT_CCB_FMT_STRING "%8.8s %8p %8p %8p %8p %.4d %.4d %.8x" + +IMG_INTERNAL +void PVRSRVDumpRefCountCCB(void) +{ + int i; + + PVRSRV_LOCK_CCB(); + + PVR_LOG(("%s", gszHeader)); + + for(i = 0; i < PVRSRV_REFCOUNT_CCB_MAX; i++) + { + PVRSRV_REFCOUNT_CCB *psRefCountCCBEntry = + &gsRefCountCCB[(giOffset + i) % PVRSRV_REFCOUNT_CCB_MAX]; + + /* Early on, we won't have MAX_REFCOUNT_CCB_SIZE messages */ + if(!psRefCountCCBEntry->pszFile) + break; + + PVR_LOG(("%s %d %s:%d", psRefCountCCBEntry->pcMesg, + psRefCountCCBEntry->ui32PID, + psRefCountCCBEntry->pszFile, + psRefCountCCBEntry->iLine)); + } + + PVRSRV_UNLOCK_CCB(); +} + +IMG_INTERNAL +void PVRSRVKernelSyncInfoIncRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo, + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo) +{ + IMG_UINT32 ui32RefValue = OSAtomicRead(psKernelSyncInfo->pvRefCount); + + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_SYNCINFO)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "SYNCINFO", + psKernelSyncInfo, + psKernelMemInfo, + NULL, + (psKernelMemInfo) ? psKernelMemInfo->sMemBlk.hOSMemHandle : NULL, + ui32RefValue, + ui32RefValue + 1, + (psKernelMemInfo) ? psKernelMemInfo->uAllocSize : 0); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + PVRSRVAcquireSyncInfoKM(psKernelSyncInfo); +} + +IMG_INTERNAL +void PVRSRVKernelSyncInfoDecRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo, + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo) +{ + IMG_UINT32 ui32RefValue = OSAtomicRead(psKernelSyncInfo->pvRefCount); + + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_SYNCINFO)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "SYNCINFO", + psKernelSyncInfo, + psKernelMemInfo, + (psKernelMemInfo) ? psKernelMemInfo->sMemBlk.hOSMemHandle : NULL, + NULL, + ui32RefValue, + ui32RefValue - 1, + (psKernelMemInfo) ? psKernelMemInfo->uAllocSize : 0); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + PVRSRVReleaseSyncInfoKM(psKernelSyncInfo); +} + +IMG_INTERNAL +void PVRSRVKernelMemInfoIncRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo) +{ + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_MEMINFO)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "MEMINFO", + psKernelMemInfo->psKernelSyncInfo, + psKernelMemInfo, + psKernelMemInfo->sMemBlk.hOSMemHandle, + NULL, + psKernelMemInfo->ui32RefCount, + psKernelMemInfo->ui32RefCount + 1, + psKernelMemInfo->uAllocSize); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + psKernelMemInfo->ui32RefCount++; +} + +IMG_INTERNAL +void PVRSRVKernelMemInfoDecRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo) +{ + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_MEMINFO)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "MEMINFO", + psKernelMemInfo->psKernelSyncInfo, + psKernelMemInfo, + psKernelMemInfo->sMemBlk.hOSMemHandle, + NULL, + psKernelMemInfo->ui32RefCount, + psKernelMemInfo->ui32RefCount - 1, + psKernelMemInfo->uAllocSize); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + psKernelMemInfo->ui32RefCount--; +} + +IMG_INTERNAL +void PVRSRVBMBufIncRef2(const IMG_CHAR *pszFile, IMG_INT iLine, BM_BUF *pBuf) +{ + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_BM_BUF)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "BM_BUF", + NULL, + NULL, + BM_HandleToOSMemHandle(pBuf), + pBuf, + pBuf->ui32RefCount, + pBuf->ui32RefCount + 1, + (pBuf->pMapping) ? pBuf->pMapping->uSize : 0); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + pBuf->ui32RefCount++; +} + +IMG_INTERNAL +void PVRSRVBMBufDecRef2(const IMG_CHAR *pszFile, IMG_INT iLine, BM_BUF *pBuf) +{ + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_BM_BUF)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "BM_BUF", + NULL, + NULL, + BM_HandleToOSMemHandle(pBuf), + pBuf, + pBuf->ui32RefCount, + pBuf->ui32RefCount - 1, + (pBuf->pMapping) ? pBuf->pMapping->uSize : 0); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + pBuf->ui32RefCount--; +} + +IMG_INTERNAL +void PVRSRVBMBufIncExport2(const IMG_CHAR *pszFile, IMG_INT iLine, BM_BUF *pBuf) +{ + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_BM_BUF2)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "BM_BUF2", + NULL, + NULL, + BM_HandleToOSMemHandle(pBuf), + pBuf, + pBuf->ui32ExportCount, + pBuf->ui32ExportCount + 1, + (pBuf->pMapping) ? pBuf->pMapping->uSize : 0); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + pBuf->ui32ExportCount++; +} + +IMG_INTERNAL +void PVRSRVBMBufDecExport2(const IMG_CHAR *pszFile, IMG_INT iLine, BM_BUF *pBuf) +{ + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_BM_BUF2)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "BM_BUF2", + NULL, + NULL, + BM_HandleToOSMemHandle(pBuf), + pBuf, + pBuf->ui32ExportCount, + pBuf->ui32ExportCount - 1, + (pBuf->pMapping) ? pBuf->pMapping->uSize : 0); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + pBuf->ui32ExportCount--; +} + +IMG_INTERNAL +void PVRSRVBMXProcIncRef2(const IMG_CHAR *pszFile, IMG_INT iLine, IMG_UINT32 ui32Index) +{ + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_BM_XPROC)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "BM_XPROC", + NULL, + NULL, + gXProcWorkaroundShareData[ui32Index].hOSMemHandle, + (IMG_VOID *) ui32Index, + gXProcWorkaroundShareData[ui32Index].ui32RefCount, + gXProcWorkaroundShareData[ui32Index].ui32RefCount + 1, + gXProcWorkaroundShareData[ui32Index].ui32Size); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + gXProcWorkaroundShareData[ui32Index].ui32RefCount++; +} + +IMG_INTERNAL +void PVRSRVBMXProcDecRef2(const IMG_CHAR *pszFile, IMG_INT iLine, IMG_UINT32 ui32Index) +{ + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_BM_XPROC)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "BM_XPROC", + NULL, + NULL, + gXProcWorkaroundShareData[ui32Index].hOSMemHandle, + (IMG_VOID *) ui32Index, + gXProcWorkaroundShareData[ui32Index].ui32RefCount, + gXProcWorkaroundShareData[ui32Index].ui32RefCount - 1, + gXProcWorkaroundShareData[ui32Index].ui32Size); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + gXProcWorkaroundShareData[ui32Index].ui32RefCount--; +} + +#if defined(__linux__) + +/* mmap refcounting is Linux specific */ + +IMG_INTERNAL +void PVRSRVOffsetStructIncRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + PKV_OFFSET_STRUCT psOffsetStruct) +{ + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_MMAP)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "MMAP", + NULL, + NULL, + psOffsetStruct->psLinuxMemArea, + psOffsetStruct, + psOffsetStruct->ui32RefCount, + psOffsetStruct->ui32RefCount + 1, + psOffsetStruct->ui32RealByteSize); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + psOffsetStruct->ui32RefCount++; +} + +IMG_INTERNAL +void PVRSRVOffsetStructDecRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + PKV_OFFSET_STRUCT psOffsetStruct) +{ + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_MMAP)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "MMAP", + NULL, + NULL, + psOffsetStruct->psLinuxMemArea, + psOffsetStruct, + psOffsetStruct->ui32RefCount, + psOffsetStruct->ui32RefCount - 1, + psOffsetStruct->ui32RealByteSize); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + psOffsetStruct->ui32RefCount--; +} + +IMG_INTERNAL +void PVRSRVOffsetStructIncMapped2(const IMG_CHAR *pszFile, IMG_INT iLine, + PKV_OFFSET_STRUCT psOffsetStruct) +{ + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_MMAP2)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "MMAP2", + NULL, + NULL, + psOffsetStruct->psLinuxMemArea, + psOffsetStruct, + psOffsetStruct->ui32Mapped, + psOffsetStruct->ui32Mapped + 1, + psOffsetStruct->ui32RealByteSize); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + psOffsetStruct->ui32Mapped++; +} + +IMG_INTERNAL +void PVRSRVOffsetStructDecMapped2(const IMG_CHAR *pszFile, IMG_INT iLine, + PKV_OFFSET_STRUCT psOffsetStruct) +{ + if(!(guiDebugMask & PVRSRV_REFCOUNT_CCB_DEBUG_MMAP2)) + goto skip; + + PVRSRV_LOCK_CCB(); + + gsRefCountCCB[giOffset].pszFile = pszFile; + gsRefCountCCB[giOffset].iLine = iLine; + gsRefCountCCB[giOffset].ui32PID = OSGetCurrentProcessIDKM(); + snprintf(gsRefCountCCB[giOffset].pcMesg, + PVRSRV_REFCOUNT_CCB_MESG_MAX - 1, + PVRSRV_REFCOUNT_CCB_FMT_STRING, + "MMAP2", + NULL, + NULL, + psOffsetStruct->psLinuxMemArea, + psOffsetStruct, + psOffsetStruct->ui32Mapped, + psOffsetStruct->ui32Mapped - 1, + psOffsetStruct->ui32RealByteSize); + gsRefCountCCB[giOffset].pcMesg[PVRSRV_REFCOUNT_CCB_MESG_MAX - 1] = 0; + giOffset = (giOffset + 1) % PVRSRV_REFCOUNT_CCB_MAX; + + PVRSRV_UNLOCK_CCB(); + +skip: + psOffsetStruct->ui32Mapped--; +} + +#endif /* defined(__linux__) */ + +#endif /* defined(PVRSRV_REFCOUNT_DEBUG) */ diff --git a/sgx/services4/srvkm/common/resman.c b/sgx/services4/srvkm/common/resman.c index 5088c7f..e0f165c 100644 --- a/sgx/services4/srvkm/common/resman.c +++ b/sgx/services4/srvkm/common/resman.c @@ -1,29 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ - +/*************************************************************************/ /*! +@Title Resource Manager +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Provide resource management +@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 "services_headers.h" #include "resman.h" @@ -81,49 +97,56 @@ static DECLARE_MUTEX(lock); #define RESMAN_SIGNATURE 0x12345678 +/****************************************************************************** + * resman structures + *****************************************************************************/ + +/* resman item structure */ typedef struct _RESMAN_ITEM_ { #ifdef DEBUG IMG_UINT32 ui32Signature; #endif - struct _RESMAN_ITEM_ **ppsThis; - struct _RESMAN_ITEM_ *psNext; + struct _RESMAN_ITEM_ **ppsThis; /*!< list navigation */ + struct _RESMAN_ITEM_ *psNext; /*!< list navigation */ - IMG_UINT32 ui32Flags; - IMG_UINT32 ui32ResType; + IMG_UINT32 ui32Flags; /*!< flags */ + IMG_UINT32 ui32ResType;/*!< res type */ - IMG_PVOID pvParam; - IMG_UINT32 ui32Param; + IMG_PVOID pvParam; /*!< param1 for callback */ + IMG_UINT32 ui32Param; /*!< param2 for callback */ - RESMAN_FREE_FN pfnFreeResource; + RESMAN_FREE_FN pfnFreeResource;/*!< resman item free callback */ } RESMAN_ITEM; +/* resman context structure */ typedef struct _RESMAN_CONTEXT_ { #ifdef DEBUG IMG_UINT32 ui32Signature; #endif - struct _RESMAN_CONTEXT_ **ppsThis; - struct _RESMAN_CONTEXT_ *psNext; + struct _RESMAN_CONTEXT_ **ppsThis;/*!< list navigation */ + struct _RESMAN_CONTEXT_ *psNext;/*!< list navigation */ - PVRSRV_PER_PROCESS_DATA *psPerProc; + PVRSRV_PER_PROCESS_DATA *psPerProc; /* owner of resources */ - RESMAN_ITEM *psResItemList; + RESMAN_ITEM *psResItemList;/*!< res item list for context */ } RESMAN_CONTEXT; +/* resman list structure */ typedef struct { - RESMAN_CONTEXT *psContextList; + RESMAN_CONTEXT *psContextList; /*!< resman context list */ -} RESMAN_LIST, *PRESMAN_LIST; +} RESMAN_LIST, *PRESMAN_LIST; /* PRQA S 3205 */ PRESMAN_LIST gpsResList = IMG_NULL; -#include "lists.h" +#include "lists.h" /* PRQA S 5087 */ /* include lists.h required here */ static IMPLEMENT_LIST_ANY_VA(RESMAN_ITEM) static IMPLEMENT_LIST_ANY_VA_2(RESMAN_ITEM, IMG_BOOL, IMG_FALSE) @@ -137,6 +160,8 @@ static IMPLEMENT_LIST_INSERT(RESMAN_CONTEXT) #define PRINT_RESLIST(x, y, z) +/******************************************************** Forword references */ + static PVRSRV_ERROR FreeResourceByPtr(RESMAN_ITEM *psItem, IMG_BOOL bExecuteCallback, IMG_BOOL bForceCleanup); static PVRSRV_ERROR FreeResourceByCriteria(PRESMAN_CONTEXT psContext, @@ -159,11 +184,21 @@ static PVRSRV_ERROR FreeResourceByCriteria(PRESMAN_CONTEXT psContext, +/*! +****************************************************************************** + + @Function ResManInit + + @Description initialises the resman + + @Return none + +******************************************************************************/ PVRSRV_ERROR ResManInit(IMG_VOID) { if (gpsResList == IMG_NULL) { - + /* If not already initialised */ if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*gpsResList), (IMG_VOID **)&gpsResList, IMG_NULL, @@ -172,10 +207,10 @@ PVRSRV_ERROR ResManInit(IMG_VOID) return PVRSRV_ERROR_OUT_OF_MEMORY; } - + /* Init list, the linked list has dummy entries at both ends */ gpsResList->psContextList = IMG_NULL; - + /* Check resource list */ VALIDATERESLIST(); } @@ -183,30 +218,52 @@ PVRSRV_ERROR ResManInit(IMG_VOID) } +/*! +****************************************************************************** + + @Function ResManDeInit + + @Description de-initialises the resman + + @Return none + +******************************************************************************/ IMG_VOID ResManDeInit(IMG_VOID) { if (gpsResList != IMG_NULL) { - OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*gpsResList), gpsResList, IMG_NULL); gpsResList = IMG_NULL; } } +/*! +****************************************************************************** + + @Function PVRSRVResManConnect + + @Description Opens a connection to the Resource Manager + + @input hPerProc - Per-process data (if applicable) + @output phResManContext - Resman context + + @Return error code or PVRSRV_OK + +******************************************************************************/ PVRSRV_ERROR PVRSRVResManConnect(IMG_HANDLE hPerProc, PRESMAN_CONTEXT *phResManContext) { PVRSRV_ERROR eError; PRESMAN_CONTEXT psResManContext; - + /*Acquire resource list sync object*/ ACQUIRE_SYNC_OBJ; - + /*Check resource list*/ VALIDATERESLIST(); - + /* Allocate memory for the new context. */ eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psResManContext), (IMG_VOID **)&psResManContext, IMG_NULL, "Resource Manager Context"); @@ -214,10 +271,10 @@ PVRSRV_ERROR PVRSRVResManConnect(IMG_HANDLE hPerProc, { PVR_DPF((PVR_DBG_ERROR, "PVRSRVResManConnect: ERROR allocating new RESMAN context struct")); - + /* Check resource list */ VALIDATERESLIST(); - + /* Release resource list sync object */ RELEASE_SYNC_OBJ; return eError; @@ -225,17 +282,17 @@ PVRSRV_ERROR PVRSRVResManConnect(IMG_HANDLE hPerProc, #ifdef DEBUG psResManContext->ui32Signature = RESMAN_SIGNATURE; -#endif +#endif /* DEBUG */ psResManContext->psResItemList = IMG_NULL; psResManContext->psPerProc = hPerProc; - + /* Insert new context struct after the dummy first entry */ List_RESMAN_CONTEXT_Insert(&gpsResList->psContextList, psResManContext); - + /* Check resource list */ VALIDATERESLIST(); - + /* Release resource list sync object */ RELEASE_SYNC_OBJ; *phResManContext = psResManContext; @@ -244,38 +301,51 @@ PVRSRV_ERROR PVRSRVResManConnect(IMG_HANDLE hPerProc, } +/*! +****************************************************************************** + + @Function PVRSRVResManDisconnect + + @Description Closes a Resource Manager connection and frees all resources + + @input hResManContext - Resman context + @input bKernelContext - IMG_TRUE for kernel contexts + + @Return IMG_VOID + +******************************************************************************/ IMG_VOID PVRSRVResManDisconnect(PRESMAN_CONTEXT psResManContext, IMG_BOOL bKernelContext) { - + /* Acquire resource list sync object */ ACQUIRE_SYNC_OBJ; - + /* Check resource list */ VALIDATERESLIST(); - + /* Print and validate resource list */ PRINT_RESLIST(gpsResList, psResManContext, IMG_TRUE); - + /* Free all auto-freed resources in order */ if (!bKernelContext) { - + /* OS specific User-mode Mappings: */ FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_OS_USERMODE_MAPPING, 0, 0, IMG_TRUE); - + /* VGX types: */ FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_DMA_CLIENT_FIFO_DATA, 0, 0, IMG_TRUE); - + /* Event Object */ FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_EVENT_OBJECT, 0, 0, IMG_TRUE); - - + /* syncobject state (Read/Write Complete values) */ + /* Must be FIFO, so we reverse the list, twice */ List_RESMAN_ITEM_Reverse(&psResManContext->psResItemList); FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_MODIFY_SYNC_OPS, 0, 0, IMG_TRUE); - List_RESMAN_ITEM_Reverse(&psResManContext->psResItemList); + List_RESMAN_ITEM_Reverse(&psResManContext->psResItemList); // (could survive without this - all following items would be cleared up "fifo" too) - + /* SGX types: */ FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_HW_RENDER_CONTEXT, 0, 0, IMG_TRUE); FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_HW_TRANSFER_CONTEXT, 0, 0, IMG_TRUE); FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_HW_2D_CONTEXT, 0, 0, IMG_TRUE); @@ -283,9 +353,7 @@ IMG_VOID PVRSRVResManDisconnect(PRESMAN_CONTEXT psResManContext, FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_SHARED_PB_DESC_CREATE_LOCK, 0, 0, IMG_TRUE); FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_SHARED_PB_DESC, 0, 0, IMG_TRUE); - - - + /* COMMON types: */ FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_SYNC_INFO, 0, 0, IMG_TRUE); FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_DEVICECLASSMEM_MAPPING, 0, 0, IMG_TRUE); FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_DEVICEMEM_WRAP, 0, 0, IMG_TRUE); @@ -294,37 +362,57 @@ IMG_VOID PVRSRVResManDisconnect(PRESMAN_CONTEXT psResManContext, FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_DEVICEMEM_ALLOCATION, 0, 0, IMG_TRUE); FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_DEVICEMEM_CONTEXT, 0, 0, IMG_TRUE); FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_SHARED_MEM_INFO, 0, 0, IMG_TRUE); - - +#if defined(SUPPORT_ION) + FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_DEVICEMEM_ION, 0, 0, IMG_TRUE); +#endif + /* DISPLAY CLASS types: */ FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_DISPLAYCLASS_SWAPCHAIN_REF, 0, 0, IMG_TRUE); FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_DISPLAYCLASS_DEVICE, 0, 0, IMG_TRUE); - + /* BUFFER CLASS types: */ FreeResourceByCriteria(psResManContext, RESMAN_CRITERIA_RESTYPE, RESMAN_TYPE_BUFFERCLASS_DEVICE, 0, 0, IMG_TRUE); } - + /* Ensure that there are no resources left */ PVR_ASSERT(psResManContext->psResItemList == IMG_NULL); - + /* Remove the context struct from the list */ List_RESMAN_CONTEXT_Remove(psResManContext); - + /* Free the context struct */ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(RESMAN_CONTEXT), psResManContext, IMG_NULL); - + /*not nulling pointer, copy on stack*/ - + /* Check resource list */ VALIDATERESLIST(); - + /* Print and validate resource list */ PRINT_RESLIST(gpsResList, psResManContext, IMG_FALSE); - + /* Release resource list sync object */ RELEASE_SYNC_OBJ; } +/*! +****************************************************************************** + @Function ResManRegisterRes + + @Description : Inform the resource manager that the given resource has + been alloacted and freeing of it will be the responsibility + of the resource manager + + @input psResManContext - resman context + @input ui32ResType - identify what kind of resource it is + @input pvParam - address of resource + @input ui32Param - size of resource + @input pfnFreeResource - pointer to function that frees this resource + + @Return On success a pointer to an opaque data structure that represents + the allocated resource, else NULL + +**************************************************************************/ PRESMAN_ITEM ResManRegisterRes(PRESMAN_CONTEXT psResManContext, IMG_UINT32 ui32ResType, IMG_PVOID pvParam, @@ -342,10 +430,10 @@ PRESMAN_ITEM ResManRegisterRes(PRESMAN_CONTEXT psResManContext, return (PRESMAN_ITEM) IMG_NULL; } - + /* Acquire resource list sync object */ ACQUIRE_SYNC_OBJ; - + /* Check resource list */ VALIDATERESLIST(); PVR_DPF((PVR_DBG_MESSAGE, "ResManRegisterRes: register resource " @@ -357,7 +445,7 @@ PRESMAN_ITEM ResManRegisterRes(PRESMAN_CONTEXT psResManContext, ui32Param, (IMG_UINTPTR_T)pfnFreeResource)); - + /* Allocate memory for the new resource structure */ if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(RESMAN_ITEM), (IMG_VOID **)&psNewResItem, IMG_NULL, @@ -366,34 +454,45 @@ PRESMAN_ITEM ResManRegisterRes(PRESMAN_CONTEXT psResManContext, PVR_DPF((PVR_DBG_ERROR, "ResManRegisterRes: " "ERROR allocating new resource item")); - + /* Release resource list sync object */ RELEASE_SYNC_OBJ; return((PRESMAN_ITEM)IMG_NULL); } - + /* Fill in details about this resource */ #ifdef DEBUG psNewResItem->ui32Signature = RESMAN_SIGNATURE; -#endif +#endif /* DEBUG */ psNewResItem->ui32ResType = ui32ResType; psNewResItem->pvParam = pvParam; psNewResItem->ui32Param = ui32Param; psNewResItem->pfnFreeResource = pfnFreeResource; psNewResItem->ui32Flags = 0; - + /* Insert new structure after dummy first entry */ List_RESMAN_ITEM_Insert(&psResManContext->psResItemList, psNewResItem); - + /* Check resource list */ VALIDATERESLIST(); - + /* Release resource list sync object */ RELEASE_SYNC_OBJ; return(psNewResItem); } +/*! +****************************************************************************** + @Function ResManFreeResByPtr + + @Description frees a resource by matching on pointer type + + @inputs psResItem - pointer to resource item to free + bForceCleanup - ignored uKernel re-sync + + @Return PVRSRV_ERROR +**************************************************************************/ PVRSRV_ERROR ResManFreeResByPtr(RESMAN_ITEM *psResItem, IMG_BOOL bForceCleanup) { PVRSRV_ERROR eError; @@ -409,25 +508,40 @@ PVRSRV_ERROR ResManFreeResByPtr(RESMAN_ITEM *psResItem, IMG_BOOL bForceCleanup) PVR_DPF((PVR_DBG_MESSAGE, "ResManFreeResByPtr: freeing resource at %08X", (IMG_UINTPTR_T)psResItem)); - + /*Acquire resource list sync object*/ ACQUIRE_SYNC_OBJ; - + /*Check resource list*/ VALIDATERESLIST(); - + /*Free resource*/ eError = FreeResourceByPtr(psResItem, IMG_TRUE, bForceCleanup); - + /*Check resource list*/ VALIDATERESLIST(); - + /*Release resource list sync object*/ RELEASE_SYNC_OBJ; return(eError); } +/*! +****************************************************************************** + @Function ResManFreeResByCriteria + + @Description frees a resource by matching on criteria + + @inputs hResManContext - handle for resman context + @inputs ui32SearchCriteria - indicates which parameters should be + used in search for resources to free + @inputs ui32ResType - identify what kind of resource to free + @inputs pvParam - address of resource to be free + @inputs ui32Param - size of resource to be free + + @Return PVRSRV_ERROR +**************************************************************************/ PVRSRV_ERROR ResManFreeResByCriteria(PRESMAN_CONTEXT psResManContext, IMG_UINT32 ui32SearchCriteria, IMG_UINT32 ui32ResType, @@ -438,10 +552,10 @@ PVRSRV_ERROR ResManFreeResByCriteria(PRESMAN_CONTEXT psResManContext, PVR_ASSERT(psResManContext != IMG_NULL); - + /* Acquire resource list sync object */ ACQUIRE_SYNC_OBJ; - + /* Check resource list */ VALIDATERESLIST(); PVR_DPF((PVR_DBG_MESSAGE, "ResManFreeResByCriteria: " @@ -449,21 +563,32 @@ PVRSRV_ERROR ResManFreeResByCriteria(PRESMAN_CONTEXT psResManContext, (IMG_UINTPTR_T)psResManContext, ui32SearchCriteria, ui32ResType, (IMG_UINTPTR_T)pvParam, ui32Param)); - + /* Free resources by criteria for this context */ eError = FreeResourceByCriteria(psResManContext, ui32SearchCriteria, ui32ResType, pvParam, ui32Param, IMG_TRUE); - + /* Check resource list */ VALIDATERESLIST(); - + /* Release resource list sync object */ RELEASE_SYNC_OBJ; return eError; } +/*! +****************************************************************************** + @Function ResManDissociateRes + + @Description Moves a resource from one context to another. + + @inputs psResItem - pointer to resource item to dissociate + @inputs psNewResManContext - new resman context for the resource + + @Return IMG_VOID +**************************************************************************/ PVRSRV_ERROR ResManDissociateRes(RESMAN_ITEM *psResItem, PRESMAN_CONTEXT psNewResManContext) { @@ -478,16 +603,16 @@ PVRSRV_ERROR ResManDissociateRes(RESMAN_ITEM *psResItem, return PVRSRV_ERROR_INVALID_PARAMS; } -#ifdef DEBUG +#ifdef DEBUG /* QAC fix */ PVR_ASSERT(psResItem->ui32Signature == RESMAN_SIGNATURE); #endif if (psNewResManContext != IMG_NULL) { - + /* Remove this item from its old resource list */ List_RESMAN_ITEM_Remove(psResItem); - + /* Re-insert into new list */ List_RESMAN_ITEM_Insert(&psNewResManContext->psResItemList, psResItem); } @@ -504,6 +629,19 @@ PVRSRV_ERROR ResManDissociateRes(RESMAN_ITEM *psResItem, return eError; } +/*! +****************************************************************************** + @Function ResManFindResourceByPtr_AnyVaCb + + @Description + Compares the resman item with a given pointer. + + @inputs psCurItem - theThe item to check + @inputs va - Variable argument list with: + psItem - pointer to resource item to find + + @Return IMG_BOOL +**************************************************************************/ static IMG_BOOL ResManFindResourceByPtr_AnyVaCb(RESMAN_ITEM *psCurItem, va_list va) { RESMAN_ITEM *psItem; @@ -514,9 +652,23 @@ static IMG_BOOL ResManFindResourceByPtr_AnyVaCb(RESMAN_ITEM *psCurItem, va_list } +/*! +****************************************************************************** + @Function ResManFindResourceByPtr + + @Description + Attempts to find a resource in the list for this context + + @inputs hResManContext - handle for resman context + @inputs psItem - pointer to resource item to find + + @Return PVRSRV_ERROR +**************************************************************************/ IMG_INTERNAL PVRSRV_ERROR ResManFindResourceByPtr(PRESMAN_CONTEXT psResManContext, RESMAN_ITEM *psItem) { +/* RESMAN_ITEM *psCurItem;*/ + PVRSRV_ERROR eResult; PVR_ASSERT(psResManContext != IMG_NULL); @@ -529,11 +681,11 @@ IMG_INTERNAL PVRSRV_ERROR ResManFindResourceByPtr(PRESMAN_CONTEXT psResManContex return PVRSRV_ERROR_INVALID_PARAMS; } -#ifdef DEBUG +#ifdef DEBUG /* QAC fix */ PVR_ASSERT(psItem->ui32Signature == RESMAN_SIGNATURE); #endif - + /* Acquire resource list sync object */ ACQUIRE_SYNC_OBJ; PVR_DPF((PVR_DBG_MESSAGE, @@ -550,7 +702,7 @@ IMG_INTERNAL PVRSRV_ERROR ResManFindResourceByPtr(PRESMAN_CONTEXT psResManContex (IMG_UINTPTR_T)psItem->pfnFreeResource, psItem->ui32Flags)); - + /* Search resource items starting at after the first dummy item */ if(List_RESMAN_ITEM_IMG_BOOL_Any_va(psResManContext->psResItemList, &ResManFindResourceByPtr_AnyVaCb, psItem)) @@ -562,12 +714,28 @@ IMG_INTERNAL PVRSRV_ERROR ResManFindResourceByPtr(PRESMAN_CONTEXT psResManContex eResult = PVRSRV_ERROR_NOT_OWNER; } - + /* Release resource list sync object */ RELEASE_SYNC_OBJ; +/* return PVRSRV_ERROR_NOT_OWNER;*/ return eResult; } +/*! +****************************************************************************** + @Function FreeResourceByPtr + + @Description + Frees a resource and move it from the list + NOTE : this function must be called with the resource + list sync object held + + @inputs psItem - pointer to resource item to free + bExecuteCallback - execute callback? + bForceCleanup - skips uKernel re-sync + + @Return PVRSRV_ERROR +**************************************************************************/ static PVRSRV_ERROR FreeResourceByPtr(RESMAN_ITEM *psItem, IMG_BOOL bExecuteCallback, IMG_BOOL bForceCleanup) @@ -582,7 +750,7 @@ static PVRSRV_ERROR FreeResourceByPtr(RESMAN_ITEM *psItem, return PVRSRV_ERROR_INVALID_PARAMS; } -#ifdef DEBUG +#ifdef DEBUG /* QAC fix */ PVR_ASSERT(psItem->ui32Signature == RESMAN_SIGNATURE); #endif @@ -597,32 +765,52 @@ static PVRSRV_ERROR FreeResourceByPtr(RESMAN_ITEM *psItem, (IMG_UINTPTR_T)psItem->pvParam, psItem->ui32Param, (IMG_UINTPTR_T)psItem->pfnFreeResource, psItem->ui32Flags)); - - List_RESMAN_ITEM_Remove(psItem); - - - + /* Release resource list sync object just in case the free routine calls the resource manager */ RELEASE_SYNC_OBJ; - + /* Call the freeing routine */ if (bExecuteCallback) { eError = psItem->pfnFreeResource(psItem->pvParam, psItem->ui32Param, bForceCleanup); - if (eError != PVRSRV_OK) + if ((eError != PVRSRV_OK) && (eError != PVRSRV_ERROR_RETRY)) { PVR_DPF((PVR_DBG_ERROR, "FreeResourceByPtr: ERROR calling FreeResource function")); } } - + /* Acquire resource list sync object */ ACQUIRE_SYNC_OBJ; - - OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(RESMAN_ITEM), psItem, IMG_NULL); + if (eError != PVRSRV_ERROR_RETRY) + { + /* Remove this item from the resource list */ + List_RESMAN_ITEM_Remove(psItem); + + /* Free memory for the resource item */ + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(RESMAN_ITEM), psItem, IMG_NULL); + } return(eError); } +/*! +****************************************************************************** + @Function FreeResourceByCriteria_AnyVaCb + + @Description + Matches a resource manager item with a given criteria. + + @inputs psCuItem - the item to be matched + @inputs va - a variable argument list with:. + ui32SearchCriteria - indicates which parameters should be used + search for resources to free + ui32ResType - identify what kind of resource to free + pvParam - address of resource to be free + ui32Param - size of resource to be free + + + @Return psCurItem if matched, IMG_NULL otherwise. +**************************************************************************/ static IMG_VOID* FreeResourceByCriteria_AnyVaCb(RESMAN_ITEM *psCurItem, va_list va) { IMG_UINT32 ui32SearchCriteria; @@ -635,17 +823,17 @@ static IMG_VOID* FreeResourceByCriteria_AnyVaCb(RESMAN_ITEM *psCurItem, va_list pvParam = va_arg(va, IMG_PVOID); ui32Param = va_arg(va, IMG_UINT32); - + /*check that for all conditions are either disabled or eval to true*/ if( - + /* Check resource type */ (((ui32SearchCriteria & RESMAN_CRITERIA_RESTYPE) == 0UL) || (psCurItem->ui32ResType == ui32ResType)) && - + /* Check address */ (((ui32SearchCriteria & RESMAN_CRITERIA_PVOID_PARAM) == 0UL) || (psCurItem->pvParam == pvParam)) && - + /* Check size */ (((ui32SearchCriteria & RESMAN_CRITERIA_UI32_PARAM) == 0UL) || (psCurItem->ui32Param == ui32Param)) ) @@ -658,6 +846,27 @@ static IMG_VOID* FreeResourceByCriteria_AnyVaCb(RESMAN_ITEM *psCurItem, va_list } } +/*! +****************************************************************************** + @Function FreeResourceByCriteria + + @Description + Frees all resources that match the given criteria for the + context. + NOTE : this function must be called with the resource + list sync object held + + @inputs psResManContext - pointer to resman context + @inputs ui32SearchCriteria - indicates which parameters should be used + @inputs search for resources to free + @inputs ui32ResType - identify what kind of resource to free + @inputs pvParam - address of resource to be free + @inputs ui32Param - size of resource to be free + @inputs ui32AutoFreeLev - auto free level to free + @inputs bExecuteCallback - execute callback? + + @Return PVRSRV_ERROR +**************************************************************************/ static PVRSRV_ERROR FreeResourceByCriteria(PRESMAN_CONTEXT psResManContext, IMG_UINT32 ui32SearchCriteria, IMG_UINT32 ui32ResType, @@ -668,8 +877,8 @@ static PVRSRV_ERROR FreeResourceByCriteria(PRESMAN_CONTEXT psResManContext, PRESMAN_ITEM psCurItem; PVRSRV_ERROR eError = PVRSRV_OK; - - + /* Search resource items starting at after the first dummy item */ + /*while we get a match and not an error*/ while((psCurItem = (PRESMAN_ITEM) List_RESMAN_ITEM_Any_va(psResManContext->psResItemList, &FreeResourceByCriteria_AnyVaCb, @@ -679,7 +888,19 @@ static PVRSRV_ERROR FreeResourceByCriteria(PRESMAN_CONTEXT psResManContext, ui32Param)) != IMG_NULL && eError == PVRSRV_OK) { - eError = FreeResourceByPtr(psCurItem, bExecuteCallback, CLEANUP_WITH_POLL); + do + { + eError = FreeResourceByPtr(psCurItem, bExecuteCallback, CLEANUP_WITH_POLL); + if (eError == PVRSRV_ERROR_RETRY) + { + RELEASE_SYNC_OBJ; + OSReleaseBridgeLock(); + /* Give a chance for other threads to come in and SGX to do more work */ + OSSleepms(MAX_CLEANUP_TIME_WAIT_US/1000); + OSReacquireBridgeLock(); + ACQUIRE_SYNC_OBJ; + } + } while (eError == PVRSRV_ERROR_RETRY); } return eError; @@ -687,12 +908,23 @@ static PVRSRV_ERROR FreeResourceByCriteria(PRESMAN_CONTEXT psResManContext, #ifdef DEBUG +/*! +****************************************************************************** + @Function ValidateResList + + @Description + Walks the resource list check the pointers + NOTE : this function must be called with the resource + list sync object held + + @Return none +**************************************************************************/ static IMG_VOID ValidateResList(PRESMAN_LIST psResList) { PRESMAN_ITEM psCurItem, *ppsThisItem; PRESMAN_CONTEXT psCurContext, *ppsThisContext; - + /* check we're initialised */ if (psResList == IMG_NULL) { PVR_DPF((PVR_DBG_MESSAGE, "ValidateResList: resman not initialised yet")); @@ -702,10 +934,10 @@ static IMG_VOID ValidateResList(PRESMAN_LIST psResList) psCurContext = psResList->psContextList; ppsThisContext = &psResList->psContextList; - + /* Walk the context list */ while(psCurContext != IMG_NULL) { - + /* Check current item */ PVR_ASSERT(psCurContext->ui32Signature == RESMAN_SIGNATURE); if (psCurContext->ppsThis != ppsThisContext) { @@ -718,12 +950,12 @@ static IMG_VOID ValidateResList(PRESMAN_LIST psResList) PVR_ASSERT(psCurContext->ppsThis == ppsThisContext); } - + /* Walk the list for this context */ psCurItem = psCurContext->psResItemList; ppsThisItem = &psCurContext->psResItemList; while(psCurItem != IMG_NULL) { - + /* Check current item */ PVR_ASSERT(psCurItem->ui32Signature == RESMAN_SIGNATURE); if (psCurItem->ppsThis != ppsThisItem) { @@ -736,16 +968,19 @@ static IMG_VOID ValidateResList(PRESMAN_LIST psResList) PVR_ASSERT(psCurItem->ppsThis == ppsThisItem); } - + /* Move to next item */ ppsThisItem = &psCurItem->psNext; psCurItem = psCurItem->psNext; } - + /* Move to next context */ ppsThisContext = &psCurContext->psNext; psCurContext = psCurContext->psNext; } } -#endif +#endif /* DEBUG */ +/****************************************************************************** + End of file (resman.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/devices/sgx/mmu.c b/sgx/services4/srvkm/devices/sgx/mmu.c index 9fa93d0..7f1fe9c 100644 --- a/sgx/services4/srvkm/devices/sgx/mmu.c +++ b/sgx/services4/srvkm/devices/sgx/mmu.c @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title MMU Management +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Implements basic low level control of MMU. +@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 "sgxdefs.h" #include "sgxmmu.h" @@ -41,34 +58,79 @@ #define UINT32_MAX_VALUE 0xFFFFFFFFUL +/* + MMU performs device virtual to physical translation. + terminology: + page directory (PD) + pagetable (PT) + data page (DP) + + Incoming 32bit Device Virtual Addresses are deconstructed into 3 fields: + --------------------------------------------------------- + | PD Index/tag: | PT Index: | DP offset: | + | bits 31:22 | bits 21:n | bits (n-1):0 | + --------------------------------------------------------- + where typically n=12 for a standard 4k DP + but n=16 for a 64k DP + + MMU page directory (PD), pagetable (PT) and data page (DP) config: + PD: + - always one page per address space + - up to 4k in size to span 4Gb (32bit) + - contains up to 1024 32bit entries + - entries are indexed by the top 12 bits of an incoming 32bit device virtual address + - the PD entry selected contains the physical address of the PT to + perform the next stage of the V to P translation + + PT: + - size depends on the DP size, e.g. 4k DPs have 4k PTs but 16k DPs have 1k PTs + - each PT always spans 4Mb of device virtual address space irrespective of DP size + - number of entries in a PT depend on DP size and ranges from 1024 to 4 entries + - entries are indexed by the PT Index field of the device virtual address (21:n) + - the PT entry selected contains the physical address of the DP to access + + DP: + - size varies from 4k to 4M in multiple of 4 steppings + - DP offset field of the device virtual address ((n-1):0) is used as a byte offset + to address into the DP itself +*/ + #define SGX_MAX_PD_ENTRIES (1<<(SGX_FEATURE_ADDRESS_SPACE_SIZE - SGX_MMU_PT_SHIFT - SGX_MMU_PAGE_SHIFT)) #if defined(FIX_HW_BRN_31620) -#define SGX_MMU_PDE_DUMMY_PAGE (0) -#define SGX_MMU_PTE_DUMMY_PAGE (0) +/* Sim doesn't use the address mask */ +#define SGX_MMU_PDE_DUMMY_PAGE (0)//(0x00000020U) +#define SGX_MMU_PTE_DUMMY_PAGE (0)//(0x00000020U) +/* 4MB adress range per page table */ #define BRN31620_PT_ADDRESS_RANGE_SHIFT 22 #define BRN31620_PT_ADDRESS_RANGE_SIZE (1 << BRN31620_PT_ADDRESS_RANGE_SHIFT) +/* 64MB address range per PDE cache line */ #define BRN31620_PDE_CACHE_FILL_SHIFT 26 #define BRN31620_PDE_CACHE_FILL_SIZE (1 << BRN31620_PDE_CACHE_FILL_SHIFT) #define BRN31620_PDE_CACHE_FILL_MASK (BRN31620_PDE_CACHE_FILL_SIZE - 1) +/* Page Directory Enteries per cache line */ #define BRN31620_PDES_PER_CACHE_LINE_SHIFT (BRN31620_PDE_CACHE_FILL_SHIFT - BRN31620_PT_ADDRESS_RANGE_SHIFT) #define BRN31620_PDES_PER_CACHE_LINE_SIZE (1 << BRN31620_PDES_PER_CACHE_LINE_SHIFT) #define BRN31620_PDES_PER_CACHE_LINE_MASK (BRN31620_PDES_PER_CACHE_LINE_SIZE - 1) +/* Macros for working out offset for dummy pages */ #define BRN31620_DUMMY_PAGE_OFFSET (1 * SGX_MMU_PAGE_SIZE) #define BRN31620_DUMMY_PDE_INDEX (BRN31620_DUMMY_PAGE_OFFSET / BRN31620_PT_ADDRESS_RANGE_SIZE) #define BRN31620_DUMMY_PTE_INDEX ((BRN31620_DUMMY_PAGE_OFFSET - (BRN31620_DUMMY_PDE_INDEX * BRN31620_PT_ADDRESS_RANGE_SIZE))/SGX_MMU_PAGE_SIZE) +/* Cache number of cache lines */ #define BRN31620_CACHE_FLUSH_SHIFT (32 - BRN31620_PDE_CACHE_FILL_SHIFT) #define BRN31620_CACHE_FLUSH_SIZE (1 << BRN31620_CACHE_FLUSH_SHIFT) +/* Cache line bits in a UINT32 */ #define BRN31620_CACHE_FLUSH_BITS_SHIFT 5 #define BRN31620_CACHE_FLUSH_BITS_SIZE (1 << BRN31620_CACHE_FLUSH_BITS_SHIFT) #define BRN31620_CACHE_FLUSH_BITS_MASK (BRN31620_CACHE_FLUSH_BITS_SIZE - 1) +/* Cache line index in array */ #define BRN31620_CACHE_FLUSH_INDEX_BITS (BRN31620_CACHE_FLUSH_SHIFT - BRN31620_CACHE_FLUSH_BITS_SHIFT) #define BRN31620_CACHE_FLUSH_INDEX_SIZE (1 << BRN31620_CACHE_FLUSH_INDEX_BITS) @@ -77,26 +139,44 @@ typedef struct _MMU_PT_INFO_ { - + /* note: may need a union here to accommodate a PT page address for local memory */ IMG_VOID *hPTPageOSMemHandle; IMG_CPU_VIRTADDR PTPageCpuVAddr; - - + /* Map of reserved PTEs. + * Reserved PTEs are like "valid" PTEs in that they (and the DevVAddrs they represent) + * cannot be assigned to another allocation but their "reserved" status persists through + * any amount of mapping and unmapping, until the allocation is finally destroyed. + * + * Reserved and Valid are independent. + * When a PTE is first reserved, it will have Reserved=1 and Valid=0. + * When the PTE is actually mapped, it will have Reserved=1 and Valid=1. + * When the PTE is unmapped, it will have Reserved=1 and Valid=0. + * At this point, the PT will can not be destroyed because although there is + * not an active mapping on the PT, it is known a PTE is reserved for use. + * + * The above sequence of mapping and unmapping may repeat any number of times + * until the allocation is unmapped and destroyed which causes the PTE to have + * Valid=0 and Reserved=0. + */ + /* Number of PTEs set up. + * i.e. have a valid SGX Phys Addr and the "VALID" PTE bit == 1 + */ IMG_UINT32 ui32ValidPTECount; } MMU_PT_INFO; +#define MMU_CONTEXT_NAME_SIZE 50 struct _MMU_CONTEXT_ { - + /* the device node */ PVRSRV_DEVICE_NODE *psDeviceNode; - + /* Page Directory CPUVirt and DevPhys Addresses */ IMG_CPU_VIRTADDR pvPDCpuVAddr; IMG_DEV_PHYADDR sPDDevPAddr; IMG_VOID *hPDOSMemHandle; - + /* information about dynamically allocated pagetables */ MMU_PT_INFO *apsPTInfoList[SGX_MAX_PD_ENTRIES]; PVRSRV_SGXDEV_INFO *psDevInfo; @@ -108,6 +188,9 @@ struct _MMU_CONTEXT_ #endif #endif + IMG_UINT32 ui32PID; + IMG_CHAR szName[MMU_CONTEXT_NAME_SIZE]; + #if defined (FIX_HW_BRN_31620) IMG_UINT32 ui32PDChangeMask[BRN31620_CACHE_FLUSH_INDEX_SIZE]; IMG_UINT32 ui32PDCacheRangeRefCount[BRN31620_CACHE_FLUSH_SIZE]; @@ -118,57 +201,65 @@ struct _MMU_CONTEXT_ struct _MMU_HEAP_ { - + /* MMU context */ MMU_CONTEXT *psMMUContext; - - - + /* + heap specific details: + */ + /* the Base PD index for the heap */ IMG_UINT32 ui32PDBaseIndex; - + /* number of pagetables in this heap */ IMG_UINT32 ui32PageTableCount; - + /* total number of pagetable entries in this heap which may be mapped to data pages */ IMG_UINT32 ui32PTETotalUsable; - + /* PD entry DP size control field */ IMG_UINT32 ui32PDEPageSizeCtrl; - - - + /* + Data Page (DP) Details: + */ + /* size in bytes of a data page */ IMG_UINT32 ui32DataPageSize; - + /* bit width of the data page offset addressing field */ IMG_UINT32 ui32DataPageBitWidth; - + /* bit mask of the data page offset addressing field */ IMG_UINT32 ui32DataPageMask; - - - + /* + PageTable (PT) Details: + */ + /* bit shift to base of PT addressing field */ IMG_UINT32 ui32PTShift; - + /* bit width of the PT addressing field */ IMG_UINT32 ui32PTBitWidth; - + /* bit mask of the PT addressing field */ IMG_UINT32 ui32PTMask; - + /* size in bytes of a pagetable */ IMG_UINT32 ui32PTSize; - + /* Allocated PT Entries per PT */ IMG_UINT32 ui32PTNumEntriesAllocated; - + /* Usable PT Entries per PT (may be different to num allocated for 4MB data page) */ IMG_UINT32 ui32PTNumEntriesUsable; - - - + /* + PageDirectory Details: + */ + /* bit shift to base of PD addressing field */ IMG_UINT32 ui32PDShift; - + /* bit width of the PD addressing field */ IMG_UINT32 ui32PDBitWidth; - + /* bit mask of the PT addressing field */ IMG_UINT32 ui32PDMask; - - + /* + Arena Info: + */ RA_ARENA *psVMArena; DEV_ARENA_DESCRIPTOR *psDevArena; + + /* If we have sparse mappings then we can't do PT level sanity checks */ + IMG_BOOL bHasSparseMappings; #if defined(PDUMP) PDUMP_MMU_ATTRIB sMMUAttrib; #endif @@ -180,6 +271,7 @@ struct _MMU_HEAP_ #define DUMMY_DATA_PAGE_SIGNATURE 0xDEADBEEF #endif +/* local prototypes: */ static IMG_VOID _DeferredFreePageTable (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32PTIndex, IMG_BOOL bOSFreePT); @@ -190,61 +282,241 @@ MMU_PDumpPageTables (MMU_HEAP *pMMUHeap, IMG_SIZE_T uSize, IMG_BOOL bForUnmap, IMG_HANDLE hUniqueTag); -#endif +#endif /* #if defined(PDUMP) */ +/* This option tests page table memory, for use during device bring-up. */ #define PAGE_TEST 0 #if PAGE_TEST static IMG_VOID PageTest(IMG_VOID* pMem, IMG_DEV_PHYADDR sDevPAddr); #endif +/* This option dumps out the PT if an assert fails */ +#define PT_DUMP 1 + +/* This option sanity checks page table PTE valid count matches active PTEs */ #define PT_DEBUG 0 -#if PT_DEBUG +#if (PT_DEBUG || PT_DUMP) && defined(PVRSRV_NEED_PVR_DPF) static IMG_VOID DumpPT(MMU_PT_INFO *psPTInfoList) { IMG_UINT32 *p = (IMG_UINT32*)psPTInfoList->PTPageCpuVAddr; IMG_UINT32 i; - + /* 1024 entries in a 4K page table */ for(i = 0; i < 1024; i += 8) { - PVR_DPF((PVR_DBG_WARNING, + PVR_DPF((PVR_DBG_ERROR, "%08X %08X %08X %08X %08X %08X %08X %08X\n", p[i + 0], p[i + 1], p[i + 2], p[i + 3], p[i + 4], p[i + 5], p[i + 6], p[i + 7])); } } +#else /* (PT_DEBUG || PT_DUMP) && defined(PVRSRV_NEED_PVR_DPF) */ +static INLINE IMG_VOID DumpPT(MMU_PT_INFO *psPTInfoList) +{ + PVR_UNREFERENCED_PARAMETER(psPTInfoList); +} +#endif /* (PT_DEBUG || PT_DUMP) && defined(PVRSRV_NEED_PVR_DPF) */ +#if PT_DEBUG static IMG_VOID CheckPT(MMU_PT_INFO *psPTInfoList) { IMG_UINT32 *p = (IMG_UINT32*) psPTInfoList->PTPageCpuVAddr; IMG_UINT32 i, ui32Count = 0; - + /* 1024 entries in a 4K page table */ for(i = 0; i < 1024; i++) if(p[i] & SGX_MMU_PTE_VALID) ui32Count++; if(psPTInfoList->ui32ValidPTECount != ui32Count) { - PVR_DPF((PVR_DBG_WARNING, "ui32ValidPTECount: %u ui32Count: %u\n", + PVR_DPF((PVR_DBG_ERROR, "ui32ValidPTECount: %u ui32Count: %u\n", psPTInfoList->ui32ValidPTECount, ui32Count)); DumpPT(psPTInfoList); BUG(); } } -#else -static INLINE IMG_VOID DumpPT(MMU_PT_INFO *psPTInfoList) +#else /* PT_DEBUG */ +static INLINE IMG_VOID CheckPT(MMU_PT_INFO *psPTInfoList) { PVR_UNREFERENCED_PARAMETER(psPTInfoList); } +#endif /* PT_DEBUG */ -static INLINE IMG_VOID CheckPT(MMU_PT_INFO *psPTInfoList) +/* + Debug functionality that allows us to make the CPU + mapping of pagetable memory readonly and only make + it read/write when we alter it. This allows us + to check that our memory isn't being overwritten +*/ +#if defined(PVRSRV_MMU_MAKE_READWRITE_ON_DEMAND) + +#include <linux/version.h> + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)) +#ifndef AUTOCONF_INCLUDED +#include <linux/config.h> +#endif +#else +#include <generated/autoconf.h> +#endif + +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/highmem.h> +#include <asm/pgtable.h> +#include <asm/tlbflush.h> + +static IMG_VOID MakeKernelPageReadWrite(IMG_PVOID ulCPUVAddr) { - PVR_UNREFERENCED_PARAMETER(psPTInfoList); + pgd_t *psPGD; + pud_t *psPUD; + pmd_t *psPMD; + pte_t *psPTE; + pte_t ptent; + spinlock_t *psPTLock; + IMG_UINT32 ui32CPUVAddr = (IMG_UINT32) ulCPUVAddr; + struct mm_struct *psMM = current->active_mm; + + + psPGD = pgd_offset(psMM, ui32CPUVAddr); + if (pgd_none(*psPGD) || pgd_bad(*psPGD)) + { + PVR_ASSERT(0); + } + + psPUD = pud_offset(psPGD, ui32CPUVAddr); + if (pud_none(*psPUD) || pud_bad(*psPUD)) + { + PVR_ASSERT(0); + } + + psPMD = pmd_offset(psPUD, ui32CPUVAddr); + if (pmd_none(*psPMD) || pmd_bad(*psPMD)) + { + PVR_ASSERT(0); + } + + psPTE = (pte_t *)pte_offset_map_lock(psMM, psPMD, ui32CPUVAddr, &psPTLock); + + ptent = ptep_modify_prot_start(psMM, ui32CPUVAddr, psPTE); + ptent = pte_mkwrite(ptent); + ptep_modify_prot_commit(psMM, ui32CPUVAddr, psPTE, ptent); + pte_unmap_unlock(psPTE, psPTLock); + + flush_tlb_all(); +} + +static IMG_VOID MakeKernelPageReadOnly(IMG_PVOID ulCPUVAddr) +{ + pgd_t *psPGD; + pud_t *psPUD; + pmd_t *psPMD; + pte_t *psPTE; + pte_t ptent; + spinlock_t *psPTLock; + IMG_UINT32 ui32CPUVAddr = (IMG_UINT32) ulCPUVAddr; + struct mm_struct *psMM = current->active_mm; + + OSWriteMemoryBarrier(); + + psPGD = pgd_offset(psMM, ui32CPUVAddr); + if (pgd_none(*psPGD) || pgd_bad(*psPGD)) + { + PVR_ASSERT(0); + } + + psPUD = pud_offset(psPGD, ui32CPUVAddr); + if (pud_none(*psPUD) || pud_bad(*psPUD)) + { + PVR_ASSERT(0); + } + + psPMD = pmd_offset(psPUD, ui32CPUVAddr); + if (pmd_none(*psPMD) || pmd_bad(*psPMD)) + { + PVR_ASSERT(0); + } + + + psPTE = (pte_t *)pte_offset_map_lock(psMM, psPMD, ui32CPUVAddr, &psPTLock); + + ptent = ptep_modify_prot_start(psMM, ui32CPUVAddr, psPTE); + ptent = pte_wrprotect(ptent); + ptep_modify_prot_commit(psMM, ui32CPUVAddr, psPTE, ptent); + pte_unmap_unlock(psPTE, psPTLock); + + flush_tlb_all(); + } -#endif +#else /* defined(PVRSRV_MMU_MAKE_READWRITE_ON_DEMAND) */ +static INLINE IMG_VOID MakeKernelPageReadWrite(IMG_PVOID ulCPUVAddr) +{ + PVR_UNREFERENCED_PARAMETER(ulCPUVAddr); +} + +static INLINE IMG_VOID MakeKernelPageReadOnly(IMG_PVOID ulCPUVAddr) +{ + PVR_UNREFERENCED_PARAMETER(ulCPUVAddr); +} + +#endif /* defined(PVRSRV_MMU_MAKE_READWRITE_ON_DEMAND) */ + +/*___________________________________________________________________________ + + Information for SUPPORT_PDUMP_MULTI_PROCESS feature. + + The client marked for pdumping will set the bPDumpActive flag in + the MMU Context (see MMU_Initialise). + + Shared heap allocations should be persistent so all apps which + are pdumped will see the allocation. Persistent flag over-rides + the bPDumpActive flag (see pdump_common.c/DbgWrite function). + + The idea is to dump PT,DP for shared heap allocations, but only + dump the PDE if the allocation is mapped into the kernel or active + client context. This ensures if a background app allocates on a + shared heap then all clients can access it in the pdump toolchain. + + + + PD PT DP + +-+ + | |---> +-+ + +-+ | |---> +-+ + +-+ + + + +-+ + + PD allocation/free: pdump flags are 0 (only need PD for active apps) + PT allocation/free: pdump flags are 0 + unless PT is for a shared heap, in which case persistent is set + PD entries (MMU init/insert shared heap): + only pdump if PDE is on the active MMU context, flags are 0 + PD entries (PT alloc): + pdump flags are 0 if kernel heap + pdump flags are 0 if shared heap and PDE is on active MMU context + otherwise ignore. + PT entries pdump flags are 0 + unless PTE is for a shared heap, in which case persistent is set + + NOTE: PDump common code:- + PDumpMallocPages and PDumpMemKM also set the persistent flag for + shared heap allocations. + + ___________________________________________________________________________ +*/ + + +/*! +****************************************************************************** + FUNCTION: MMU_IsHeapShared + + PURPOSE: Is this heap shared? + PARAMETERS: In: pMMU_Heap + RETURNS: true if heap is shared +******************************************************************************/ IMG_BOOL MMU_IsHeapShared(MMU_HEAP* pMMUHeap) { switch(pMMUHeap->psDevArena->DevMemHeapType) @@ -264,78 +536,145 @@ IMG_BOOL MMU_IsHeapShared(MMU_HEAP* pMMUHeap) } #ifdef SUPPORT_SGX_MMU_BYPASS +/*! +****************************************************************************** + FUNCTION: EnableHostAccess + + PURPOSE: Enables Host accesses to device memory, by passing the device + MMU address translation + + PARAMETERS: In: psMMUContext + RETURNS: None +******************************************************************************/ IMG_VOID EnableHostAccess (MMU_CONTEXT *psMMUContext) { IMG_UINT32 ui32RegVal; IMG_VOID *pvRegsBaseKM = psMMUContext->psDevInfo->pvRegsBaseKM; - - - + /* + bypass the MMU for the host port requestor, + conserving bypass state of other requestors + */ ui32RegVal = OSReadHWReg(pvRegsBaseKM, EUR_CR_BIF_CTRL); OSWriteHWReg(pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32RegVal | EUR_CR_BIF_CTRL_MMU_BYPASS_HOST_MASK); - + /* assume we're not wiping-out any other bits */ PDUMPREG(SGX_PDUMPREG_NAME, EUR_CR_BIF_CTRL, EUR_CR_BIF_CTRL_MMU_BYPASS_HOST_MASK); } +/*! +****************************************************************************** + FUNCTION: DisableHostAccess + + PURPOSE: Disables Host accesses to device memory, by passing the device + MMU address translation + + PARAMETERS: In: psMMUContext + RETURNS: None +******************************************************************************/ IMG_VOID DisableHostAccess (MMU_CONTEXT *psMMUContext) { IMG_UINT32 ui32RegVal; IMG_VOID *pvRegsBaseKM = psMMUContext->psDevInfo->pvRegsBaseKM; - - - - + /* + disable MMU-bypass for the host port requestor, + conserving bypass state of other requestors + and flushing all caches/tlbs + */ OSWriteHWReg(pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32RegVal & ~EUR_CR_BIF_CTRL_MMU_BYPASS_HOST_MASK); - + /* assume we're not wiping-out any other bits */ PDUMPREG(SGX_PDUMPREG_NAME, EUR_CR_BIF_CTRL, 0); } #endif #if defined(SGX_FEATURE_SYSTEM_CACHE) +/*! +****************************************************************************** + FUNCTION: MMU_InvalidateSystemLevelCache + + PURPOSE: Invalidates the System Level Cache to purge stale PDEs and PTEs + + PARAMETERS: In: psDevInfo + RETURNS: None + +******************************************************************************/ static IMG_VOID MMU_InvalidateSystemLevelCache(PVRSRV_SGXDEV_INFO *psDevInfo) { #if defined(SGX_FEATURE_MP) psDevInfo->ui32CacheControl |= SGXMKIF_CC_INVAL_BIF_SL; #else - + /* The MMU always bypasses the SLC */ PVR_UNREFERENCED_PARAMETER(psDevInfo); - #endif + #endif /* SGX_FEATURE_MP */ } -#endif +#endif /* SGX_FEATURE_SYSTEM_CACHE */ + +/*! +****************************************************************************** + FUNCTION: MMU_InvalidateDirectoryCache + PURPOSE: Invalidates the page directory cache + page table cache + requestor TLBs + + PARAMETERS: In: psDevInfo + RETURNS: None + +******************************************************************************/ IMG_VOID MMU_InvalidateDirectoryCache(PVRSRV_SGXDEV_INFO *psDevInfo) { psDevInfo->ui32CacheControl |= SGXMKIF_CC_INVAL_BIF_PD; #if defined(SGX_FEATURE_SYSTEM_CACHE) MMU_InvalidateSystemLevelCache(psDevInfo); - #endif + #endif /* SGX_FEATURE_SYSTEM_CACHE */ } +/*! +****************************************************************************** + FUNCTION: MMU_InvalidatePageTableCache + + PURPOSE: Invalidates the page table cache + requestor TLBs + + PARAMETERS: In: psDevInfo + RETURNS: None + +******************************************************************************/ static IMG_VOID MMU_InvalidatePageTableCache(PVRSRV_SGXDEV_INFO *psDevInfo) { psDevInfo->ui32CacheControl |= SGXMKIF_CC_INVAL_BIF_PT; #if defined(SGX_FEATURE_SYSTEM_CACHE) MMU_InvalidateSystemLevelCache(psDevInfo); - #endif + #endif /* SGX_FEATURE_SYSTEM_CACHE */ } #if defined(FIX_HW_BRN_31620) +/*! +****************************************************************************** + FUNCTION: BRN31620InvalidatePageTableEntry + + PURPOSE: Frees page tables in PDE cache line chunks re-wiring the + dummy page when required + + PARAMETERS: In: psMMUContext, ui32PDIndex, ui32PTIndex + RETURNS: None + +******************************************************************************/ static IMG_VOID BRN31620InvalidatePageTableEntry(MMU_CONTEXT *psMMUContext, IMG_UINT32 ui32PDIndex, IMG_UINT32 ui32PTIndex, IMG_UINT32 *pui32PTE) { PVRSRV_SGXDEV_INFO *psDevInfo = psMMUContext->psDevInfo; - + /* + * Note: We can't tell at this stage if this PT will be freed before + * the end of the function so we always wire up the dummy page to + * to the PT. + */ if (((ui32PDIndex % (BRN31620_PDE_CACHE_FILL_SIZE/BRN31620_PT_ADDRESS_RANGE_SIZE)) == BRN31620_DUMMY_PDE_INDEX) && (ui32PTIndex == BRN31620_DUMMY_PTE_INDEX)) { @@ -350,6 +689,17 @@ static IMG_VOID BRN31620InvalidatePageTableEntry(MMU_CONTEXT *psMMUContext, IMG_ } } +/*! +****************************************************************************** + FUNCTION: BRN31620FreePageTable + + PURPOSE: Frees page tables in PDE cache line chunks re-wiring the + dummy page when required + + PARAMETERS: In: psMMUContext, ui32PDIndex + RETURNS: IMG_TRUE if we freed any PT's + +******************************************************************************/ static IMG_BOOL BRN31620FreePageTable(MMU_HEAP *psMMUHeap, IMG_UINT32 ui32PDIndex) { MMU_CONTEXT *psMMUContext = psMMUHeap->psMMUContext; @@ -360,13 +710,18 @@ static IMG_BOOL BRN31620FreePageTable(MMU_HEAP *psMMUHeap, IMG_UINT32 ui32PDInde PVR_ASSERT(psMMUHeap != IMG_NULL); - + /* + * Clear the PT info for this PD index so even if we don't + * free the memory here apsPTInfoList[PDIndex] will trigger + * an "allocation" in _DeferredAllocPagetables which + * bumps up the refcount. + */ PVR_ASSERT(psMMUContext->apsPTInfoListSave[ui32PDIndex] == IMG_NULL); psMMUContext->apsPTInfoListSave[ui32PDIndex] = psMMUContext->apsPTInfoList[ui32PDIndex]; psMMUContext->apsPTInfoList[ui32PDIndex] = IMG_NULL; - + /* Check if this was the last PT in the cache line */ if (--psMMUContext->ui32PDCacheRangeRefCount[ui32PDCacheLine] == 0) { IMG_UINT32 i; @@ -374,10 +729,10 @@ static IMG_BOOL BRN31620FreePageTable(MMU_HEAP *psMMUHeap, IMG_UINT32 ui32PDInde IMG_UINT32 ui32PDIndexEnd = ui32PDIndexStart + BRN31620_PDES_PER_CACHE_LINE_SIZE; IMG_UINT32 ui32PDBitMaskIndex, ui32PDBitMaskShift; - + /* Free all PT's in cache line */ for (i=ui32PDIndexStart;i<ui32PDIndexEnd;i++) { - + /* This PT is _really_ being freed now */ psMMUContext->apsPTInfoList[i] = psMMUContext->apsPTInfoListSave[i]; psMMUContext->apsPTInfoListSave[i] = IMG_NULL; _DeferredFreePageTable(psMMUHeap, i - psMMUHeap->ui32PDBaseIndex, IMG_TRUE); @@ -386,22 +741,27 @@ static IMG_BOOL BRN31620FreePageTable(MMU_HEAP *psMMUHeap, IMG_UINT32 ui32PDInde ui32PDBitMaskIndex = ui32PDCacheLine >> BRN31620_CACHE_FLUSH_BITS_SHIFT; ui32PDBitMaskShift = ui32PDCacheLine & BRN31620_CACHE_FLUSH_BITS_MASK; - + /* Check if this is a shared heap */ if (MMU_IsHeapShared(psMMUHeap)) { - + /* Mark the remove of the Page Table from all memory contexts */ MMU_CONTEXT *psMMUContextWalker = (MMU_CONTEXT*) psMMUHeap->psMMUContext->psDevInfo->pvMMUContextList; while(psMMUContextWalker) { psMMUContextWalker->ui32PDChangeMask[ui32PDBitMaskIndex] |= 1 << ui32PDBitMaskShift; - + /* + * We've just cleared a cache line's worth of PDE's so we need + * to wire up the dummy PT + */ + MakeKernelPageReadWrite(psMMUContextWalker->pvPDCpuVAddr); pui32Tmp = (IMG_UINT32 *) psMMUContextWalker->pvPDCpuVAddr; pui32Tmp[ui32PDIndexStart + BRN31620_DUMMY_PDE_INDEX] = (psDevInfo->sBRN31620DummyPTDevPAddr.uiAddr>>SGX_MMU_PDE_ADDR_ALIGNSHIFT) | SGX_MMU_PDE_PAGE_SIZE_4K | SGX_MMU_PDE_DUMMY_PAGE | SGX_MMU_PDE_VALID; + MakeKernelPageReadOnly(psMMUContextWalker->pvPDCpuVAddr); PDUMPCOMMENT("BRN31620 Re-wire dummy PT due to releasing PT allocation block"); PDUMPPDENTRIES(&psMMUHeap->sMMUAttrib, psMMUContextWalker->hPDOSMemHandle, (IMG_VOID*)&pui32Tmp[ui32PDIndexStart + BRN31620_DUMMY_PDE_INDEX], sizeof(IMG_UINT32), 0, IMG_FALSE, PDUMP_PT_UNIQUETAG, PDUMP_PT_UNIQUETAG); @@ -412,17 +772,22 @@ static IMG_BOOL BRN31620FreePageTable(MMU_HEAP *psMMUHeap, IMG_UINT32 ui32PDInde { psMMUContext->ui32PDChangeMask[ui32PDBitMaskIndex] |= 1 << ui32PDBitMaskShift; - + /* + * We've just cleared a cache line's worth of PDE's so we need + * to wire up the dummy PT + */ + MakeKernelPageReadWrite(psMMUContext->pvPDCpuVAddr); pui32Tmp = (IMG_UINT32 *) psMMUContext->pvPDCpuVAddr; pui32Tmp[ui32PDIndexStart + BRN31620_DUMMY_PDE_INDEX] = (psDevInfo->sBRN31620DummyPTDevPAddr.uiAddr>>SGX_MMU_PDE_ADDR_ALIGNSHIFT) | SGX_MMU_PDE_PAGE_SIZE_4K | SGX_MMU_PDE_DUMMY_PAGE | SGX_MMU_PDE_VALID; + MakeKernelPageReadOnly(psMMUContext->pvPDCpuVAddr); PDUMPCOMMENT("BRN31620 Re-wire dummy PT due to releasing PT allocation block"); PDUMPPDENTRIES(&psMMUHeap->sMMUAttrib, psMMUContext->hPDOSMemHandle, (IMG_VOID*)&pui32Tmp[ui32PDIndexStart + BRN31620_DUMMY_PDE_INDEX], sizeof(IMG_UINT32), 0, IMG_FALSE, PDUMP_PT_UNIQUETAG, PDUMP_PT_UNIQUETAG); } - + /* We've freed a cachline's worth of PDE's so trigger a PD cache flush */ bFreePTs = IMG_TRUE; } @@ -430,6 +795,18 @@ static IMG_BOOL BRN31620FreePageTable(MMU_HEAP *psMMUHeap, IMG_UINT32 ui32PDInde } #endif +/*! +****************************************************************************** + FUNCTION: _AllocPageTableMemory + + PURPOSE: Allocate physical memory for a page table + + PARAMETERS: In: pMMUHeap - the mmu + In: psPTInfoList - PT info + Out: psDevPAddr - device physical address for new PT + RETURNS: IMG_TRUE - Success + IMG_FALSE - Failed +******************************************************************************/ static IMG_BOOL _AllocPageTableMemory (MMU_HEAP *pMMUHeap, MMU_PT_INFO *psPTInfoList, @@ -438,23 +815,33 @@ _AllocPageTableMemory (MMU_HEAP *pMMUHeap, IMG_DEV_PHYADDR sDevPAddr; IMG_CPU_PHYADDR sCpuPAddr; - - - + /* + depending on the specific system, pagetables are allocated from system memory + or device local memory. For now, just look for at least a valid local heap/arena + */ if(pMMUHeap->psDevArena->psDeviceMemoryHeapInfo->psLocalDevMemArena == IMG_NULL) { - + //FIXME: replace with an RA, this allocator only handles 4k allocs if (OSAllocPages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, - pMMUHeap->ui32PTSize, - SGX_MMU_PAGE_SIZE, - (IMG_VOID **)&psPTInfoList->PTPageCpuVAddr, - &psPTInfoList->hPTPageOSMemHandle) != PVRSRV_OK) + pMMUHeap->ui32PTSize, + SGX_MMU_PAGE_SIZE,//FIXME: assume 4K page size for now (wastes memory for smaller pagetables + IMG_NULL, + 0, + IMG_NULL, + (IMG_VOID **)&psPTInfoList->PTPageCpuVAddr, + &psPTInfoList->hPTPageOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "_AllocPageTableMemory: ERROR call to OSAllocPages failed")); return IMG_FALSE; } - + /* + Force the page to read only, we will make it read/write as + and when we need to + */ + MakeKernelPageReadOnly(psPTInfoList->PTPageCpuVAddr); + + /* translate address to device physical */ if(psPTInfoList->PTPageCpuVAddr) { sCpuPAddr = OSMapLinToCPUPhys(psPTInfoList->hPTPageOSMemHandle, @@ -462,7 +849,8 @@ _AllocPageTableMemory (MMU_HEAP *pMMUHeap, } else { - + /* This isn't used in all cases since not all ports currently support + * OSMemHandleToCpuPAddr() */ sCpuPAddr = OSMemHandleToCpuPAddr(psPTInfoList->hPTPageOSMemHandle, 0); } @@ -472,16 +860,19 @@ _AllocPageTableMemory (MMU_HEAP *pMMUHeap, { IMG_SYS_PHYADDR sSysPAddr; - - - - + /* + just allocate from the first local memory arena + (unlikely to be more than one local mem area(?)) + */ + //FIXME: just allocate a 4K page for each PT for now if(RA_Alloc(pMMUHeap->psDevArena->psDeviceMemoryHeapInfo->psLocalDevMemArena, - SGX_MMU_PAGE_SIZE, + SGX_MMU_PAGE_SIZE,//pMMUHeap->ui32PTSize, IMG_NULL, IMG_NULL, 0, - SGX_MMU_PAGE_SIZE, + SGX_MMU_PAGE_SIZE,//pMMUHeap->ui32PTSize, + 0, + IMG_NULL, 0, &(sSysPAddr.uiAddr))!= IMG_TRUE) { @@ -489,9 +880,9 @@ _AllocPageTableMemory (MMU_HEAP *pMMUHeap, return IMG_FALSE; } - + /* derive the CPU virtual address */ sCpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); - + /* note: actual ammount is pMMUHeap->ui32PTSize but must be a multiple of 4k pages */ psPTInfoList->PTPageCpuVAddr = OSMapPhysToLin(sCpuPAddr, SGX_MMU_PAGE_SIZE, PVRSRV_HAP_WRITECOMBINE|PVRSRV_HAP_KERNEL_ONLY, @@ -502,7 +893,7 @@ _AllocPageTableMemory (MMU_HEAP *pMMUHeap, return IMG_FALSE; } - + /* translate address to device physical */ sDevPAddr = SysCpuPAddrToDevPAddr (PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); #if PAGE_TEST @@ -510,60 +901,76 @@ _AllocPageTableMemory (MMU_HEAP *pMMUHeap, #endif } + MakeKernelPageReadWrite(psPTInfoList->PTPageCpuVAddr); #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) { IMG_UINT32 *pui32Tmp; IMG_UINT32 i; pui32Tmp = (IMG_UINT32*)psPTInfoList->PTPageCpuVAddr; - + /* point the new PT entries to the dummy data page */ for(i=0; i<pMMUHeap->ui32PTNumEntriesUsable; i++) { pui32Tmp[i] = (pMMUHeap->psMMUContext->psDevInfo->sDummyDataDevPAddr.uiAddr>>SGX_MMU_PTE_ADDR_ALIGNSHIFT) | SGX_MMU_PTE_VALID; } - + /* zero the remaining allocated entries, if any */ for(; i<pMMUHeap->ui32PTNumEntriesAllocated; i++) { pui32Tmp[i] = 0; } } #else - + /* Zero the page table. */ OSMemSet(psPTInfoList->PTPageCpuVAddr, 0, pMMUHeap->ui32PTSize); #endif + MakeKernelPageReadOnly(psPTInfoList->PTPageCpuVAddr); #if defined(PDUMP) { IMG_UINT32 ui32Flags = 0; #if defined(SUPPORT_PDUMP_MULTI_PROCESS) - + /* make sure shared heap PT allocs are always pdumped */ ui32Flags |= ( MMU_IsHeapShared(pMMUHeap) ) ? PDUMP_FLAGS_PERSISTENT : 0; #endif - + /* pdump the PT malloc */ PDUMPMALLOCPAGETABLE(&pMMUHeap->psMMUContext->psDeviceNode->sDevId, psPTInfoList->hPTPageOSMemHandle, 0, psPTInfoList->PTPageCpuVAddr, pMMUHeap->ui32PTSize, ui32Flags, PDUMP_PT_UNIQUETAG); - + /* pdump the PT Pages */ PDUMPMEMPTENTRIES(&pMMUHeap->sMMUAttrib, psPTInfoList->hPTPageOSMemHandle, psPTInfoList->PTPageCpuVAddr, pMMUHeap->ui32PTSize, ui32Flags, IMG_TRUE, PDUMP_PT_UNIQUETAG, PDUMP_PT_UNIQUETAG); } #endif - - + + /* return the DevPAddr */ *psDevPAddr = sDevPAddr; return IMG_TRUE; } +/*! +****************************************************************************** + FUNCTION: _FreePageTableMemory + + PURPOSE: Free physical memory for a page table + + PARAMETERS: In: pMMUHeap - the mmu + In: psPTInfoList - PT info to free + RETURNS: NONE +******************************************************************************/ static IMG_VOID _FreePageTableMemory (MMU_HEAP *pMMUHeap, MMU_PT_INFO *psPTInfoList) { - - - - + /* + free the PT page: + depending on the specific system, pagetables are allocated from system memory + or device local memory. For now, just look for at least a valid local heap/arena + */ if(pMMUHeap->psDevArena->psDeviceMemoryHeapInfo->psLocalDevMemArena == IMG_NULL) { - + /* Force the page to read write before we free it*/ + MakeKernelPageReadWrite(psPTInfoList->PTPageCpuVAddr); + + //FIXME: replace with an RA, this allocator only handles 4k allocs OSFreePages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, pMMUHeap->ui32PTSize, psPTInfoList->PTPageCpuVAddr, @@ -574,27 +981,39 @@ _FreePageTableMemory (MMU_HEAP *pMMUHeap, MMU_PT_INFO *psPTInfoList) IMG_SYS_PHYADDR sSysPAddr; IMG_CPU_PHYADDR sCpuPAddr; - + /* derive the system physical address */ sCpuPAddr = OSMapLinToCPUPhys(psPTInfoList->hPTPageOSMemHandle, psPTInfoList->PTPageCpuVAddr); sSysPAddr = SysCpuPAddrToSysPAddr (sCpuPAddr); - - + /* unmap the CPU mapping */ + /* note: actual ammount is pMMUHeap->ui32PTSize but must be a multiple of 4k pages */ OSUnMapPhysToLin(psPTInfoList->PTPageCpuVAddr, SGX_MMU_PAGE_SIZE, PVRSRV_HAP_WRITECOMBINE|PVRSRV_HAP_KERNEL_ONLY, psPTInfoList->hPTPageOSMemHandle); - - - + /* + just free from the first local memory arena + (unlikely to be more than one local mem area(?)) + */ RA_Free (pMMUHeap->psDevArena->psDeviceMemoryHeapInfo->psLocalDevMemArena, sSysPAddr.uiAddr, IMG_FALSE); } } +/*! +****************************************************************************** + FUNCTION: _DeferredFreePageTable + + PURPOSE: Free one page table associated with an MMU. + + PARAMETERS: In: pMMUHeap - the mmu heap + In: ui32PTIndex - index of the page table to free relative + to the base of heap. + RETURNS: None +******************************************************************************/ static IMG_VOID _DeferredFreePageTable (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32PTIndex, IMG_BOOL bOSFreePT) { @@ -606,10 +1025,10 @@ _DeferredFreePageTable (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32PTIndex, IMG_BOOL bOS SysAcquireData(&psSysData); - + /* find the index/offset in PD entries */ ui32PDIndex = pMMUHeap->psDevArena->BaseDevVAddr.uiAddr >> pMMUHeap->ui32PDShift; - + /* set the base PT info */ ppsPTInfoList = &pMMUHeap->psMMUContext->apsPTInfoList[ui32PDIndex]; { @@ -617,11 +1036,11 @@ _DeferredFreePageTable (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32PTIndex, IMG_BOOL bOS if(ppsPTInfoList[ui32PTIndex] && ppsPTInfoList[ui32PTIndex]->ui32ValidPTECount > 0) { DumpPT(ppsPTInfoList[ui32PTIndex]); - + /* Fall-through, will fail assert */ } #endif - + /* Assert that all mappings have gone */ PVR_ASSERT(ppsPTInfoList[ui32PTIndex] == IMG_NULL || ppsPTInfoList[ui32PTIndex]->ui32ValidPTECount == 0); } @@ -631,7 +1050,7 @@ _DeferredFreePageTable (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32PTIndex, IMG_BOOL bOS #if defined(SUPPORT_PDUMP_MULTI_PROCESS) ui32Flags |= ( MMU_IsHeapShared(pMMUHeap) ) ? PDUMP_FLAGS_PERSISTENT : 0; #endif - + /* pdump the PT free */ PDUMPCOMMENT("Free page table (page count == %08X)", pMMUHeap->ui32PageTableCount); if(ppsPTInfoList[ui32PTIndex] && ppsPTInfoList[ui32PTIndex]->PTPageCpuVAddr) { @@ -645,30 +1064,32 @@ _DeferredFreePageTable (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32PTIndex, IMG_BOOL bOS case DEVICE_MEMORY_HEAP_SHARED : case DEVICE_MEMORY_HEAP_SHARED_EXPORTED : { - + /* Remove Page Table from all memory contexts */ MMU_CONTEXT *psMMUContext = (MMU_CONTEXT*)pMMUHeap->psMMUContext->psDevInfo->pvMMUContextList; while(psMMUContext) { - + /* get the PD CPUVAddr base and advance to the first entry */ + MakeKernelPageReadWrite(psMMUContext->pvPDCpuVAddr); pui32PDEntry = (IMG_UINT32*)psMMUContext->pvPDCpuVAddr; pui32PDEntry += ui32PDIndex; #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) - + /* point the PD entry to the dummy PT */ pui32PDEntry[ui32PTIndex] = (psMMUContext->psDevInfo->sDummyPTDevPAddr.uiAddr >>SGX_MMU_PDE_ADDR_ALIGNSHIFT) | SGX_MMU_PDE_PAGE_SIZE_4K | SGX_MMU_PDE_VALID; #else - + /* free the entry */ if(bOSFreePT) { pui32PDEntry[ui32PTIndex] = 0; } #endif + MakeKernelPageReadOnly(psMMUContext->pvPDCpuVAddr); #if defined(PDUMP) - + /* pdump the PD Page modifications */ #if defined(SUPPORT_PDUMP_MULTI_PROCESS) if(psMMUContext->bPDumpActive) #endif @@ -676,7 +1097,7 @@ _DeferredFreePageTable (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32PTIndex, IMG_BOOL bOS PDUMPPDENTRIES(&pMMUHeap->sMMUAttrib, psMMUContext->hPDOSMemHandle, (IMG_VOID*)&pui32PDEntry[ui32PTIndex], sizeof(IMG_UINT32), 0, IMG_FALSE, PDUMP_PT_UNIQUETAG, PDUMP_PT_UNIQUETAG); } #endif - + /* advance to next context */ psMMUContext = psMMUContext->psNext; } break; @@ -684,25 +1105,27 @@ _DeferredFreePageTable (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32PTIndex, IMG_BOOL bOS case DEVICE_MEMORY_HEAP_PERCONTEXT : case DEVICE_MEMORY_HEAP_KERNEL : { - + MakeKernelPageReadWrite(pMMUHeap->psMMUContext->pvPDCpuVAddr); + /* Remove Page Table from this memory context only */ pui32PDEntry = (IMG_UINT32*)pMMUHeap->psMMUContext->pvPDCpuVAddr; pui32PDEntry += ui32PDIndex; #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) - + /* point the PD entry to the dummy PT */ pui32PDEntry[ui32PTIndex] = (pMMUHeap->psMMUContext->psDevInfo->sDummyPTDevPAddr.uiAddr >>SGX_MMU_PDE_ADDR_ALIGNSHIFT) | SGX_MMU_PDE_PAGE_SIZE_4K | SGX_MMU_PDE_VALID; #else - + /* free the entry */ if(bOSFreePT) { pui32PDEntry[ui32PTIndex] = 0; } #endif + MakeKernelPageReadOnly(pMMUHeap->psMMUContext->pvPDCpuVAddr); - + /* pdump the PD Page modifications */ PDUMPPDENTRIES(&pMMUHeap->sMMUAttrib, pMMUHeap->psMMUContext->hPDOSMemHandle, (IMG_VOID*)&pui32PDEntry[ui32PTIndex], sizeof(IMG_UINT32), 0, IMG_FALSE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); break; } @@ -713,45 +1136,49 @@ _DeferredFreePageTable (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32PTIndex, IMG_BOOL bOS } } - + /* clear the PT entries in each PT page */ if(ppsPTInfoList[ui32PTIndex] != IMG_NULL) { if(ppsPTInfoList[ui32PTIndex]->PTPageCpuVAddr != IMG_NULL) { IMG_PUINT32 pui32Tmp; + MakeKernelPageReadWrite(ppsPTInfoList[ui32PTIndex]->PTPageCpuVAddr); pui32Tmp = (IMG_UINT32*)ppsPTInfoList[ui32PTIndex]->PTPageCpuVAddr; - + /* clear the entries */ for(i=0; (i<pMMUHeap->ui32PTETotalUsable) && (i<pMMUHeap->ui32PTNumEntriesUsable); i++) { - + /* over-allocated PT entries for 4MB data page case should never be non-zero */ pui32Tmp[i] = 0; } + MakeKernelPageReadOnly(ppsPTInfoList[ui32PTIndex]->PTPageCpuVAddr); - - + /* + free the pagetable memory + */ if(bOSFreePT) { _FreePageTableMemory(pMMUHeap, ppsPTInfoList[ui32PTIndex]); } - - - + /* + decrement the PT Entry Count by the number + of entries we've cleared in this pass + */ pMMUHeap->ui32PTETotalUsable -= i; } else { - + /* decrement the PT Entry Count by a page's worth of entries */ pMMUHeap->ui32PTETotalUsable -= pMMUHeap->ui32PTNumEntriesUsable; } if(bOSFreePT) { - + /* free the pt info */ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(MMU_PT_INFO), ppsPTInfoList[ui32PTIndex], @@ -761,13 +1188,22 @@ _DeferredFreePageTable (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32PTIndex, IMG_BOOL bOS } else { - + /* decrement the PT Entry Count by a page's worth of usable entries */ pMMUHeap->ui32PTETotalUsable -= pMMUHeap->ui32PTNumEntriesUsable; } PDUMPCOMMENT("Finished free page table (page count == %08X)", pMMUHeap->ui32PageTableCount); } +/*! +****************************************************************************** + FUNCTION: _DeferredFreePageTables + + PURPOSE: Free the page tables associated with an MMU. + + PARAMETERS: In: pMMUHeap - the mmu + RETURNS: None +******************************************************************************/ static IMG_VOID _DeferredFreePageTables (MMU_HEAP *pMMUHeap) { @@ -794,14 +1230,17 @@ _DeferredFreePageTables (MMU_HEAP *pMMUHeap) { if (psMMUContext->apsPTInfoList[ui32PDIndex]->PTPageCpuVAddr) { - + /* + * We have to do this to setup the dummy page as + * not all heaps are PD cache size or aligned + */ for (j=0;j<SGX_MMU_PT_SIZE;j++) { pui32Tmp = (IMG_UINT32 *) psMMUContext->apsPTInfoList[ui32PDIndex]->PTPageCpuVAddr; BRN31620InvalidatePageTableEntry(psMMUContext, ui32PDIndex, j, &pui32Tmp[j]); } } - + /* Free the PT and NULL's out the PTInfo */ if (BRN31620FreePageTable(pMMUHeap, ui32PDIndex) == IMG_TRUE) { bInvalidateDirectoryCache = IMG_TRUE; @@ -809,7 +1248,10 @@ _DeferredFreePageTables (MMU_HEAP *pMMUHeap) } } - + /* + * Due to freeing PT's in chunks we might need to flush the PT cache + * rather then the directory cache + */ if (bInvalidateDirectoryCache) { MMU_InvalidateDirectoryCache(pMMUHeap->psMMUContext->psDevInfo); @@ -828,6 +1270,18 @@ _DeferredFreePageTables (MMU_HEAP *pMMUHeap) } +/*! +****************************************************************************** + FUNCTION: _DeferredAllocPagetables + + PURPOSE: allocates page tables at time of allocation + + PARAMETERS: In: pMMUHeap - the mmu heap + DevVAddr - devVAddr of allocation + ui32Size - size of allocation + RETURNS: IMG_TRUE - Success + IMG_FALSE - Failed +******************************************************************************/ static IMG_BOOL _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT32 ui32Size) { @@ -848,23 +1302,23 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT IMG_UINT32 ui32ModifiedCachelines[BRN31620_CACHE_FLUSH_INDEX_SIZE]; #endif - + /* Check device linear address */ #if SGX_FEATURE_ADDRESS_SPACE_SIZE < 32 PVR_ASSERT(DevVAddr.uiAddr < (1<<SGX_FEATURE_ADDRESS_SPACE_SIZE)); #endif - + /* get the sysdata */ SysAcquireData(&psSysData); - + /* find the index/offset in PD entries */ ui32PDIndex = DevVAddr.uiAddr >> pMMUHeap->ui32PDShift; - - + /* how many PDs does the allocation occupy? */ + /* first check for overflows */ if((UINT32_MAX_VALUE - DevVAddr.uiAddr) < (ui32Size + pMMUHeap->ui32DataPageMask + pMMUHeap->ui32PTMask)) { - + /* detected overflow, clamp to highest address */ sHighDevVAddr.uiAddr = UINT32_MAX_VALUE; } else @@ -877,7 +1331,7 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT ui32PageTableCount = sHighDevVAddr.uiAddr >> pMMUHeap->ui32PDShift; - + /* Fix allocation of last 4MB */ if (ui32PageTableCount == 0) ui32PageTableCount = 1024; @@ -887,42 +1341,42 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT ui32ModifiedCachelines[i] = 0; } - - - + /*****************************************************************/ + /* Save off requested data and round allocation to PD cache line */ + /*****************************************************************/ sDevVAddrRequestStart = DevVAddr; ui32PDRequestStart = ui32PDIndex; sDevVAddrRequestEnd = sHighDevVAddr; ui32PDRequestEnd = ui32PageTableCount - 1; - + /* Round allocations down to the PD cacheline */ DevVAddr.uiAddr = DevVAddr.uiAddr & (~BRN31620_PDE_CACHE_FILL_MASK); - + /* Round the end address of the PD allocation to cacheline */ sHighDevVAddr.uiAddr = ((sHighDevVAddr.uiAddr + (BRN31620_PDE_CACHE_FILL_SIZE - 1)) & (~BRN31620_PDE_CACHE_FILL_MASK)); ui32PDIndex = DevVAddr.uiAddr >> pMMUHeap->ui32PDShift; ui32PageTableCount = sHighDevVAddr.uiAddr >> pMMUHeap->ui32PDShift; - + /* Fix allocation of last 4MB */ if (ui32PageTableCount == 0) ui32PageTableCount = 1024; #endif ui32PageTableCount -= ui32PDIndex; - + /* get the PD CPUVAddr base and advance to the first entry */ pui32PDEntry = (IMG_UINT32*)pMMUHeap->psMMUContext->pvPDCpuVAddr; pui32PDEntry += ui32PDIndex; - + /* and advance to the first PT info list */ ppsPTInfoList = &pMMUHeap->psMMUContext->apsPTInfoList[ui32PDIndex]; #if defined(PDUMP) { IMG_UINT32 ui32Flags = 0; - + /* pdump the PD Page modifications */ if( MMU_IsHeapShared(pMMUHeap) ) { ui32Flags |= PDUMP_FLAGS_CONTINUOUS; @@ -935,16 +1389,16 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT PDUMPCOMMENTWITHFLAGS(ui32Flags, "Page directory mods (page count == %08X)", ui32PageTableCount); } #endif - + /* walk the psPTInfoList to see what needs allocating: */ for(i=0; i<ui32PageTableCount; i++) { if(ppsPTInfoList[i] == IMG_NULL) { #if defined(FIX_HW_BRN_31620) - + /* Check if we have a saved PT (i.e. this PDE cache line is still live) */ if (pMMUHeap->psMMUContext->apsPTInfoListSave[ui32PDIndex + i]) { - + /* Only make this PTInfo "live" if it's requested */ if (((ui32PDIndex + i) >= ui32PDRequestStart) && ((ui32PDIndex + i) <= ui32PDRequestEnd)) { IMG_UINT32 ui32PDCacheLine = (ui32PDIndex + i) >> BRN31620_PDES_PER_CACHE_LINE_SHIFT; @@ -973,7 +1427,7 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT #endif } #if defined(FIX_HW_BRN_31620) - + /* Only try to allocate if ppsPTInfoList[i] is valid */ if (ppsPTInfoList[i]) { #endif @@ -986,7 +1440,7 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT IMG_UINT32 j; #else #if !defined(FIX_HW_BRN_31620) - + /* no page table has been allocated so allocate one */ PVR_ASSERT(pui32PDEntry[i] == 0); #endif #endif @@ -997,7 +1451,7 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT } #if defined(FIX_HW_BRN_31620) bFlushSystemCache = IMG_TRUE; - + /* Bump up the page table count if required */ { IMG_UINT32 ui32PD; IMG_UINT32 ui32PDCacheLine; @@ -1010,7 +1464,7 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT ui32PDBitMaskShift = ui32PDCacheLine & BRN31620_CACHE_FLUSH_BITS_MASK; ui32ModifiedCachelines[ui32PDBitMaskIndex] |= 1 << ui32PDBitMaskShift; - + /* Add 1 to ui32PD as we want the count, not a range */ if ((pMMUHeap->ui32PDBaseIndex + pMMUHeap->ui32PageTableCount) < (ui32PD + 1)) { pMMUHeap->ui32PageTableCount = (ui32PD + 1) - pMMUHeap->ui32PDBaseIndex; @@ -1027,30 +1481,32 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT case DEVICE_MEMORY_HEAP_SHARED : case DEVICE_MEMORY_HEAP_SHARED_EXPORTED : { - + /* insert Page Table into all memory contexts */ MMU_CONTEXT *psMMUContext = (MMU_CONTEXT*)pMMUHeap->psMMUContext->psDevInfo->pvMMUContextList; while(psMMUContext) { - + MakeKernelPageReadWrite(psMMUContext->pvPDCpuVAddr); + /* get the PD CPUVAddr base and advance to the first entry */ pui32PDEntry = (IMG_UINT32*)psMMUContext->pvPDCpuVAddr; pui32PDEntry += ui32PDIndex; - + /* insert the page, specify the data page size and make the pde valid */ pui32PDEntry[i] = (sDevPAddr.uiAddr>>SGX_MMU_PDE_ADDR_ALIGNSHIFT) | pMMUHeap->ui32PDEPageSizeCtrl | SGX_MMU_PDE_VALID; + MakeKernelPageReadOnly(psMMUContext->pvPDCpuVAddr); #if defined(PDUMP) - + /* pdump the PD Page modifications */ #if defined(SUPPORT_PDUMP_MULTI_PROCESS) if(psMMUContext->bPDumpActive) #endif { - + //PDUMPCOMMENT("_DeferredAllocPTs: Dumping shared PDEs on context %d (%s)", psMMUContext->ui32PDumpMMUContextID, (psMMUContext->bPDumpActive) ? "active" : ""); PDUMPPDENTRIES(&pMMUHeap->sMMUAttrib, psMMUContext->hPDOSMemHandle, (IMG_VOID*)&pui32PDEntry[i], sizeof(IMG_UINT32), 0, IMG_FALSE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); } - #endif - + #endif /* PDUMP */ + /* advance to next context */ psMMUContext = psMMUContext->psNext; } #if defined(FIX_HW_BRN_31620) @@ -1061,13 +1517,14 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT case DEVICE_MEMORY_HEAP_PERCONTEXT : case DEVICE_MEMORY_HEAP_KERNEL : { - + MakeKernelPageReadWrite(pMMUHeap->psMMUContext->pvPDCpuVAddr); + /* insert Page Table into only this memory context */ pui32PDEntry[i] = (sDevPAddr.uiAddr>>SGX_MMU_PDE_ADDR_ALIGNSHIFT) | pMMUHeap->ui32PDEPageSizeCtrl | SGX_MMU_PDE_VALID; - - - + MakeKernelPageReadOnly(pMMUHeap->psMMUContext->pvPDCpuVAddr); + /* pdump the PD Page modifications */ + //PDUMPCOMMENT("_DeferredAllocPTs: Dumping kernel PDEs on context %d (%s)", pMMUHeap->psMMUContext->ui32PDumpMMUContextID, (pMMUHeap->psMMUContext->bPDumpActive) ? "active" : ""); PDUMPPDENTRIES(&pMMUHeap->sMMUAttrib, pMMUHeap->psMMUContext->hPDOSMemHandle, (IMG_VOID*)&pui32PDEntry[i], sizeof(IMG_UINT32), 0, IMG_FALSE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); break; } @@ -1079,14 +1536,15 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT } #if !defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) - - - - + /* This is actually not to do with multiple mem contexts, but to do with the directory cache. + In the 1 context implementation of the MMU, the directory "cache" is actually a copy of the + page directory memory, and requires updating whenever the page directory changes, even if there + was no previous value in a particular entry + */ MMU_InvalidateDirectoryCache(pMMUHeap->psMMUContext->psDevInfo); #endif #if defined(FIX_HW_BRN_31620) - + /* If this PT is not in the requested range then save it and null out the main PTInfo */ if (((ui32PDIndex + i) < ui32PDRequestStart) || ((ui32PDIndex + i) > ui32PDRequestEnd)) { pMMUHeap->psMMUContext->apsPTInfoListSave[ui32PDIndex + i] = ppsPTInfoList[i]; @@ -1097,7 +1555,7 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT else { #if !defined(FIX_HW_BRN_31620) - + /* already have an allocated PT */ PVR_ASSERT(pui32PDEntry[i] != 0); #endif } @@ -1108,20 +1566,20 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT #if defined(SGX_FEATURE_SYSTEM_CACHE) #if defined(FIX_HW_BRN_31620) - + /* This function might not allocate any new PT's so check before flushing */ if (bFlushSystemCache) { #endif MMU_InvalidateSystemLevelCache(pMMUHeap->psMMUContext->psDevInfo); - #endif + #endif /* SGX_FEATURE_SYSTEM_CACHE */ #if defined(FIX_HW_BRN_31620) } - + /* Handle the last 4MB roll over */ sHighDevVAddr.uiAddr = sHighDevVAddr.uiAddr - 1; - + /* Update our PD flush mask if required */ if (bFlushSystemCache) { MMU_CONTEXT *psMMUContext; @@ -1137,7 +1595,7 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT psMMUContext->ui32PDChangeMask[i] |= ui32ModifiedCachelines[i]; } - + /* advance to next context */ psMMUContext = psMMUContext->psNext; } } @@ -1149,7 +1607,11 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT } } - + /* + * Always hook up the dummy page when we allocate a new range of PTs. + * It might be this is overwritten before the SGX access the dummy page + * but we don't care, it's a lot simpler to add this logic here. + */ psMMUContext = pMMUHeap->psMMUContext; for (i=0;i<BRN31620_CACHE_FLUSH_INDEX_SIZE;i++) { @@ -1165,7 +1627,7 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT ui32PDIndex = (((i * BRN31620_CACHE_FLUSH_BITS_SIZE) + j) * BRN31620_PDES_PER_CACHE_LINE_SIZE) + BRN31620_DUMMY_PDE_INDEX; - + /* The PT for the dummy page might not be "live". If not get it from the saved pointer */ if (psMMUContext->apsPTInfoList[ui32PDIndex]) { psTempPTInfo = psMMUContext->apsPTInfoList[ui32PDIndex]; @@ -1177,13 +1639,14 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT PVR_ASSERT(psTempPTInfo != IMG_NULL); + MakeKernelPageReadWrite(psTempPTInfo->PTPageCpuVAddr); pui32Tmp = (IMG_UINT32 *) psTempPTInfo->PTPageCpuVAddr; PVR_ASSERT(pui32Tmp != IMG_NULL); pui32Tmp[BRN31620_DUMMY_PTE_INDEX] = (psDevInfo->sBRN31620DummyPageDevPAddr.uiAddr>>SGX_MMU_PTE_ADDR_ALIGNSHIFT) | SGX_MMU_PTE_DUMMY_PAGE | SGX_MMU_PTE_READONLY | SGX_MMU_PTE_VALID; - + MakeKernelPageReadOnly(psTempPTInfo->PTPageCpuVAddr); PDUMPCOMMENT("BRN31620 Dump PTE for dummy page after wireing up new PT"); PDUMPMEMPTENTRIES(&pMMUHeap->sMMUAttrib, psTempPTInfo->hPTPageOSMemHandle, (IMG_VOID *) &pui32Tmp[BRN31620_DUMMY_PTE_INDEX], sizeof(IMG_UINT32), 0, IMG_FALSE, PDUMP_PT_UNIQUETAG, PDUMP_PT_UNIQUETAG); } @@ -1197,20 +1660,44 @@ _DeferredAllocPagetables(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT #if defined(PDUMP) +/*! + * FUNCTION: MMU_GetPDumpContextID + * + * RETURNS: pdump MMU context ID + */ IMG_UINT32 MMU_GetPDumpContextID(IMG_HANDLE hDevMemContext) { BM_CONTEXT *pBMContext = hDevMemContext; PVR_ASSERT(pBMContext); - + /* PRQA S 0505 1 */ /* PVR_ASSERT should catch NULL ptr */ return pBMContext->psMMUContext->ui32PDumpMMUContextID; } +/*! + * FUNCTION: MMU_SetPDumpAttribs + * + * PURPOSE: Called from MMU_Initialise and MMU_Create. + * Sets up device-specific attributes for pdumping. + * FIXME: breaks variable size PTs. Really need separate per context + * and per heap attribs. + * + * INPUT: psDeviceNode - used to access deviceID + * INPUT: ui32DataPageMask - data page mask + * INPUT: ui32PTSize - PT size + * + * OUTPUT: psMMUAttrib - pdump MMU attributes + * + * RETURNS: none + */ +#if defined(SGX_FEATURE_VARIABLE_MMU_PAGE_SIZE) +# error "FIXME: breaks variable size pagetables" +#endif static IMG_VOID MMU_SetPDumpAttribs(PDUMP_MMU_ATTRIB *psMMUAttrib, PVRSRV_DEVICE_NODE *psDeviceNode, IMG_UINT32 ui32DataPageMask, IMG_UINT32 ui32PTSize) { - + /* Sets up device ID, contains pdump memspace name */ psMMUAttrib->sDevId = psDeviceNode->sDevId; psMMUAttrib->pszPDRegRegion = IMG_NULL; @@ -1223,8 +1710,18 @@ static IMG_VOID MMU_SetPDumpAttribs(PDUMP_MMU_ATTRIB *psMMUAttrib, psMMUAttrib->ui32PDEMask = SGX_MMU_PDE_ADDR_MASK; psMMUAttrib->ui32PDEAlignShift = SGX_MMU_PDE_ADDR_ALIGNSHIFT; } -#endif +#endif /* PDUMP */ + +/*! +****************************************************************************** + FUNCTION: MMU_Initialise + + PURPOSE: Called from BM_CreateContext. + Allocates the top level Page Directory 4k Page for the new context. + PARAMETERS: None + RETURNS: PVRSRV_ERROR +******************************************************************************/ PVRSRV_ERROR MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, IMG_DEV_PHYADDR *psPDDevPAddr) { @@ -1244,8 +1741,8 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I SysAcquireData(&psSysData); #if defined(PDUMP) - - + /* Note: these attribs are on the stack, used only to pdump the MMU context + * creation. */ MMU_SetPDumpAttribs(&sMMUAttrib, psDeviceNode, SGX_MMU_PAGE_MASK, SGX_MMU_PT_SIZE * sizeof(IMG_UINT32)); @@ -1262,21 +1759,24 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I } OSMemSet (psMMUContext, 0, sizeof(MMU_CONTEXT)); - + /* stick the devinfo in the context for subsequent use */ psDevInfo = (PVRSRV_SGXDEV_INFO*)psDeviceNode->pvDevice; psMMUContext->psDevInfo = psDevInfo; - + /* record device node for subsequent use */ psMMUContext->psDeviceNode = psDeviceNode; - + /* allocate 4k page directory page for the new context */ if(psDeviceNode->psLocalDevMemArena == IMG_NULL) { if (OSAllocPages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, - SGX_MMU_PAGE_SIZE, - SGX_MMU_PAGE_SIZE, - &pvPDCpuVAddr, - &hPDOSMemHandle) != PVRSRV_OK) + SGX_MMU_PAGE_SIZE, + SGX_MMU_PAGE_SIZE, + IMG_NULL, + 0, + IMG_NULL, + &pvPDCpuVAddr, + &hPDOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "MMU_Initialise: ERROR call to OSAllocPages failed")); return PVRSRV_ERROR_FAILED_TO_ALLOC_PAGES; @@ -1289,7 +1789,8 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I } else { - + /* This is not used in all cases, since not all ports currently + * support OSMemHandleToCpuPAddr */ sCpuPAddr = OSMemHandleToCpuPAddr(hPDOSMemHandle, 0); } sPDDevPAddr = SysCpuPAddrToDevPAddr (PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); @@ -1299,15 +1800,18 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I #endif #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) - + /* Allocate dummy PT and Data pages for the first context to be created */ if(!psDevInfo->pvMMUContextList) { - + /* Dummy PT page */ if (OSAllocPages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, - SGX_MMU_PAGE_SIZE, - SGX_MMU_PAGE_SIZE, - &psDevInfo->pvDummyPTPageCpuVAddr, - &psDevInfo->hDummyPTPageOSMemHandle) != PVRSRV_OK) + SGX_MMU_PAGE_SIZE, + SGX_MMU_PAGE_SIZE, + IMG_NULL, + 0, + IMG_NULL, + &psDevInfo->pvDummyPTPageCpuVAddr, + &psDevInfo->hDummyPTPageOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "MMU_Initialise: ERROR call to OSAllocPages failed")); return PVRSRV_ERROR_FAILED_TO_ALLOC_PAGES; @@ -1320,17 +1824,21 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I } else { - + /* This is not used in all cases, since not all ports currently + * support OSMemHandleToCpuPAddr */ sCpuPAddr = OSMemHandleToCpuPAddr(psDevInfo->hDummyPTPageOSMemHandle, 0); } psDevInfo->sDummyPTDevPAddr = SysCpuPAddrToDevPAddr (PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); - + /* Dummy Data page */ if (OSAllocPages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, - SGX_MMU_PAGE_SIZE, - SGX_MMU_PAGE_SIZE, - &psDevInfo->pvDummyDataPageCpuVAddr, - &psDevInfo->hDummyDataPageOSMemHandle) != PVRSRV_OK) + SGX_MMU_PAGE_SIZE, + SGX_MMU_PAGE_SIZE, + IMG_NULL, + 0, + IMG_NULL, + &psDevInfo->pvDummyDataPageCpuVAddr, + &psDevInfo->hDummyDataPageOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "MMU_Initialise: ERROR call to OSAllocPages failed")); return PVRSRV_ERROR_FAILED_TO_ALLOC_PAGES; @@ -1347,24 +1855,27 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I } psDevInfo->sDummyDataDevPAddr = SysCpuPAddrToDevPAddr (PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); } -#endif +#endif /* #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) */ #if defined(FIX_HW_BRN_31620) - + /* Allocate dummy Data pages for the first context to be created */ if(!psDevInfo->pvMMUContextList) { IMG_UINT32 j; - + /* Allocate dummy page */ if (OSAllocPages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, - SGX_MMU_PAGE_SIZE, - SGX_MMU_PAGE_SIZE, - &psDevInfo->pvBRN31620DummyPageCpuVAddr, - &psDevInfo->hBRN31620DummyPageOSMemHandle) != PVRSRV_OK) + SGX_MMU_PAGE_SIZE, + SGX_MMU_PAGE_SIZE, + IMG_NULL, + 0, + IMG_NULL, + &psDevInfo->pvBRN31620DummyPageCpuVAddr, + &psDevInfo->hBRN31620DummyPageOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "MMU_Initialise: ERROR call to OSAllocPages failed")); return PVRSRV_ERROR_FAILED_TO_ALLOC_PAGES; } - + /* Get a physical address */ if(psDevInfo->pvBRN31620DummyPageCpuVAddr) { sCpuPAddr = OSMapLinToCPUPhys(psDevInfo->hBRN31620DummyPageOSMemHandle, @@ -1384,18 +1895,21 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I psDevInfo->sBRN31620DummyPageDevPAddr = SysCpuPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); PDUMPMALLOCPAGETABLE(&psDeviceNode->sDevId, psDevInfo->hBRN31620DummyPageOSMemHandle, 0, psDevInfo->pvBRN31620DummyPageCpuVAddr, SGX_MMU_PAGE_SIZE, 0, PDUMP_PT_UNIQUETAG); - + /* Allocate dummy PT */ if (OSAllocPages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, - SGX_MMU_PAGE_SIZE, - SGX_MMU_PAGE_SIZE, - &psDevInfo->pvBRN31620DummyPTCpuVAddr, - &psDevInfo->hBRN31620DummyPTOSMemHandle) != PVRSRV_OK) + SGX_MMU_PAGE_SIZE, + SGX_MMU_PAGE_SIZE, + IMG_NULL, + 0, + IMG_NULL, + &psDevInfo->pvBRN31620DummyPTCpuVAddr, + &psDevInfo->hBRN31620DummyPTOSMemHandle) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "MMU_Initialise: ERROR call to OSAllocPages failed")); return PVRSRV_ERROR_FAILED_TO_ALLOC_PAGES; } - + /* Get a physical address */ if(psDevInfo->pvBRN31620DummyPTCpuVAddr) { sCpuPAddr = OSMapLinToCPUPhys(psDevInfo->hBRN31620DummyPTOSMemHandle, @@ -1416,7 +1930,7 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I { IMG_SYS_PHYADDR sSysPAddr; - + /* allocate from the device's local memory arena */ if(RA_Alloc(psDeviceNode->psLocalDevMemArena, SGX_MMU_PAGE_SIZE, IMG_NULL, @@ -1424,13 +1938,15 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I 0, SGX_MMU_PAGE_SIZE, 0, + IMG_NULL, + 0, &(sSysPAddr.uiAddr))!= IMG_TRUE) { PVR_DPF((PVR_DBG_ERROR, "MMU_Initialise: ERROR call to RA_Alloc failed")); return PVRSRV_ERROR_FAILED_TO_ALLOC_VIRT_MEMORY; } - + /* derive the CPU virtual address */ sCpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); sPDDevPAddr = SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sSysPAddr); pvPDCpuVAddr = OSMapPhysToLin(sCpuPAddr, @@ -1448,10 +1964,10 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I #endif #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) - + /* Allocate dummy PT and Data pages for the first context to be created */ if(!psDevInfo->pvMMUContextList) { - + /* Dummy PT page */ if(RA_Alloc(psDeviceNode->psLocalDevMemArena, SGX_MMU_PAGE_SIZE, IMG_NULL, @@ -1459,13 +1975,15 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I 0, SGX_MMU_PAGE_SIZE, 0, + IMG_NULL, + 0, &(sSysPAddr.uiAddr))!= IMG_TRUE) { PVR_DPF((PVR_DBG_ERROR, "MMU_Initialise: ERROR call to RA_Alloc failed")); return PVRSRV_ERROR_FAILED_TO_ALLOC_VIRT_MEMORY; } - + /* derive the CPU virtual address */ sCpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); psDevInfo->sDummyPTDevPAddr = SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sSysPAddr); psDevInfo->pvDummyPTPageCpuVAddr = OSMapPhysToLin(sCpuPAddr, @@ -1478,7 +1996,7 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I return PVRSRV_ERROR_FAILED_TO_MAP_PAGE_TABLE; } - + /* Dummy Data page */ if(RA_Alloc(psDeviceNode->psLocalDevMemArena, SGX_MMU_PAGE_SIZE, IMG_NULL, @@ -1486,13 +2004,15 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I 0, SGX_MMU_PAGE_SIZE, 0, + IMG_NULL, + 0, &(sSysPAddr.uiAddr))!= IMG_TRUE) { PVR_DPF((PVR_DBG_ERROR, "MMU_Initialise: ERROR call to RA_Alloc failed")); return PVRSRV_ERROR_FAILED_TO_ALLOC_VIRT_MEMORY; } - + /* derive the CPU virtual address */ sCpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); psDevInfo->sDummyDataDevPAddr = SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sSysPAddr); psDevInfo->pvDummyDataPageCpuVAddr = OSMapPhysToLin(sCpuPAddr, @@ -1505,13 +2025,13 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I return PVRSRV_ERROR_FAILED_TO_MAP_PAGE_TABLE; } } -#endif +#endif /* #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) */ #if defined(FIX_HW_BRN_31620) - + /* Allocate dummy PT and Data pages for the first context to be created */ if(!psDevInfo->pvMMUContextList) { IMG_UINT32 j; - + /* Allocate dummy page */ if(RA_Alloc(psDeviceNode->psLocalDevMemArena, SGX_MMU_PAGE_SIZE, IMG_NULL, @@ -1519,13 +2039,15 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I 0, SGX_MMU_PAGE_SIZE, 0, + IMG_NULL, + 0, &(sSysPAddr.uiAddr))!= IMG_TRUE) { PVR_DPF((PVR_DBG_ERROR, "MMU_Initialise: ERROR call to RA_Alloc failed")); return PVRSRV_ERROR_FAILED_TO_ALLOC_VIRT_MEMORY; } - + /* derive the CPU virtual address */ sCpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); psDevInfo->sBRN31620DummyPageDevPAddr = SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sSysPAddr); psDevInfo->pvBRN31620DummyPageCpuVAddr = OSMapPhysToLin(sCpuPAddr, @@ -1538,14 +2060,16 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I return PVRSRV_ERROR_FAILED_TO_MAP_PAGE_TABLE; } + MakeKernelPageReadWrite(psDevInfo->pvBRN31620DummyPageCpuVAddr); pui32Tmp = (IMG_UINT32 *)psDevInfo->pvBRN31620DummyPageCpuVAddr; for(j=0; j<(SGX_MMU_PAGE_SIZE/4); j++) { pui32Tmp[j] = BRN31620_DUMMY_PAGE_SIGNATURE; } + MakeKernelPageReadOnly(psDevInfo->pvBRN31620DummyPageCpuVAddr); PDUMPMALLOCPAGETABLE(&psDeviceNode->sDevId, psDevInfo->hBRN31620DummyPageOSMemHandle, 0, psDevInfo->pvBRN31620DummyPageCpuVAddr, SGX_MMU_PAGE_SIZE, 0, PDUMP_PT_UNIQUETAG); - + /* Allocate dummy PT */ if(RA_Alloc(psDeviceNode->psLocalDevMemArena, SGX_MMU_PAGE_SIZE, IMG_NULL, @@ -1553,13 +2077,15 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I 0, SGX_MMU_PAGE_SIZE, 0, + IMG_NULL, + 0, &(sSysPAddr.uiAddr))!= IMG_TRUE) { PVR_DPF((PVR_DBG_ERROR, "MMU_Initialise: ERROR call to RA_Alloc failed")); return PVRSRV_ERROR_FAILED_TO_ALLOC_VIRT_MEMORY; } - + /* derive the CPU virtual address */ sCpuPAddr = SysSysPAddrToCpuPAddr(sSysPAddr); psDevInfo->sBRN31620DummyPTDevPAddr = SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sSysPAddr); psDevInfo->pvBRN31620DummyPTCpuVAddr = OSMapPhysToLin(sCpuPAddr, @@ -1576,13 +2102,13 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I OSMemSet(psDevInfo->pvBRN31620DummyPTCpuVAddr,0,SGX_MMU_PAGE_SIZE); PDUMPMALLOCPAGETABLE(&psDeviceNode->sDevId, psDevInfo->hBRN31620DummyPTOSMemHandle, 0, psDevInfo->pvBRN31620DummyPTCpuVAddr, SGX_MMU_PAGE_SIZE, 0, PDUMP_PT_UNIQUETAG); } -#endif +#endif /* #if defined(FIX_HW_BRN_31620) */ } #if defined(FIX_HW_BRN_31620) if (!psDevInfo->pvMMUContextList) { - + /* Save the kernel MMU context which is always the 1st to be created */ psDevInfo->hKernelMMUContext = psMMUContext; PVR_DPF((PVR_DBG_ERROR, "MMU_Initialise: saving kernel mmu context: %p", psMMUContext)); } @@ -1590,12 +2116,14 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I #if defined(PDUMP) #if defined(SUPPORT_PDUMP_MULTI_PROCESS) - + /* Find out if this context is for the active pdump client. + * If it is, need to ensure PD entries are pdumped whenever another + * process allocates from a shared heap. */ { PVRSRV_PER_PROCESS_DATA* psPerProc = PVRSRVFindPerProcessData(); if(psPerProc == IMG_NULL) { - + /* changes to the kernel context PD/PTs should be pdumped */ psMMUContext->bPDumpActive = IMG_TRUE; } else @@ -1603,8 +2131,8 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I psMMUContext->bPDumpActive = psPerProc->bPDumpActive; } } -#endif - +#endif /* SUPPORT_PDUMP_MULTI_PROCESS */ + /* pdump the PD malloc */ #if IMG_ADDRSPACE_PHYSADDR_BITS == 32 PDUMPCOMMENT("Alloc page directory for new MMU context (PDDevPAddr == 0x%08x)", sPDDevPAddr.uiAddr); @@ -1613,7 +2141,7 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I sPDDevPAddr.uiHighAddr, sPDDevPAddr.uiAddr); #endif PDUMPMALLOCPAGETABLE(&psDeviceNode->sDevId, hPDOSMemHandle, 0, pvPDCpuVAddr, SGX_MMU_PAGE_SIZE, 0, PDUMP_PD_UNIQUETAG); -#endif +#endif /* PDUMP */ #ifdef SUPPORT_SGX_MMU_BYPASS EnableHostAccess(psMMUContext); @@ -1631,55 +2159,65 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) - + MakeKernelPageReadWrite(pvPDCpuVAddr); + /* wire-up the new PD to the dummy PT */ for(i=0; i<SGX_MMU_PD_SIZE; i++) { pui32Tmp[i] = (psDevInfo->sDummyPTDevPAddr.uiAddr>>SGX_MMU_PDE_ADDR_ALIGNSHIFT) | SGX_MMU_PDE_PAGE_SIZE_4K | SGX_MMU_PDE_VALID; } + MakeKernelPageReadOnly(pvPDCpuVAddr); if(!psDevInfo->pvMMUContextList) { - - - + /* + if we've just allocated the dummy pages + wire up the dummy PT to the dummy data page + */ + MakeKernelPageReadWrite(psDevInfo->pvDummyPTPageCpuVAddr); pui32Tmp = (IMG_UINT32 *)psDevInfo->pvDummyPTPageCpuVAddr; for(i=0; i<SGX_MMU_PT_SIZE; i++) { pui32Tmp[i] = (psDevInfo->sDummyDataDevPAddr.uiAddr>>SGX_MMU_PTE_ADDR_ALIGNSHIFT) | SGX_MMU_PTE_VALID; } - + MakeKernelPageReadOnly(psDevInfo->pvDummyPTPageCpuVAddr); + /* pdump the Dummy PT Page */ PDUMPCOMMENT("Dummy Page table contents"); PDUMPMEMPTENTRIES(&sMMUAttrib, psDevInfo->hDummyPTOSMemHandle, psDevInfo->pvDummyPTPageCpuVAddr, SGX_MMU_PAGE_SIZE, 0, IMG_TRUE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); - - + /* + write a signature to the dummy data page + */ + MakeKernelPageReadWrite(psDevInfo->pvDummyDataPageCpuVAddr); pui32Tmp = (IMG_UINT32 *)psDevInfo->pvDummyDataPageCpuVAddr; for(i=0; i<(SGX_MMU_PAGE_SIZE/4); i++) { pui32Tmp[i] = DUMMY_DATA_PAGE_SIGNATURE; } - + MakeKernelPageReadOnly(psDevInfo->pvDummyDataPageCpuVAddr); + /* pdump the Dummy Data Page */ PDUMPCOMMENT("Dummy Data Page contents"); PDUMPMEMPTENTRIES(PVRSRV_DEVICE_TYPE_SGX, psDevInfo->hDummyDataPageOSMemHandle, psDevInfo->pvDummyDataPageCpuVAddr, SGX_MMU_PAGE_SIZE, 0, IMG_TRUE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); } -#else - +#else /* #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) */ + /* initialise the PD to invalid address state */ + MakeKernelPageReadWrite(pvPDCpuVAddr); for(i=0; i<SGX_MMU_PD_SIZE; i++) { - + /* invalid, no read, no write, no cache consistency */ pui32Tmp[i] = 0; } -#endif + MakeKernelPageReadOnly(pvPDCpuVAddr); +#endif /* #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) */ #if defined(PDUMP) #if defined(SUPPORT_PDUMP_MULTI_PROCESS) if(psMMUContext->bPDumpActive) -#endif +#endif /* SUPPORT_PDUMP_MULTI_PROCESS */ { - + /* pdump the PD Page */ PDUMPCOMMENT("Page directory contents"); PDUMPPDENTRIES(&sMMUAttrib, hPDOSMemHandle, pvPDCpuVAddr, SGX_MMU_PAGE_SIZE, 0, IMG_TRUE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); } @@ -1693,59 +2231,62 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I PDUMPCOMMENT("BRN31620 Set up dummy PT"); + MakeKernelPageReadWrite(psDevInfo->pvBRN31620DummyPTCpuVAddr); pui32PT = (IMG_UINT32 *) psDevInfo->pvBRN31620DummyPTCpuVAddr; pui32PT[BRN31620_DUMMY_PTE_INDEX] = (psDevInfo->sBRN31620DummyPageDevPAddr.uiAddr>>SGX_MMU_PTE_ADDR_ALIGNSHIFT) | SGX_MMU_PTE_DUMMY_PAGE | SGX_MMU_PTE_READONLY | SGX_MMU_PTE_VALID; - + MakeKernelPageReadOnly(psDevInfo->pvBRN31620DummyPTCpuVAddr); #if defined(PDUMP) - + /* Dump initial contents */ PDUMPCOMMENT("BRN31620 Dump dummy PT contents"); PDUMPMEMPTENTRIES(&sMMUAttrib, psDevInfo->hBRN31620DummyPTOSMemHandle, psDevInfo->pvBRN31620DummyPTCpuVAddr, SGX_MMU_PAGE_SIZE, 0, IMG_TRUE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); PDUMPCOMMENT("BRN31620 Dump dummy page contents"); PDUMPMEMPTENTRIES(&sMMUAttrib, psDevInfo->hBRN31620DummyPageOSMemHandle, psDevInfo->pvBRN31620DummyPageCpuVAddr, SGX_MMU_PAGE_SIZE, 0, IMG_TRUE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); - + /* Dump the wiring */ for(i=0;i<SGX_MMU_PT_SIZE;i++) { PDUMPMEMPTENTRIES(&sMMUAttrib, psDevInfo->hBRN31620DummyPTOSMemHandle, &pui32PT[i], sizeof(IMG_UINT32), 0, IMG_FALSE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); } #endif PDUMPCOMMENT("BRN31620 Dump PDE wire up"); - + /* Walk the PD wireing up the PT's */ for(i=0;i<SGX_MMU_PD_SIZE;i++) { pui32Tmp[i] = 0; if (ui32PDCount == BRN31620_DUMMY_PDE_INDEX) { + MakeKernelPageReadWrite(pvPDCpuVAddr); pui32Tmp[i] = (psDevInfo->sBRN31620DummyPTDevPAddr.uiAddr>>SGX_MMU_PDE_ADDR_ALIGNSHIFT) | SGX_MMU_PDE_PAGE_SIZE_4K | SGX_MMU_PDE_DUMMY_PAGE | SGX_MMU_PDE_VALID; + MakeKernelPageReadOnly(pvPDCpuVAddr); } PDUMPMEMPTENTRIES(&sMMUAttrib, hPDOSMemHandle, (IMG_VOID *) &pui32Tmp[i], sizeof(IMG_UINT32), 0, IMG_FALSE, PDUMP_PT_UNIQUETAG, PDUMP_PT_UNIQUETAG); ui32PDCount++; if (ui32PDCount == BRN31620_PDES_PER_CACHE_LINE_SIZE) { - + /* Reset PT count */ ui32PDCount = 0; } } - + /* pdump the Dummy PT Page */ PDUMPCOMMENT("BRN31620 dummy Page table contents"); PDUMPMEMPTENTRIES(&sMMUAttrib, psDevInfo->hBRN31620DummyPageOSMemHandle, psDevInfo->pvBRN31620DummyPageCpuVAddr, SGX_MMU_PAGE_SIZE, 0, IMG_TRUE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); } #endif #if defined(PDUMP) - + /* pdump set MMU context */ { PVRSRV_ERROR eError; - + /* default MMU type is 1, 4k page */ IMG_UINT32 ui32MMUType = 1; #if defined(SGX_FEATURE_36BIT_MMU) @@ -1770,7 +2311,7 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I } } - + /* PDump the context ID */ PDUMPCOMMENT("Set MMU context complete (MMU Context ID == %u)", psMMUContext->ui32PDumpMMUContextID); #endif @@ -1790,18 +2331,24 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I psMMUContext->apsPTInfoListSave[i] = IMG_NULL; } #endif - + /* store PD info in the MMU context */ psMMUContext->pvPDCpuVAddr = pvPDCpuVAddr; psMMUContext->sPDDevPAddr = sPDDevPAddr; psMMUContext->hPDOSMemHandle = hPDOSMemHandle; - + /* Get some process information to aid debug */ + psMMUContext->ui32PID = OSGetCurrentProcessIDKM(); + psMMUContext->szName[0] = '\0'; + OSGetCurrentProcessNameKM(psMMUContext->szName, MMU_CONTEXT_NAME_SIZE); + + /* return context */ *ppsMMUContext = psMMUContext; - + /* return the PD DevVAddr */ *psPDDevPAddr = sPDDevPAddr; - + + /* add the new MMU context onto the list of MMU contexts */ psMMUContext->psNext = (MMU_CONTEXT*)psDevInfo->pvMMUContextList; psDevInfo->pvMMUContextList = (IMG_VOID*)psMMUContext; @@ -1812,6 +2359,15 @@ MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, I return PVRSRV_OK; } +/*! +****************************************************************************** + FUNCTION: MMU_Finalise + + PURPOSE: Finalise the mmu module, deallocate all resources. + + PARAMETERS: In: psMMUContext - MMU context to deallocate + RETURNS: None. +******************************************************************************/ IMG_VOID MMU_Finalise (MMU_CONTEXT *psMMUContext) { @@ -1826,11 +2382,11 @@ MMU_Finalise (MMU_CONTEXT *psMMUContext) SysAcquireData(&psSysData); #if defined(PDUMP) - + /* pdump the MMU context clear */ PDUMPCOMMENT("Clear MMU context (MMU Context ID == %u)", psMMUContext->ui32PDumpMMUContextID); PDUMPCLEARMMUCONTEXT(PVRSRV_DEVICE_TYPE_SGX, psMMUContext->psDeviceNode->sDevId.pszPDumpDevName, psMMUContext->ui32PDumpMMUContextID, 2); - + /* pdump the PD free */ #if IMG_ADDRSPACE_PHYSADDR_BITS == 32 PDUMPCOMMENT("Free page directory (PDDevPAddr == 0x%08x)", psMMUContext->sPDDevPAddr.uiAddr); @@ -1838,7 +2394,7 @@ MMU_Finalise (MMU_CONTEXT *psMMUContext) PDUMPCOMMENT("Free page directory, 64-bit arch detected (PDDevPAddr == 0x%08x%08x)", psMMUContext->sPDDevPAddr.uiHighAddr, psMMUContext->sPDDevPAddr.uiAddr); #endif -#endif +#endif /* PDUMP */ PDUMPFREEPAGETABLE(&psMMUContext->psDeviceNode->sDevId, psMMUContext->hPDOSMemHandle, psMMUContext->pvPDCpuVAddr, SGX_MMU_PAGE_SIZE, 0, PDUMP_PT_UNIQUETAG); #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) @@ -1848,29 +2404,33 @@ MMU_Finalise (MMU_CONTEXT *psMMUContext) pui32Tmp = (IMG_UINT32 *)psMMUContext->pvPDCpuVAddr; - + MakeKernelPageReadWrite(psMMUContext->pvPDCpuVAddr); + /* initialise the PD to invalid address state */ for(i=0; i<SGX_MMU_PD_SIZE; i++) { - + /* invalid, no read, no write, no cache consistency */ pui32Tmp[i] = 0; } + MakeKernelPageReadOnly(psMMUContext->pvPDCpuVAddr); - - - - + /* + free the PD: + depending on the specific system, the PD is allocated from system memory + or device local memory. For now, just look for at least a valid local heap/arena + */ if(psMMUContext->psDeviceNode->psLocalDevMemArena == IMG_NULL) { #if defined(FIX_HW_BRN_31620) PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO*)psMMUContext->psDevInfo; #endif + MakeKernelPageReadWrite(psMMUContext->pvPDCpuVAddr); OSFreePages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, SGX_MMU_PAGE_SIZE, psMMUContext->pvPDCpuVAddr, psMMUContext->hPDOSMemHandle); #if defined(FIX_HW_BRN_31620) - + /* If this is the _last_ MMU context it must be the uKernel */ if (!psMMUContextList->psNext) { PDUMPFREEPAGETABLE(&psMMUContext->psDeviceNode->sDevId, psDevInfo->hBRN31620DummyPageOSMemHandle, psDevInfo->pvBRN31620DummyPageCpuVAddr, SGX_MMU_PAGE_SIZE, 0, PDUMP_PT_UNIQUETAG); @@ -1888,7 +2448,7 @@ MMU_Finalise (MMU_CONTEXT *psMMUContext) } #endif #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) - + /* if this is the last context free the dummy pages too */ if(!psMMUContextList->psNext) { OSFreePages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, @@ -1907,82 +2467,82 @@ MMU_Finalise (MMU_CONTEXT *psMMUContext) IMG_SYS_PHYADDR sSysPAddr; IMG_CPU_PHYADDR sCpuPAddr; - + /* derive the system physical address */ sCpuPAddr = OSMapLinToCPUPhys(psMMUContext->hPDOSMemHandle, psMMUContext->pvPDCpuVAddr); sSysPAddr = SysCpuPAddrToSysPAddr(sCpuPAddr); - + /* unmap the CPU mapping */ OSUnMapPhysToLin(psMMUContext->pvPDCpuVAddr, SGX_MMU_PAGE_SIZE, PVRSRV_HAP_WRITECOMBINE|PVRSRV_HAP_KERNEL_ONLY, psMMUContext->hPDOSMemHandle); - + /* and free the memory */ RA_Free (psMMUContext->psDeviceNode->psLocalDevMemArena, sSysPAddr.uiAddr, IMG_FALSE); #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) - + /* if this is the last context free the dummy pages too */ if(!psMMUContextList->psNext) { - + /* free the Dummy PT Page */ sCpuPAddr = OSMapLinToCPUPhys(psDevInfo->hDummyPTPageOSMemHandle, psDevInfo->pvDummyPTPageCpuVAddr); sSysPAddr = SysCpuPAddrToSysPAddr(sCpuPAddr); - + /* unmap the CPU mapping */ OSUnMapPhysToLin(psDevInfo->pvDummyPTPageCpuVAddr, SGX_MMU_PAGE_SIZE, PVRSRV_HAP_WRITECOMBINE|PVRSRV_HAP_KERNEL_ONLY, psDevInfo->hDummyPTPageOSMemHandle); - + /* and free the memory */ RA_Free (psMMUContext->psDeviceNode->psLocalDevMemArena, sSysPAddr.uiAddr, IMG_FALSE); - + /* free the Dummy Data Page */ sCpuPAddr = OSMapLinToCPUPhys(psDevInfo->hDummyDataPageOSMemHandle, psDevInfo->pvDummyDataPageCpuVAddr); sSysPAddr = SysCpuPAddrToSysPAddr(sCpuPAddr); - + /* unmap the CPU mapping */ OSUnMapPhysToLin(psDevInfo->pvDummyDataPageCpuVAddr, SGX_MMU_PAGE_SIZE, PVRSRV_HAP_WRITECOMBINE|PVRSRV_HAP_KERNEL_ONLY, psDevInfo->hDummyDataPageOSMemHandle); - + /* and free the memory */ RA_Free (psMMUContext->psDeviceNode->psLocalDevMemArena, sSysPAddr.uiAddr, IMG_FALSE); } #endif #if defined(FIX_HW_BRN_31620) - + /* if this is the last context free the dummy pages too */ if(!psMMUContextList->psNext) { - + /* free the Page */ PDUMPFREEPAGETABLE(&psMMUContext->psDeviceNode->sDevId, psDevInfo->hBRN31620DummyPageOSMemHandle, psDevInfo->pvBRN31620DummyPageCpuVAddr, SGX_MMU_PAGE_SIZE, 0, PDUMP_PT_UNIQUETAG); sCpuPAddr = OSMapLinToCPUPhys(psDevInfo->hBRN31620DummyPageOSMemHandle, psDevInfo->pvBRN31620DummyPageCpuVAddr); sSysPAddr = SysCpuPAddrToSysPAddr(sCpuPAddr); - + /* unmap the CPU mapping */ OSUnMapPhysToLin(psDevInfo->pvBRN31620DummyPageCpuVAddr, SGX_MMU_PAGE_SIZE, PVRSRV_HAP_WRITECOMBINE|PVRSRV_HAP_KERNEL_ONLY, psDevInfo->hBRN31620DummyPageOSMemHandle); - + /* and free the memory */ RA_Free (psMMUContext->psDeviceNode->psLocalDevMemArena, sSysPAddr.uiAddr, IMG_FALSE); - + /* free the Dummy PT */ PDUMPFREEPAGETABLE(&psMMUContext->psDeviceNode->sDevId, psDevInfo->hBRN31620DummyPTOSMemHandle, psDevInfo->pvBRN31620DummyPTCpuVAddr, SGX_MMU_PAGE_SIZE, 0, PDUMP_PT_UNIQUETAG); sCpuPAddr = OSMapLinToCPUPhys(psDevInfo->hBRN31620DummyPTOSMemHandle, psDevInfo->pvBRN31620DummyPTCpuVAddr); sSysPAddr = SysCpuPAddrToSysPAddr(sCpuPAddr); - + /* unmap the CPU mapping */ OSUnMapPhysToLin(psDevInfo->pvBRN31620DummyPTCpuVAddr, SGX_MMU_PAGE_SIZE, PVRSRV_HAP_WRITECOMBINE|PVRSRV_HAP_KERNEL_ONLY, psDevInfo->hBRN31620DummyPTOSMemHandle); - + /* and free the memory */ RA_Free (psMMUContext->psDeviceNode->psLocalDevMemArena, sSysPAddr.uiAddr, IMG_FALSE); } #endif @@ -1990,27 +2550,38 @@ MMU_Finalise (MMU_CONTEXT *psMMUContext) PVR_DPF ((PVR_DBG_MESSAGE, "MMU_Finalise")); - + /* remove the MMU context from the list of MMU contexts */ ppsMMUContext = (MMU_CONTEXT**)&psMMUContext->psDevInfo->pvMMUContextList; while(*ppsMMUContext) { if(*ppsMMUContext == psMMUContext) { - + /* remove item from the list */ *ppsMMUContext = psMMUContext->psNext; break; } - + /* advance to next next */ ppsMMUContext = &((*ppsMMUContext)->psNext); } - + /* free the context itself. */ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(MMU_CONTEXT), psMMUContext, IMG_NULL); - + /*not nulling pointer, copy on stack*/ } +/*! +****************************************************************************** + FUNCTION: MMU_InsertHeap + + PURPOSE: Copies PDEs from shared/exported heap into current MMU context. + + PARAMETERS: In: psMMUContext - the mmu + In: psMMUHeap - a shared/exported heap + + RETURNS: None +******************************************************************************/ IMG_VOID MMU_InsertHeap(MMU_CONTEXT *psMMUContext, MMU_HEAP *psMMUHeap) { @@ -2021,20 +2592,21 @@ MMU_InsertHeap(MMU_CONTEXT *psMMUContext, MMU_HEAP *psMMUHeap) IMG_BOOL bInvalidateDirectoryCache = IMG_FALSE; #endif - + /* advance to the first entry */ pui32PDCpuVAddr += psMMUHeap->psDevArena->BaseDevVAddr.uiAddr >> psMMUHeap->ui32PDShift; pui32KernelPDCpuVAddr += psMMUHeap->psDevArena->BaseDevVAddr.uiAddr >> psMMUHeap->ui32PDShift; - - - + /* + update the PD range relating to the heap's + device virtual address range + */ #if defined(PDUMP) PDUMPCOMMENT("Page directory shared heap range copy"); PDUMPCOMMENT(" (Source heap MMU Context ID == %u, PT count == 0x%x)", psMMUHeap->psMMUContext->ui32PDumpMMUContextID, psMMUHeap->ui32PageTableCount); PDUMPCOMMENT(" (Destination MMU Context ID == %u)", psMMUContext->ui32PDumpMMUContextID); -#endif +#endif /* PDUMP */ #ifdef SUPPORT_SGX_MMU_BYPASS EnableHostAccess(psMMUContext); #endif @@ -2042,20 +2614,29 @@ MMU_InsertHeap(MMU_CONTEXT *psMMUContext, MMU_HEAP *psMMUHeap) for (ui32PDEntry = 0; ui32PDEntry < psMMUHeap->ui32PageTableCount; ui32PDEntry++) { #if (!defined(SUPPORT_SGX_MMU_DUMMY_PAGE)) && (!defined(FIX_HW_BRN_31620)) - + /* check we have invalidated target PDEs */ PVR_ASSERT(pui32PDCpuVAddr[ui32PDEntry] == 0); #endif - - + MakeKernelPageReadWrite(psMMUContext->pvPDCpuVAddr); + /* copy over the PDEs */ pui32PDCpuVAddr[ui32PDEntry] = pui32KernelPDCpuVAddr[ui32PDEntry]; + MakeKernelPageReadOnly(psMMUContext->pvPDCpuVAddr); if (pui32PDCpuVAddr[ui32PDEntry]) { - + /* Ensure the shared heap allocation is mapped into the context/PD + * for the active pdump process/app. The PTs and backing physical + * should also be pdumped (elsewhere). + * MALLOC (PT) + * LDB (init PT) + * MALLOC (data page) + * WRW (PTE->data page) + * LDB (init data page) -- could be useful to ensure page is initialised + */ #if defined(PDUMP) - + //PDUMPCOMMENT("MMU_InsertHeap: Mapping shared heap to new context %d (%s)", psMMUContext->ui32PDumpMMUContextID, (psMMUContext->bPDumpActive) ? "active" : ""); #if defined(SUPPORT_PDUMP_MULTI_PROCESS) if(psMMUContext->bPDumpActive) - #endif + #endif /* SUPPORT_PDUMP_MULTI_PROCESS */ { PDUMPPDENTRIES(&psMMUHeap->sMMUAttrib, psMMUContext->hPDOSMemHandle, (IMG_VOID *) &pui32PDCpuVAddr[ui32PDEntry], sizeof(IMG_UINT32), 0, IMG_FALSE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); } @@ -2073,16 +2654,30 @@ MMU_InsertHeap(MMU_CONTEXT *psMMUContext, MMU_HEAP *psMMUHeap) #if !defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) if (bInvalidateDirectoryCache) { - - - - + /* This is actually not to do with multiple mem contexts, but to do with the directory cache. + In the 1 context implementation of the MMU, the directory "cache" is actually a copy of the + page directory memory, and requires updating whenever the page directory changes, even if there + was no previous value in a particular entry + */ MMU_InvalidateDirectoryCache(psMMUContext->psDevInfo); } #endif } +/*! +****************************************************************************** + FUNCTION: MMU_UnmapPagesAndFreePTs + + PURPOSE: unmap pages, invalidate virtual address and try to free the PTs + + PARAMETERS: In: psMMUHeap - the mmu. + In: sDevVAddr - the device virtual address. + In: ui32PageCount - page count + In: hUniqueTag - A unique ID for use as a tag identifier + + RETURNS: None +******************************************************************************/ static IMG_VOID MMU_UnmapPagesAndFreePTs (MMU_HEAP *psMMUHeap, IMG_DEV_VIRTADDR sDevVAddr, @@ -2099,39 +2694,48 @@ MMU_UnmapPagesAndFreePTs (MMU_HEAP *psMMUHeap, #if !defined (PDUMP) PVR_UNREFERENCED_PARAMETER(hUniqueTag); #endif - + /* setup tmp devvaddr to base of allocation */ sTmpDevVAddr = sDevVAddr; for(i=0; i<ui32PageCount; i++) { MMU_PT_INFO **ppsPTInfoList; - + /* find the index/offset in PD entries */ ui32PDIndex = sTmpDevVAddr.uiAddr >> psMMUHeap->ui32PDShift; - + /* and advance to the first PT info list */ ppsPTInfoList = &psMMUHeap->psMMUContext->apsPTInfoList[ui32PDIndex]; { - + /* find the index/offset of the first PT in the first PT page */ ui32PTIndex = (sTmpDevVAddr.uiAddr & psMMUHeap->ui32PTMask) >> psMMUHeap->ui32PTShift; - + /* Is the PT page valid? */ if (!ppsPTInfoList[0]) { - PVR_DPF((PVR_DBG_MESSAGE, "MMU_UnmapPagesAndFreePTs: Invalid PT for alloc at VAddr:0x%08X (VaddrIni:0x%08X AllocPage:%u) PDIdx:%u PTIdx:%u",sTmpDevVAddr.uiAddr, sDevVAddr.uiAddr,i, ui32PDIndex, ui32PTIndex )); + /* + With sparse mappings we expect that the PT could be freed + before we reach the end of it as the unmapped pages don't + bump ui32ValidPTECount so it can reach zero before we reach + the end of the PT. + */ + if (!psMMUHeap->bHasSparseMappings) + { + PVR_DPF((PVR_DBG_MESSAGE, "MMU_UnmapPagesAndFreePTs: Invalid PT for alloc at VAddr:0x%08X (VaddrIni:0x%08X AllocPage:%u) PDIdx:%u PTIdx:%u",sTmpDevVAddr.uiAddr, sDevVAddr.uiAddr,i, ui32PDIndex, ui32PTIndex )); + } - + /* advance the sTmpDevVAddr by one page */ sTmpDevVAddr.uiAddr += psMMUHeap->ui32DataPageSize; - + /* Try to unmap the remaining allocation pages */ continue; } - + /* setup pointer to the first entry in the PT page */ pui32Tmp = (IMG_UINT32*)ppsPTInfoList[0]->PTPageCpuVAddr; - + /* Is PTPageCpuVAddr valid ? */ if (!pui32Tmp) { continue; @@ -2139,37 +2743,41 @@ MMU_UnmapPagesAndFreePTs (MMU_HEAP *psMMUHeap, CheckPT(ppsPTInfoList[0]); - + /* Decrement the valid page count only if the current page is valid*/ if (pui32Tmp[ui32PTIndex] & SGX_MMU_PTE_VALID) { ppsPTInfoList[0]->ui32ValidPTECount--; } else { - PVR_DPF((PVR_DBG_MESSAGE, "MMU_UnmapPagesAndFreePTs: Page is already invalid for alloc at VAddr:0x%08X (VAddrIni:0x%08X AllocPage:%u) PDIdx:%u PTIdx:%u",sTmpDevVAddr.uiAddr, sDevVAddr.uiAddr,i, ui32PDIndex, ui32PTIndex )); + if (!psMMUHeap->bHasSparseMappings) + { + PVR_DPF((PVR_DBG_MESSAGE, "MMU_UnmapPagesAndFreePTs: Page is already invalid for alloc at VAddr:0x%08X (VAddrIni:0x%08X AllocPage:%u) PDIdx:%u PTIdx:%u",sTmpDevVAddr.uiAddr, sDevVAddr.uiAddr,i, ui32PDIndex, ui32PTIndex )); + } } - + /* The page table count should not go below zero */ PVR_ASSERT((IMG_INT32)ppsPTInfoList[0]->ui32ValidPTECount >= 0); - + MakeKernelPageReadWrite(ppsPTInfoList[0]->PTPageCpuVAddr); #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) - + /* point the PT entry to the dummy data page */ pui32Tmp[ui32PTIndex] = (psMMUHeap->psMMUContext->psDevInfo->sDummyDataDevPAddr.uiAddr>>SGX_MMU_PTE_ADDR_ALIGNSHIFT) | SGX_MMU_PTE_VALID; #else - + /* invalidate entry */ #if defined(FIX_HW_BRN_31620) BRN31620InvalidatePageTableEntry(psMMUHeap->psMMUContext, ui32PDIndex, ui32PTIndex, &pui32Tmp[ui32PTIndex]); #else pui32Tmp[ui32PTIndex] = 0; #endif #endif - + MakeKernelPageReadOnly(ppsPTInfoList[0]->PTPageCpuVAddr); CheckPT(ppsPTInfoList[0]); } - - + /* + Free a page table if we can. + */ if (ppsPTInfoList[0] && (ppsPTInfoList[0]->ui32ValidPTECount == 0) ) { @@ -2184,7 +2792,7 @@ MMU_UnmapPagesAndFreePTs (MMU_HEAP *psMMUHeap, #endif } - + /* advance the sTmpDevVAddr by one page */ sTmpDevVAddr.uiAddr += psMMUHeap->ui32DataPageSize; } @@ -2203,10 +2811,23 @@ MMU_UnmapPagesAndFreePTs (MMU_HEAP *psMMUHeap, psMMUHeap->ui32DataPageSize * ui32PageCount, IMG_TRUE, hUniqueTag); -#endif +#endif /* #if defined(PDUMP) */ } +/*! +****************************************************************************** + FUNCTION: MMU_FreePageTables + + PURPOSE: Call back from RA_Free to zero page table entries used by freed + spans. + + PARAMETERS: In: pvMMUHeap + In: ui32Start + In: ui32End + In: hUniqueTag - A unique ID for use as a tag identifier + RETURNS: +******************************************************************************/ static IMG_VOID MMU_FreePageTables(IMG_PVOID pvMMUHeap, IMG_SIZE_T ui32Start, IMG_SIZE_T ui32End, @@ -2220,6 +2841,18 @@ static IMG_VOID MMU_FreePageTables(IMG_PVOID pvMMUHeap, MMU_UnmapPagesAndFreePTs(pMMUHeap, Start, (IMG_UINT32)((ui32End - ui32Start) >> pMMUHeap->ui32PTShift), hUniqueTag); } +/*! +****************************************************************************** + FUNCTION: MMU_Create + + PURPOSE: Create an mmu device virtual heap. + + PARAMETERS: In: psMMUContext - MMU context + In: psDevArena - device memory resource arena + Out: ppsVMArena - virtual mapping arena + RETURNS: MMU_HEAP + RETURNS: +******************************************************************************/ MMU_HEAP * MMU_Create (MMU_CONTEXT *psMMUContext, DEV_ARENA_DESCRIPTOR *psDevArena, @@ -2252,9 +2885,10 @@ MMU_Create (MMU_CONTEXT *psMMUContext, pMMUHeap->psMMUContext = psMMUContext; pMMUHeap->psDevArena = psDevArena; - - - + /* + generate page table and data page mask and shift values + based on the data page size + */ switch(pMMUHeap->psDevArena->ui32DataPageSize) { case 0x1000: @@ -2282,67 +2916,72 @@ MMU_Create (MMU_CONTEXT *psMMUContext, ui32ScaleSize = 10; pMMUHeap->ui32PDEPageSizeCtrl = SGX_MMU_PDE_PAGE_SIZE_4M; break; -#endif +#endif /* #if defined(SGX_FEATURE_VARIABLE_MMU_PAGE_SIZE) */ default: PVR_DPF((PVR_DBG_ERROR, "MMU_Create: invalid data page size")); goto ErrorFreeHeap; } - + /* number of bits of address offset into the data page */ pMMUHeap->ui32DataPageSize = psDevArena->ui32DataPageSize; pMMUHeap->ui32DataPageBitWidth = SGX_MMU_PAGE_SHIFT + ui32ScaleSize; pMMUHeap->ui32DataPageMask = pMMUHeap->ui32DataPageSize - 1; - + /* number of bits of address indexing into a pagetable */ pMMUHeap->ui32PTShift = pMMUHeap->ui32DataPageBitWidth; pMMUHeap->ui32PTBitWidth = SGX_MMU_PT_SHIFT - ui32ScaleSize; pMMUHeap->ui32PTMask = SGX_MMU_PT_MASK & (SGX_MMU_PT_MASK<<ui32ScaleSize); pMMUHeap->ui32PTSize = (IMG_UINT32)(1UL<<pMMUHeap->ui32PTBitWidth) * sizeof(IMG_UINT32); - + /* note: PT size must be at least 4 entries, even for 4Mb data page size */ if(pMMUHeap->ui32PTSize < 4 * sizeof(IMG_UINT32)) { pMMUHeap->ui32PTSize = 4 * sizeof(IMG_UINT32); } pMMUHeap->ui32PTNumEntriesAllocated = pMMUHeap->ui32PTSize >> 2; - + /* find the number of actual PT entries per PD entry range. For 4MB data + * pages we only use the first entry although the PT has 16 byte allocation/alignment + * (due to 4 LSbits of the PDE are reserved for control) */ pMMUHeap->ui32PTNumEntriesUsable = (IMG_UINT32)(1UL << pMMUHeap->ui32PTBitWidth); - + /* number of bits of address indexing into a page directory */ pMMUHeap->ui32PDShift = pMMUHeap->ui32PTBitWidth + pMMUHeap->ui32PTShift; pMMUHeap->ui32PDBitWidth = SGX_FEATURE_ADDRESS_SPACE_SIZE - pMMUHeap->ui32PTBitWidth - pMMUHeap->ui32DataPageBitWidth; pMMUHeap->ui32PDMask = SGX_MMU_PD_MASK & (SGX_MMU_PD_MASK>>(32-SGX_FEATURE_ADDRESS_SPACE_SIZE)); - + /* External system cache violates this rule */ #if !defined (SUPPORT_EXTERNAL_SYSTEM_CACHE) - - - - + /* + The heap must start on a PT boundary to avoid PT sharing across heaps + The only exception is the first heap which can start at any address + from 0 to the end of the first PT boundary + */ if(psDevArena->BaseDevVAddr.uiAddr > (pMMUHeap->ui32DataPageMask | pMMUHeap->ui32PTMask)) { - - - + /* + if for some reason the first heap starts after the end of the first PT boundary + but is not aligned to a PT boundary then the assert will trigger unncessarily + */ PVR_ASSERT ((psDevArena->BaseDevVAddr.uiAddr & (pMMUHeap->ui32DataPageMask | pMMUHeap->ui32PTMask)) == 0); } #endif - + /* how many PT entries do we need? */ pMMUHeap->ui32PTETotalUsable = pMMUHeap->psDevArena->ui32Size >> pMMUHeap->ui32PTShift; - + /* calculate the PD Base index for the Heap (required for page mapping) */ pMMUHeap->ui32PDBaseIndex = (pMMUHeap->psDevArena->BaseDevVAddr.uiAddr & pMMUHeap->ui32PDMask) >> pMMUHeap->ui32PDShift; - - - + /* + how many page tables? + round up to nearest entries to the nearest page table sized block + */ pMMUHeap->ui32PageTableCount = (pMMUHeap->ui32PTETotalUsable + pMMUHeap->ui32PTNumEntriesUsable - 1) >> pMMUHeap->ui32PTBitWidth; PVR_ASSERT(pMMUHeap->ui32PageTableCount > 0); - + /* Create the arena */ pMMUHeap->psVMArena = RA_Create(psDevArena->pszName, psDevArena->BaseDevVAddr.uiAddr, psDevArena->ui32Size, @@ -2360,7 +2999,7 @@ MMU_Create (MMU_CONTEXT *psMMUContext, } #if defined(PDUMP) - + /* setup per-heap PDUMP MMU attributes */ MMU_SetPDumpAttribs(&pMMUHeap->sMMUAttrib, psMMUContext->psDeviceNode, pMMUHeap->ui32DataPageMask, @@ -2372,51 +3011,35 @@ MMU_Create (MMU_CONTEXT *psMMUContext, psDevArena->ui32Size, pMMUHeap->ui32DataPageSize, psDevArena->BaseDevVAddr.uiAddr); -#endif - -#if 0 - - if(psDevArena->ui32HeapID == SGX_TILED_HEAP_ID) - { - IMG_UINT32 ui32RegVal; - IMG_UINT32 ui32XTileStride; - - - - - - - ui32XTileStride = 2; - - ui32RegVal = (EUR_CR_BIF_TILE0_MIN_ADDRESS_MASK - & ((psDevArena->BaseDevVAddr.uiAddr>>20) - << EUR_CR_BIF_TILE0_MIN_ADDRESS_SHIFT)) - |(EUR_CR_BIF_TILE0_MAX_ADDRESS_MASK - & (((psDevArena->BaseDevVAddr.uiAddr+psDevArena->ui32Size)>>20) - << EUR_CR_BIF_TILE0_MAX_ADDRESS_SHIFT)) - |(EUR_CR_BIF_TILE0_CFG_MASK - & (((ui32XTileStride<<1)|8) << EUR_CR_BIF_TILE0_CFG_SHIFT)); - PDUMPREG(SGX_PDUMPREG_NAME, EUR_CR_BIF_TILE0, ui32RegVal); - } -#endif - - +#endif /* PDUMP */ + /* + And return the RA for VM arena management + */ *ppsVMArena = pMMUHeap->psVMArena; return pMMUHeap; - + /* drop into here if errors */ ErrorFreePagetables: _DeferredFreePageTables (pMMUHeap); ErrorFreeHeap: OSFreeMem (PVRSRV_OS_PAGEABLE_HEAP, sizeof(MMU_HEAP), pMMUHeap, IMG_NULL); - + /*not nulling pointer, out of scope*/ return IMG_NULL; } +/*! +****************************************************************************** + FUNCTION: MMU_Delete + + PURPOSE: Delete an MMU device virtual heap. + + PARAMETERS: In: pMMUHeap - The MMU heap to delete. + RETURNS: +******************************************************************************/ IMG_VOID MMU_Delete (MMU_HEAP *pMMUHeap) { @@ -2434,7 +3057,7 @@ MMU_Delete (MMU_HEAP *pMMUHeap) pMMUHeap->psDevArena->pszName, pMMUHeap->psDevArena->BaseDevVAddr.uiAddr, pMMUHeap->ui32PageTableCount); -#endif +#endif /* PDUMP */ #ifdef SUPPORT_SGX_MMU_BYPASS EnableHostAccess(pMMUHeap->psMMUContext); @@ -2445,10 +3068,23 @@ MMU_Delete (MMU_HEAP *pMMUHeap) #endif OSFreeMem (PVRSRV_OS_PAGEABLE_HEAP, sizeof(MMU_HEAP), pMMUHeap, IMG_NULL); - + /*not nulling pointer, copy on stack*/ } } +/*! +****************************************************************************** + FUNCTION: MMU_Alloc + PURPOSE: Allocate space in an mmu's virtual address space. + PARAMETERS: In: pMMUHeap - MMU to allocate on. + In: uSize - Size in bytes to allocate. + Out: pActualSize - If non null receives actual size allocated. + In: uFlags - Allocation flags. + In: uDevVAddrAlignment - Required alignment. + Out: DevVAddr - Receives base address of allocation. + RETURNS: IMG_TRUE - Success + IMG_FALSE - Failure +******************************************************************************/ IMG_BOOL MMU_Alloc (MMU_HEAP *pMMUHeap, IMG_SIZE_T uSize, @@ -2463,8 +3099,9 @@ MMU_Alloc (MMU_HEAP *pMMUHeap, "MMU_Alloc: uSize=0x%x, flags=0x%x, align=0x%x", uSize, uFlags, uDevVAddrAlignment)); - - + /* + Only allocate a VM address if the caller did not supply one + */ if((uFlags & PVRSRV_MEM_USER_SUPPLIED_DEVVADDR) == 0) { IMG_UINTPTR_T uiAddr; @@ -2476,6 +3113,8 @@ MMU_Alloc (MMU_HEAP *pMMUHeap, 0, uDevVAddrAlignment, 0, + IMG_NULL, + 0, &uiAddr); if(!bStatus) { @@ -2493,7 +3132,7 @@ MMU_Alloc (MMU_HEAP *pMMUHeap, EnableHostAccess(pMMUHeap->psMMUContext); #endif - + /* allocate page tables to cover allocation as required */ bStatus = _DeferredAllocPagetables(pMMUHeap, *psDevVAddr, (IMG_UINT32)uSize); #ifdef SUPPORT_SGX_MMU_BYPASS @@ -2509,7 +3148,7 @@ MMU_Alloc (MMU_HEAP *pMMUHeap, pMMUHeap->psDevArena->ui32HeapID)); if((uFlags & PVRSRV_MEM_USER_SUPPLIED_DEVVADDR) == 0) { - + /* free the VM address */ RA_Free (pMMUHeap->psVMArena, psDevVAddr->uiAddr, IMG_FALSE); } } @@ -2517,6 +3156,14 @@ MMU_Alloc (MMU_HEAP *pMMUHeap, return bStatus; } +/*! +****************************************************************************** + FUNCTION: MMU_Free + PURPOSE: Free space in an mmu's virtual address space. + PARAMETERS: In: pMMUHeap - MMU to deallocate on. + In: DevVAddr - Base address to deallocate. + RETURNS: None +******************************************************************************/ IMG_VOID MMU_Free (MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT32 ui32Size) { @@ -2546,21 +3193,52 @@ MMU_Free (MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT32 ui32Size) pMMUHeap->psDevArena->ui32HeapID)); } +/*! +****************************************************************************** + FUNCTION: MMU_Enable + + PURPOSE: Enable an mmu. Establishes pages tables and takes the mmu out + of bypass and waits for the mmu to acknowledge enabled. + + PARAMETERS: In: pMMUHeap - the mmu + RETURNS: None +******************************************************************************/ IMG_VOID MMU_Enable (MMU_HEAP *pMMUHeap) { PVR_UNREFERENCED_PARAMETER(pMMUHeap); - + /* SGX mmu is always enabled (stub function) */ } +/*! +****************************************************************************** + FUNCTION: MMU_Disable + + PURPOSE: Disable an mmu, takes the mmu into bypass. + + PARAMETERS: In: pMMUHeap - the mmu + RETURNS: None +******************************************************************************/ IMG_VOID MMU_Disable (MMU_HEAP *pMMUHeap) { PVR_UNREFERENCED_PARAMETER(pMMUHeap); - + /* SGX mmu is always enabled (stub function) */ } #if defined(FIX_HW_BRN_31620) +/*! +****************************************************************************** + FUNCTION: MMU_GetCacheFlushRange + + PURPOSE: Gets device physical address of the mmu context. + + PARAMETERS: In: pMMUContext - the mmu context + Out: pui32RangeMask - Bit mask showing which PD cache + lines have changed + RETURNS: None +******************************************************************************/ + IMG_VOID MMU_GetCacheFlushRange(MMU_CONTEXT *pMMUContext, IMG_UINT32 *pui32RangeMask) { IMG_UINT32 i; @@ -2569,11 +3247,22 @@ IMG_VOID MMU_GetCacheFlushRange(MMU_CONTEXT *pMMUContext, IMG_UINT32 *pui32Range { pui32RangeMask[i] = pMMUContext->ui32PDChangeMask[i]; - + /* Clear bit mask for the next set of allocations */ pMMUContext->ui32PDChangeMask[i] = 0; } } +/*! +****************************************************************************** + FUNCTION: MMU_GetPDPhysAddr + + PURPOSE: Gets device physical address of the mmu contexts PD. + + PARAMETERS: In: pMMUContext - the mmu context + Out: psDevPAddr - Address of PD + RETURNS: None +******************************************************************************/ + IMG_VOID MMU_GetPDPhysAddr(MMU_CONTEXT *pMMUContext, IMG_DEV_PHYADDR *psDevPAddr) { *psDevPAddr = pMMUContext->sPDDevPAddr; @@ -2581,6 +3270,19 @@ IMG_VOID MMU_GetPDPhysAddr(MMU_CONTEXT *pMMUContext, IMG_DEV_PHYADDR *psDevPAddr #endif #if defined(PDUMP) +/*! +****************************************************************************** + FUNCTION: MMU_PDumpPageTables + + PURPOSE: PDump the linear mapping for a range of pages at a specified + virtual address. + + PARAMETERS: In: pMMUHeap - the mmu. + In: DevVAddr - the device virtual address. + In: uSize - size of memory range in bytes + In: hUniqueTag - A unique ID for use as a tag identifier + RETURNS: None +******************************************************************************/ static IMG_VOID MMU_PDumpPageTables (MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, @@ -2596,22 +3298,25 @@ MMU_PDumpPageTables (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32PDIndex; IMG_UINT32 ui32PTDumpCount; - +#if defined(FIX_HW_BRN_31620) + PVRSRV_SGXDEV_INFO *psDevInfo = pMMUHeap->psMMUContext->psDevInfo; +#endif + /* find number of PT entries to dump */ ui32NumPTEntries = (IMG_UINT32)((uSize + pMMUHeap->ui32DataPageMask) >> pMMUHeap->ui32PTShift); - + /* find the index/offset in PD entries */ ui32PDIndex = DevVAddr.uiAddr >> pMMUHeap->ui32PDShift; - + /* set the base PT info */ ppsPTInfoList = &pMMUHeap->psMMUContext->apsPTInfoList[ui32PDIndex]; - + /* find the index/offset of the first PT entry in the first PT page */ ui32PTIndex = (DevVAddr.uiAddr & pMMUHeap->ui32PTMask) >> pMMUHeap->ui32PTShift; - + /* pdump the PT Page modification */ PDUMPCOMMENT("Page table mods (num entries == %08X) %s", ui32NumPTEntries, bForUnmap ? "(for unmap)" : ""); - + /* walk the PT pages, dumping as we go */ while(ui32NumPTEntries > 0) { MMU_PT_INFO* psPTInfo = *ppsPTInfoList++; @@ -2627,26 +3332,68 @@ MMU_PDumpPageTables (MMU_HEAP *pMMUHeap, if (psPTInfo) { +#if defined(FIX_HW_BRN_31620) + IMG_UINT32 i; +#endif IMG_UINT32 ui32Flags = 0; #if defined(SUPPORT_PDUMP_MULTI_PROCESS) ui32Flags |= ( MMU_IsHeapShared(pMMUHeap) ) ? PDUMP_FLAGS_PERSISTENT : 0; #endif pui32PTEntry = (IMG_UINT32*)psPTInfo->PTPageCpuVAddr; - PDUMPMEMPTENTRIES(&pMMUHeap->sMMUAttrib, psPTInfo->hPTPageOSMemHandle, (IMG_VOID *) &pui32PTEntry[ui32PTIndex], ui32PTDumpCount * sizeof(IMG_UINT32), ui32Flags, IMG_FALSE, PDUMP_PT_UNIQUETAG, hUniqueTag); +#if defined(FIX_HW_BRN_31620) + if ((ui32PDIndex % (BRN31620_PDE_CACHE_FILL_SIZE/BRN31620_PT_ADDRESS_RANGE_SIZE)) == BRN31620_DUMMY_PDE_INDEX) + { + for (i=ui32PTIndex;i<(ui32PTIndex + ui32PTDumpCount);i++) + { + if (pui32PTEntry[i] == ((psDevInfo->sBRN31620DummyPageDevPAddr.uiAddr>>SGX_MMU_PTE_ADDR_ALIGNSHIFT) + | SGX_MMU_PTE_DUMMY_PAGE + | SGX_MMU_PTE_READONLY + | SGX_MMU_PTE_VALID)) + { + PDUMPMEMPTENTRIES(&pMMUHeap->sMMUAttrib, psPTInfo->hPTPageOSMemHandle, (IMG_VOID *) &pui32PTEntry[i], sizeof(IMG_UINT32), ui32Flags, IMG_FALSE, PDUMP_PT_UNIQUETAG, PDUMP_PD_UNIQUETAG); + } + else + { + PDUMPMEMPTENTRIES(&pMMUHeap->sMMUAttrib, psPTInfo->hPTPageOSMemHandle, (IMG_VOID *) &pui32PTEntry[i], sizeof(IMG_UINT32), ui32Flags, IMG_FALSE, PDUMP_PT_UNIQUETAG, hUniqueTag); + } + } + } + else +#endif + { + PDUMPMEMPTENTRIES(&pMMUHeap->sMMUAttrib, psPTInfo->hPTPageOSMemHandle, (IMG_VOID *) &pui32PTEntry[ui32PTIndex], ui32PTDumpCount * sizeof(IMG_UINT32), ui32Flags, IMG_FALSE, PDUMP_PT_UNIQUETAG, hUniqueTag); + } } - + /* decrement PT entries left */ ui32NumPTEntries -= ui32PTDumpCount; - + /* reset offset in page */ ui32PTIndex = 0; + +#if defined(FIX_HW_BRN_31620) + /* For 31620 we need to know which PD index we're working on */ + ui32PDIndex++; +#endif } PDUMPCOMMENT("Finished page table mods %s", bForUnmap ? "(for unmap)" : ""); } -#endif +#endif /* #if defined(PDUMP) */ + +/*! +****************************************************************************** + FUNCTION: MMU_MapPage + PURPOSE: Create a mapping for one page at a specified virtual address. + + PARAMETERS: In: pMMUHeap - the mmu. + In: DevVAddr - the device virtual address. + In: DevPAddr - the device physical address of the page to map. + In: ui32MemFlags - BM r/w/cache flags + RETURNS: None +******************************************************************************/ static IMG_VOID MMU_MapPage (MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, @@ -2658,63 +3405,66 @@ MMU_MapPage (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32MMUFlags = 0; MMU_PT_INFO **ppsPTInfoList; - + /* check the physical alignment of the memory to map */ PVR_ASSERT((DevPAddr.uiAddr & pMMUHeap->ui32DataPageMask) == 0); - - + /* + unravel the read/write/cache flags + */ if(((PVRSRV_MEM_READ|PVRSRV_MEM_WRITE) & ui32MemFlags) == (PVRSRV_MEM_READ|PVRSRV_MEM_WRITE)) { - + /* read/write */ ui32MMUFlags = 0; } else if(PVRSRV_MEM_READ & ui32MemFlags) { - + /* read only */ ui32MMUFlags |= SGX_MMU_PTE_READONLY; } else if(PVRSRV_MEM_WRITE & ui32MemFlags) { - + /* write only */ ui32MMUFlags |= SGX_MMU_PTE_WRITEONLY; } - + /* cache coherency */ if(PVRSRV_MEM_CACHE_CONSISTENT & ui32MemFlags) { ui32MMUFlags |= SGX_MMU_PTE_CACHECONSISTENT; } #if !defined(FIX_HW_BRN_25503) - + /* EDM protection */ if(PVRSRV_MEM_EDM_PROTECT & ui32MemFlags) { ui32MMUFlags |= SGX_MMU_PTE_EDMPROTECT; } #endif - - + /* + we receive a device physical address for the page that is to be mapped + and a device virtual address representing where it should be mapped to + */ - + /* find the index/offset in PD entries */ ui32Index = DevVAddr.uiAddr >> pMMUHeap->ui32PDShift; - + /* and advance to the first PT info list */ ppsPTInfoList = &pMMUHeap->psMMUContext->apsPTInfoList[ui32Index]; CheckPT(ppsPTInfoList[0]); - + /* find the index/offset of the first PT in the first PT page */ ui32Index = (DevVAddr.uiAddr & pMMUHeap->ui32PTMask) >> pMMUHeap->ui32PTShift; - + /* setup pointer to the first entry in the PT page */ pui32Tmp = (IMG_UINT32*)ppsPTInfoList[0]->PTPageCpuVAddr; #if !defined(SUPPORT_SGX_MMU_DUMMY_PAGE) { IMG_UINT32 uTmp = pui32Tmp[ui32Index]; - + /* Is the current page already valid? (should not be unless it was allocated and not deallocated) */ #if defined(FIX_HW_BRN_31620) if ((uTmp & SGX_MMU_PTE_VALID) && ((DevVAddr.uiAddr & BRN31620_PDE_CACHE_FILL_MASK) != BRN31620_DUMMY_PAGE_OFFSET)) #else @@ -2728,6 +3478,9 @@ MMU_MapPage (MMU_HEAP *pMMUHeap, ui32Index )); PVR_DPF((PVR_DBG_ERROR, "MMU_MapPage: Page table entry value: 0x%08X", uTmp)); PVR_DPF((PVR_DBG_ERROR, "MMU_MapPage: Physical page to map: 0x%08X", DevPAddr.uiAddr)); +#if PT_DUMP + DumpPT(ppsPTInfoList[0]); +#endif } #if !defined(FIX_HW_BRN_31620) PVR_ASSERT((uTmp & SGX_MMU_PTE_VALID) == 0); @@ -2735,19 +3488,36 @@ MMU_MapPage (MMU_HEAP *pMMUHeap, } #endif - + /* One more valid entry in the page table. */ ppsPTInfoList[0]->ui32ValidPTECount++; - + MakeKernelPageReadWrite(ppsPTInfoList[0]->PTPageCpuVAddr); + /* map in the physical page */ pui32Tmp[ui32Index] = ((DevPAddr.uiAddr>>SGX_MMU_PTE_ADDR_ALIGNSHIFT) & ((~pMMUHeap->ui32DataPageMask)>>SGX_MMU_PTE_ADDR_ALIGNSHIFT)) | SGX_MMU_PTE_VALID | ui32MMUFlags; - + MakeKernelPageReadOnly(ppsPTInfoList[0]->PTPageCpuVAddr); CheckPT(ppsPTInfoList[0]); } +/*! +****************************************************************************** + FUNCTION: MMU_MapScatter + + PURPOSE: Create a linear mapping for a range of pages at a specified + virtual address. + + PARAMETERS: In: pMMUHeap - the mmu. + In: DevVAddr - the device virtual address. + In: psSysAddr - the device physical address of the page to + map. + In: uSize - size of memory range in bytes + In: ui32MemFlags - page table flags. + In: hUniqueTag - A unique ID for use as a tag identifier + RETURNS: None +******************************************************************************/ IMG_VOID MMU_MapScatter (MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, @@ -2758,7 +3528,7 @@ MMU_MapScatter (MMU_HEAP *pMMUHeap, { #if defined(PDUMP) IMG_DEV_VIRTADDR MapBaseDevVAddr; -#endif +#endif /*PDUMP*/ IMG_UINT32 uCount, i; IMG_DEV_PHYADDR DevPAddr; @@ -2768,7 +3538,7 @@ MMU_MapScatter (MMU_HEAP *pMMUHeap, MapBaseDevVAddr = DevVAddr; #else PVR_UNREFERENCED_PARAMETER(hUniqueTag); -#endif +#endif /*PDUMP*/ for (i=0, uCount=0; uCount<uSize; i++, uCount+=pMMUHeap->ui32DataPageSize) { @@ -2777,7 +3547,7 @@ MMU_MapScatter (MMU_HEAP *pMMUHeap, sSysAddr = psSysAddr[i]; - + /* check the physical alignment of the memory to map */ PVR_ASSERT((sSysAddr.uiAddr & pMMUHeap->ui32DataPageMask) == 0); DevPAddr = SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sSysAddr); @@ -2793,9 +3563,25 @@ MMU_MapScatter (MMU_HEAP *pMMUHeap, #if defined(PDUMP) MMU_PDumpPageTables (pMMUHeap, MapBaseDevVAddr, uSize, IMG_FALSE, hUniqueTag); -#endif +#endif /* #if defined(PDUMP) */ } +/*! +****************************************************************************** + FUNCTION: MMU_MapPages + + PURPOSE: Create a linear mapping for a ranege of pages at a specified + virtual address. + + PARAMETERS: In: pMMUHeap - the mmu. + In: DevVAddr - the device virtual address. + In: SysPAddr - the system physical address of the page to + map. + In: uSize - size of memory range in bytes + In: ui32MemFlags - page table flags. + In: hUniqueTag - A unique ID for use as a tag identifier + RETURNS: None +******************************************************************************/ IMG_VOID MMU_MapPages (MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, @@ -2807,7 +3593,7 @@ MMU_MapPages (MMU_HEAP *pMMUHeap, IMG_DEV_PHYADDR DevPAddr; #if defined(PDUMP) IMG_DEV_VIRTADDR MapBaseDevVAddr; -#endif +#endif /*PDUMP*/ IMG_UINT32 uCount; IMG_UINT32 ui32VAdvance; IMG_UINT32 ui32PAdvance; @@ -2821,7 +3607,7 @@ MMU_MapPages (MMU_HEAP *pMMUHeap, SysPAddr.uiAddr, uSize)); - + /* set the virtual and physical advance */ ui32VAdvance = pMMUHeap->ui32DataPageSize; ui32PAdvance = pMMUHeap->ui32DataPageSize; @@ -2829,40 +3615,153 @@ MMU_MapPages (MMU_HEAP *pMMUHeap, MapBaseDevVAddr = DevVAddr; #else PVR_UNREFERENCED_PARAMETER(hUniqueTag); -#endif +#endif /*PDUMP*/ DevPAddr = SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, SysPAddr); - + /* check the physical alignment of the memory to map */ PVR_ASSERT((DevPAddr.uiAddr & pMMUHeap->ui32DataPageMask) == 0); -#if defined(FIX_HW_BRN_23281) - if(ui32MemFlags & PVRSRV_MEM_INTERLEAVED) + /* + for dummy allocations there is only one physical + page backing the virtual range + */ + if(ui32MemFlags & PVRSRV_MEM_DUMMY) { - ui32VAdvance *= 2; + ui32PAdvance = 0; } + + for (uCount=0; uCount<uSize; uCount+=ui32VAdvance) + { + MMU_MapPage (pMMUHeap, DevVAddr, DevPAddr, ui32MemFlags); + DevVAddr.uiAddr += ui32VAdvance; + DevPAddr.uiAddr += ui32PAdvance; + } + +#if defined(PDUMP) + MMU_PDumpPageTables (pMMUHeap, MapBaseDevVAddr, uSize, IMG_FALSE, hUniqueTag); +#endif /* #if defined(PDUMP) */ +} + + +/*! +****************************************************************************** + FUNCTION: MMU_MapPagesSparse + + PURPOSE: Create a linear mapping for a ranege of pages at a specified + virtual address. + + PARAMETERS: In: pMMUHeap - the mmu. + In: DevVAddr - the device virtual address. + In: SysPAddr - the system physical address of the page to + map. + In: ui32ChunkSize - Size of the chunk (must be page multiple) + In: ui32NumVirtChunks - Number of virtual chunks + In: ui32NumPhysChunks - Number of physical chunks + In: pabMapChunk - Mapping array + In: ui32MemFlags - page table flags. + In: hUniqueTag - A unique ID for use as a tag identifier + RETURNS: None +******************************************************************************/ +IMG_VOID +MMU_MapPagesSparse (MMU_HEAP *pMMUHeap, + IMG_DEV_VIRTADDR DevVAddr, + IMG_SYS_PHYADDR SysPAddr, + IMG_UINT32 ui32ChunkSize, + IMG_UINT32 ui32NumVirtChunks, + IMG_UINT32 ui32NumPhysChunks, + IMG_BOOL *pabMapChunk, + IMG_UINT32 ui32MemFlags, + IMG_HANDLE hUniqueTag) +{ + IMG_DEV_PHYADDR DevPAddr; +#if defined(PDUMP) + IMG_DEV_VIRTADDR MapBaseDevVAddr; +#endif /*PDUMP*/ + IMG_UINT32 uCount; + IMG_UINT32 ui32VAdvance; + IMG_UINT32 ui32PAdvance; + IMG_SIZE_T uSizeVM = ui32ChunkSize * ui32NumVirtChunks; +#if !defined(PVRSRV_NEED_PVR_DPF) + PVR_UNREFERENCED_PARAMETER(ui32NumPhysChunks); #endif - + PVR_ASSERT (pMMUHeap != IMG_NULL); + PVR_DPF ((PVR_DBG_MESSAGE, "MMU_MapPagesSparse: heap:%s, heap_id:%d devVAddr=%08X, SysPAddr=%08X, VM space=0x%x, PHYS space=0x%x", + pMMUHeap->psDevArena->pszName, + pMMUHeap->psDevArena->ui32HeapID, + DevVAddr.uiAddr, + SysPAddr.uiAddr, + uSizeVM, + ui32ChunkSize * ui32NumPhysChunks)); + + /* set the virtual and physical advance */ + ui32VAdvance = pMMUHeap->ui32DataPageSize; + ui32PAdvance = pMMUHeap->ui32DataPageSize; + +#if defined(PDUMP) + MapBaseDevVAddr = DevVAddr; +#else + PVR_UNREFERENCED_PARAMETER(hUniqueTag); +#endif /*PDUMP*/ + DevPAddr = SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, SysPAddr); + + /* check the physical alignment of the memory to map */ + PVR_ASSERT((DevPAddr.uiAddr & pMMUHeap->ui32DataPageMask) == 0); + + /* + for dummy allocations there is only one physical + page backing the virtual range + */ if(ui32MemFlags & PVRSRV_MEM_DUMMY) { ui32PAdvance = 0; } - for (uCount=0; uCount<uSize; uCount+=ui32VAdvance) + for (uCount=0; uCount<uSizeVM; uCount+=ui32VAdvance) { - MMU_MapPage (pMMUHeap, DevVAddr, DevPAddr, ui32MemFlags); + if (pabMapChunk[uCount/ui32ChunkSize]) + { + MMU_MapPage (pMMUHeap, DevVAddr, DevPAddr, ui32MemFlags); + DevPAddr.uiAddr += ui32PAdvance; + } DevVAddr.uiAddr += ui32VAdvance; - DevPAddr.uiAddr += ui32PAdvance; } + pMMUHeap->bHasSparseMappings = IMG_TRUE; #if defined(PDUMP) - MMU_PDumpPageTables (pMMUHeap, MapBaseDevVAddr, uSize, IMG_FALSE, hUniqueTag); -#endif + MMU_PDumpPageTables (pMMUHeap, MapBaseDevVAddr, uSizeVM, IMG_FALSE, hUniqueTag); +#endif /* #if defined(PDUMP) */ } +/*! +****************************************************************************** + FUNCTION: MMU_MapShadow + + PURPOSE: Create a mapping for a range of pages from either a CPU + virtual adddress, (or if NULL a hOSMemHandle) to a specified + device virtual address. + + PARAMETERS: In: pMMUHeap - the mmu. + In: MapBaseDevVAddr - A page aligned device virtual address + to start mapping from. + In: uByteSize - A page aligned mapping length in bytes. + In: CpuVAddr - A page aligned CPU virtual address. + In: hOSMemHandle - An alternative OS specific memory handle + for mapping RAM without a CPU virtual + address + Out: pDevVAddr - deprecated - It used to return a byte aligned + device virtual address corresponding to the + cpu virtual address (When CpuVAddr wasn't + constrained to be page aligned.) Now it just + returns MapBaseDevVAddr. Unaligned semantics + can easily be handled above this API if required. + In: hUniqueTag - A unique ID for use as a tag identifier + In: ui32MemFlags - page table flags. + RETURNS: None +******************************************************************************/ IMG_VOID MMU_MapShadow (MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR MapBaseDevVAddr, @@ -2889,31 +3788,25 @@ MMU_MapShadow (MMU_HEAP *pMMUHeap, uByteSize, (IMG_UINTPTR_T)CpuVAddr)); - + /* set the virtual and physical advance */ ui32VAdvance = pMMUHeap->ui32DataPageSize; ui32PAdvance = pMMUHeap->ui32DataPageSize; - + /* note: can't do useful check on the CPU Addr other than it being at least 4k alignment */ PVR_ASSERT(((IMG_UINTPTR_T)CpuVAddr & (SGX_MMU_PAGE_SIZE - 1)) == 0); PVR_ASSERT(((IMG_UINT32)uByteSize & pMMUHeap->ui32DataPageMask) == 0); pDevVAddr->uiAddr = MapBaseDevVAddr.uiAddr; -#if defined(FIX_HW_BRN_23281) - if(ui32MemFlags & PVRSRV_MEM_INTERLEAVED) - { - ui32VAdvance *= 2; - } -#endif - - - - + /* + for dummy allocations there is only one physical + page backing the virtual range + */ if(ui32MemFlags & PVRSRV_MEM_DUMMY) { ui32PAdvance = 0; } - + /* Loop through cpu memory and map page by page */ MapDevVAddr = MapBaseDevVAddr; for (i=0; i<uByteSize; i+=ui32VAdvance) { @@ -2931,7 +3824,7 @@ MMU_MapShadow (MMU_HEAP *pMMUHeap, } DevPAddr = SysCpuPAddrToDevPAddr (PVRSRV_DEVICE_TYPE_SGX, CpuPAddr); - + /* check the physical alignment of the memory to map */ PVR_ASSERT((DevPAddr.uiAddr & pMMUHeap->ui32DataPageMask) == 0); PVR_DPF ((PVR_DBG_MESSAGE, @@ -2944,17 +3837,157 @@ MMU_MapShadow (MMU_HEAP *pMMUHeap, MMU_MapPage (pMMUHeap, MapDevVAddr, DevPAddr, ui32MemFlags); - + /* loop update */ MapDevVAddr.uiAddr += ui32VAdvance; uOffset += ui32PAdvance; } #if defined(PDUMP) MMU_PDumpPageTables (pMMUHeap, MapBaseDevVAddr, uByteSize, IMG_FALSE, hUniqueTag); -#endif +#endif /* #if defined(PDUMP) */ +} + +/*! +****************************************************************************** + FUNCTION: MMU_MapShadowSparse + + PURPOSE: Create a mapping for a range of pages from either a CPU + virtual adddress, (or if NULL a hOSMemHandle) to a specified + device virtual address. + + PARAMETERS: In: pMMUHeap - the mmu. + In: MapBaseDevVAddr - A page aligned device virtual address + to start mapping from. + In: ui32ChunkSize - Size of the chunk (must be page multiple) + In: ui32NumVirtChunks - Number of virtual chunks + In: ui32NumPhysChunks - Number of physical chunks + In: pabMapChunk - Mapping array + In: CpuVAddr - A page aligned CPU virtual address. + In: hOSMemHandle - An alternative OS specific memory handle + for mapping RAM without a CPU virtual + address + Out: pDevVAddr - deprecated - It used to return a byte aligned + device virtual address corresponding to the + cpu virtual address (When CpuVAddr wasn't + constrained to be page aligned.) Now it just + returns MapBaseDevVAddr. Unaligned semantics + can easily be handled above this API if required. + In: hUniqueTag - A unique ID for use as a tag identifier + In: ui32MemFlags - page table flags. + RETURNS: None +******************************************************************************/ +IMG_VOID +MMU_MapShadowSparse (MMU_HEAP *pMMUHeap, + IMG_DEV_VIRTADDR MapBaseDevVAddr, + IMG_UINT32 ui32ChunkSize, + IMG_UINT32 ui32NumVirtChunks, + IMG_UINT32 ui32NumPhysChunks, + IMG_BOOL *pabMapChunk, + IMG_CPU_VIRTADDR CpuVAddr, + IMG_HANDLE hOSMemHandle, + IMG_DEV_VIRTADDR *pDevVAddr, + IMG_UINT32 ui32MemFlags, + IMG_HANDLE hUniqueTag) +{ + IMG_UINT32 i; + IMG_UINT32 uOffset = 0; + IMG_DEV_VIRTADDR MapDevVAddr; + IMG_UINT32 ui32VAdvance; + IMG_UINT32 ui32PAdvance; + IMG_SIZE_T uiSizeVM = ui32ChunkSize * ui32NumVirtChunks; + IMG_UINT32 ui32ChunkIndex = 0; + IMG_UINT32 ui32ChunkOffset = 0; +#if !defined(PVRSRV_NEED_PVR_DPF) + PVR_UNREFERENCED_PARAMETER(ui32NumPhysChunks); +#endif +#if !defined (PDUMP) + PVR_UNREFERENCED_PARAMETER(hUniqueTag); +#endif + + PVR_DPF ((PVR_DBG_MESSAGE, + "MMU_MapShadowSparse: DevVAddr:%08X, VM space:0x%x, CPUVAddr:%08X PHYS space:0x%x", + MapBaseDevVAddr.uiAddr, + uiSizeVM, + (IMG_UINTPTR_T)CpuVAddr, + ui32ChunkSize * ui32NumPhysChunks)); + + /* set the virtual and physical advance */ + ui32VAdvance = pMMUHeap->ui32DataPageSize; + ui32PAdvance = pMMUHeap->ui32DataPageSize; + + /* note: can't do useful check on the CPU Addr other than it being at least 4k alignment */ + PVR_ASSERT(((IMG_UINTPTR_T)CpuVAddr & (SGX_MMU_PAGE_SIZE - 1)) == 0); + PVR_ASSERT(((IMG_UINT32)uiSizeVM & pMMUHeap->ui32DataPageMask) == 0); + pDevVAddr->uiAddr = MapBaseDevVAddr.uiAddr; + + /* Shouldn't come through the sparse interface */ + PVR_ASSERT((ui32MemFlags & PVRSRV_MEM_DUMMY) == 0); + + /* Loop through cpu memory and map page by page */ + MapDevVAddr = MapBaseDevVAddr; + for (i=0; i<uiSizeVM; i+=ui32VAdvance) + { + IMG_CPU_PHYADDR CpuPAddr; + IMG_DEV_PHYADDR DevPAddr; + + if (pabMapChunk[i/ui32ChunkSize]) + /*if (pabMapChunk[ui32ChunkIndex])*/ + { + if(CpuVAddr) + { + CpuPAddr = OSMapLinToCPUPhys (hOSMemHandle, + (IMG_VOID *)((IMG_UINTPTR_T)CpuVAddr + uOffset)); + } + else + { + CpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, uOffset); + } + DevPAddr = SysCpuPAddrToDevPAddr (PVRSRV_DEVICE_TYPE_SGX, CpuPAddr); + + /* check the physical alignment of the memory to map */ + PVR_ASSERT((DevPAddr.uiAddr & pMMUHeap->ui32DataPageMask) == 0); + + PVR_DPF ((PVR_DBG_MESSAGE, + "Offset=0x%x: CpuVAddr=%08X, CpuPAddr=%08X, DevVAddr=%08X, DevPAddr=%08X", + uOffset, + (IMG_UINTPTR_T)CpuVAddr + uOffset, + CpuPAddr.uiAddr, + MapDevVAddr.uiAddr, + DevPAddr.uiAddr)); + + MMU_MapPage (pMMUHeap, MapDevVAddr, DevPAddr, ui32MemFlags); + uOffset += ui32PAdvance; + } + + /* loop update */ + MapDevVAddr.uiAddr += ui32VAdvance; + + if (ui32ChunkOffset == ui32ChunkSize) + { + ui32ChunkIndex++; + ui32ChunkOffset = 0; + } + } + + pMMUHeap->bHasSparseMappings = IMG_TRUE; +#if defined(PDUMP) + MMU_PDumpPageTables (pMMUHeap, MapBaseDevVAddr, uiSizeVM, IMG_FALSE, hUniqueTag); +#endif /* #if defined(PDUMP) */ } +/*! +****************************************************************************** + FUNCTION: MMU_UnmapPages + + PURPOSE: unmap pages and invalidate virtual address + PARAMETERS: In: psMMUHeap - the mmu. + In: sDevVAddr - the device virtual address. + In: ui32PageCount - page count + In: hUniqueTag - A unique ID for use as a tag identifier + + RETURNS: None +******************************************************************************/ IMG_VOID MMU_UnmapPages (MMU_HEAP *psMMUHeap, IMG_DEV_VIRTADDR sDevVAddr, @@ -2972,24 +4005,24 @@ MMU_UnmapPages (MMU_HEAP *psMMUHeap, PVR_UNREFERENCED_PARAMETER(hUniqueTag); #endif - + /* setup tmp devvaddr to base of allocation */ sTmpDevVAddr = sDevVAddr; for(i=0; i<ui32PageCount; i++) { MMU_PT_INFO **ppsPTInfoList; - + /* find the index/offset in PD entries */ ui32PDIndex = sTmpDevVAddr.uiAddr >> psMMUHeap->ui32PDShift; - + /* and advance to the first PT info list */ ppsPTInfoList = &psMMUHeap->psMMUContext->apsPTInfoList[ui32PDIndex]; - + /* find the index/offset of the first PT in the first PT page */ ui32PTIndex = (sTmpDevVAddr.uiAddr & psMMUHeap->ui32PTMask) >> psMMUHeap->ui32PTShift; - - if (!ppsPTInfoList[0]) + /* Is the PT page valid? */ + if ((!ppsPTInfoList[0]) && (!psMMUHeap->bHasSparseMappings)) { PVR_DPF((PVR_DBG_ERROR, "MMU_UnmapPages: ERROR Invalid PT for alloc at VAddr:0x%08X (VaddrIni:0x%08X AllocPage:%u) PDIdx:%u PTIdx:%u", sTmpDevVAddr.uiAddr, @@ -2998,19 +4031,19 @@ MMU_UnmapPages (MMU_HEAP *psMMUHeap, ui32PDIndex, ui32PTIndex)); - + /* advance the sTmpDevVAddr by one page */ sTmpDevVAddr.uiAddr += uPageSize; - + /* Try to unmap the remaining allocation pages */ continue; } CheckPT(ppsPTInfoList[0]); - + /* setup pointer to the first entry in the PT page */ pui32Tmp = (IMG_UINT32*)ppsPTInfoList[0]->PTPageCpuVAddr; - + /* Decrement the valid page count only if the current page is valid*/ if (pui32Tmp[ui32PTIndex] & SGX_MMU_PTE_VALID) { ppsPTInfoList[0]->ui32ValidPTECount--; @@ -3026,25 +4059,27 @@ MMU_UnmapPages (MMU_HEAP *psMMUHeap, PVR_DPF((PVR_DBG_ERROR, "MMU_UnmapPages: Page table entry value: 0x%08X", pui32Tmp[ui32PTIndex])); } - + /* The page table count should not go below zero */ PVR_ASSERT((IMG_INT32)ppsPTInfoList[0]->ui32ValidPTECount >= 0); + MakeKernelPageReadWrite(ppsPTInfoList[0]->PTPageCpuVAddr); #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) - + /* point the PT entry to the dummy data page */ pui32Tmp[ui32PTIndex] = (psMMUHeap->psMMUContext->psDevInfo->sDummyDataDevPAddr.uiAddr>>SGX_MMU_PTE_ADDR_ALIGNSHIFT) | SGX_MMU_PTE_VALID; #else - + /* invalidate entry */ #if defined(FIX_HW_BRN_31620) BRN31620InvalidatePageTableEntry(psMMUHeap->psMMUContext, ui32PDIndex, ui32PTIndex, &pui32Tmp[ui32PTIndex]); #else pui32Tmp[ui32PTIndex] = 0; #endif #endif + MakeKernelPageReadOnly(ppsPTInfoList[0]->PTPageCpuVAddr); CheckPT(ppsPTInfoList[0]); - + /* advance the sTmpDevVAddr by one page */ sTmpDevVAddr.uiAddr += uPageSize; } @@ -3052,10 +4087,21 @@ MMU_UnmapPages (MMU_HEAP *psMMUHeap, #if defined(PDUMP) MMU_PDumpPageTables (psMMUHeap, sDevVAddr, uPageSize*ui32PageCount, IMG_TRUE, hUniqueTag); -#endif +#endif /* #if defined(PDUMP) */ } +/*! +****************************************************************************** + FUNCTION: MMU_GetPhysPageAddr + + PURPOSE: extracts physical address from MMU page tables + + PARAMETERS: In: pMMUHeap - the mmu + PARAMETERS: In: sDevVPageAddr - the virtual address to extract physical + page mapping from + RETURNS: None +******************************************************************************/ IMG_DEV_PHYADDR MMU_GetPhysPageAddr(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR sDevVPageAddr) { @@ -3064,31 +4110,35 @@ MMU_GetPhysPageAddr(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR sDevVPageAddr) IMG_DEV_PHYADDR sDevPAddr; MMU_PT_INFO **ppsPTInfoList; - + /* find the index/offset in PD entries */ ui32Index = sDevVPageAddr.uiAddr >> pMMUHeap->ui32PDShift; - + /* and advance to the first PT info list */ ppsPTInfoList = &pMMUHeap->psMMUContext->apsPTInfoList[ui32Index]; if (!ppsPTInfoList[0]) { - PVR_DPF((PVR_DBG_ERROR,"MMU_GetPhysPageAddr: Not mapped in at 0x%08x", sDevVPageAddr.uiAddr)); + /* Heaps with sparse mappings are allowed invalid pages */ + if (!pMMUHeap->bHasSparseMappings) + { + PVR_DPF((PVR_DBG_ERROR,"MMU_GetPhysPageAddr: Not mapped in at 0x%08x", sDevVPageAddr.uiAddr)); + } sDevPAddr.uiAddr = 0; return sDevPAddr; } - + /* find the index/offset of the first PT in the first PT page */ ui32Index = (sDevVPageAddr.uiAddr & pMMUHeap->ui32PTMask) >> pMMUHeap->ui32PTShift; - + /* setup pointer to the first entry in the PT page */ pui32PageTable = (IMG_UINT32*)ppsPTInfoList[0]->PTPageCpuVAddr; - + /* read back physical page */ sDevPAddr.uiAddr = pui32PageTable[ui32Index]; - + /* Mask off non-address bits */ sDevPAddr.uiAddr &= ~(pMMUHeap->ui32DataPageMask>>SGX_MMU_PTE_ADDR_ALIGNSHIFT); - + /* and align the address */ sDevPAddr.uiAddr <<= SGX_MMU_PTE_ADDR_ALIGNSHIFT; return sDevPAddr; @@ -3101,6 +4151,18 @@ IMG_DEV_PHYADDR MMU_GetPDDevPAddr(MMU_CONTEXT *pMMUContext) } +/*! +****************************************************************************** + FUNCTION: SGXGetPhysPageAddr + + PURPOSE: Gets DEV and CPU physical address of sDevVAddr + + PARAMETERS: In: hDevMemHeap - device mem heap handle + PARAMETERS: In: sDevVAddr - the base virtual address to unmap from + PARAMETERS: Out: pDevPAddr - DEV physical address + PARAMETERS: Out: pCpuPAddr - CPU physical address + RETURNS: None +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR SGXGetPhysPageAddrKM (IMG_HANDLE hDevMemHeap, IMG_DEV_VIRTADDR sDevVAddr, @@ -3110,18 +4172,30 @@ PVRSRV_ERROR SGXGetPhysPageAddrKM (IMG_HANDLE hDevMemHeap, MMU_HEAP *pMMUHeap; IMG_DEV_PHYADDR DevPAddr; - - + /* + Get MMU Heap From hDevMemHeap + */ pMMUHeap = (MMU_HEAP*)BM_GetMMUHeap(hDevMemHeap); DevPAddr = MMU_GetPhysPageAddr(pMMUHeap, sDevVAddr); - pCpuPAddr->uiAddr = DevPAddr.uiAddr; + pCpuPAddr->uiAddr = DevPAddr.uiAddr; /* SysDevPAddrToCPUPAddr(DevPAddr) */ pDevPAddr->uiAddr = DevPAddr.uiAddr; return (pDevPAddr->uiAddr != 0) ? PVRSRV_OK : PVRSRV_ERROR_INVALID_PARAMS; } +/*! +****************************************************************************** + FUNCTION: SGXGetMMUPDAddrKM + + PURPOSE: Gets PD device physical address of hDevMemContext + + PARAMETERS: In: hDevCookie - device cookie + PARAMETERS: In: hDevMemContext - memory context + PARAMETERS: Out: psPDDevPAddr - MMU PD address + RETURNS: None +******************************************************************************/ PVRSRV_ERROR SGXGetMMUPDAddrKM(IMG_HANDLE hDevCookie, IMG_HANDLE hDevMemContext, IMG_DEV_PHYADDR *psPDDevPAddr) @@ -3131,12 +4205,24 @@ PVRSRV_ERROR SGXGetMMUPDAddrKM(IMG_HANDLE hDevCookie, return PVRSRV_ERROR_INVALID_PARAMS; } - + /* return the address */ *psPDDevPAddr = ((BM_CONTEXT*)hDevMemContext)->psMMUContext->sPDDevPAddr; return PVRSRV_OK; } +/*! +****************************************************************************** + FUNCTION: MMU_BIFResetPDAlloc + + PURPOSE: Allocate a dummy Page Directory, Page Table and Page which can + be used for dynamic dummy page mapping during SGX reset. + Note: since this is only used for hardware recovery, no + pdumping is performed. + + PARAMETERS: In: psDevInfo - device info + RETURNS: PVRSRV_OK or error +******************************************************************************/ PVRSRV_ERROR MMU_BIFResetPDAlloc(PVRSRV_SGXDEV_INFO *psDevInfo) { PVRSRV_ERROR eError; @@ -3151,13 +4237,16 @@ PVRSRV_ERROR MMU_BIFResetPDAlloc(PVRSRV_SGXDEV_INFO *psDevInfo) psLocalDevMemArena = psSysData->apsLocalDevMemArena[0]; - + /* allocate 3 pages - for the PD, PT and dummy page */ if(psLocalDevMemArena == IMG_NULL) { - + /* UMA system */ eError = OSAllocPages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, 3 * SGX_MMU_PAGE_SIZE, SGX_MMU_PAGE_SIZE, + IMG_NULL, + 0, + IMG_NULL, (IMG_VOID **)&pui8MemBlock, &hOSMemHandle); if (eError != PVRSRV_OK) @@ -3166,7 +4255,7 @@ PVRSRV_ERROR MMU_BIFResetPDAlloc(PVRSRV_SGXDEV_INFO *psDevInfo) return eError; } - + /* translate address to device physical */ if(pui8MemBlock) { sMemBlockCpuPAddr = OSMapLinToCPUPhys(hOSMemHandle, @@ -3174,13 +4263,14 @@ PVRSRV_ERROR MMU_BIFResetPDAlloc(PVRSRV_SGXDEV_INFO *psDevInfo) } else { - + /* This isn't used in all cases since not all ports currently support + * OSMemHandleToCpuPAddr() */ sMemBlockCpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, 0); } } else { - + /* non-UMA system */ if(RA_Alloc(psLocalDevMemArena, 3 * SGX_MMU_PAGE_SIZE, @@ -3189,13 +4279,15 @@ PVRSRV_ERROR MMU_BIFResetPDAlloc(PVRSRV_SGXDEV_INFO *psDevInfo) 0, SGX_MMU_PAGE_SIZE, 0, + IMG_NULL, + 0, &(sMemBlockSysPAddr.uiAddr)) != IMG_TRUE) { PVR_DPF((PVR_DBG_ERROR, "MMU_BIFResetPDAlloc: ERROR call to RA_Alloc failed")); return PVRSRV_ERROR_OUT_OF_MEMORY; } - + /* derive the CPU virtual address */ sMemBlockCpuPAddr = SysSysPAddrToCpuPAddr(sMemBlockSysPAddr); pui8MemBlock = OSMapPhysToLin(sMemBlockCpuPAddr, SGX_MMU_PAGE_SIZE * 3, @@ -3212,20 +4304,29 @@ PVRSRV_ERROR MMU_BIFResetPDAlloc(PVRSRV_SGXDEV_INFO *psDevInfo) psDevInfo->sBIFResetPDDevPAddr = SysCpuPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sMemBlockCpuPAddr); psDevInfo->sBIFResetPTDevPAddr.uiAddr = psDevInfo->sBIFResetPDDevPAddr.uiAddr + SGX_MMU_PAGE_SIZE; psDevInfo->sBIFResetPageDevPAddr.uiAddr = psDevInfo->sBIFResetPTDevPAddr.uiAddr + SGX_MMU_PAGE_SIZE; - - + /* override pointer cast warnings */ + /* PRQA S 3305,509 2 */ psDevInfo->pui32BIFResetPD = (IMG_UINT32 *)pui8MemBlock; psDevInfo->pui32BIFResetPT = (IMG_UINT32 *)(pui8MemBlock + SGX_MMU_PAGE_SIZE); - + /* Invalidate entire PD and PT. */ OSMemSet(psDevInfo->pui32BIFResetPD, 0, SGX_MMU_PAGE_SIZE); OSMemSet(psDevInfo->pui32BIFResetPT, 0, SGX_MMU_PAGE_SIZE); - + /* Fill dummy page with markers. */ OSMemSet(pui8MemBlock + (2 * SGX_MMU_PAGE_SIZE), 0xDB, SGX_MMU_PAGE_SIZE); return PVRSRV_OK; } +/*! +****************************************************************************** + FUNCTION: MMU_BIFResetPDFree + + PURPOSE: Free resources allocated in MMU_BIFResetPDAlloc. + + PARAMETERS: In: psDevInfo - device info + RETURNS: +******************************************************************************/ IMG_VOID MMU_BIFResetPDFree(PVRSRV_SGXDEV_INFO *psDevInfo) { SYS_DATA *psSysData; @@ -3236,7 +4337,7 @@ IMG_VOID MMU_BIFResetPDFree(PVRSRV_SGXDEV_INFO *psDevInfo) psLocalDevMemArena = psSysData->apsLocalDevMemArena[0]; - + /* free the page directory */ if(psLocalDevMemArena == IMG_NULL) { OSFreePages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, @@ -3256,274 +4357,60 @@ IMG_VOID MMU_BIFResetPDFree(PVRSRV_SGXDEV_INFO *psDevInfo) } } - -#if defined(FIX_HW_BRN_22997) && defined(FIX_HW_BRN_23030) && defined(SGX_FEATURE_HOST_PORT) -PVRSRV_ERROR WorkaroundBRN22997Alloc(PVRSRV_DEVICE_NODE *psDeviceNode) +IMG_VOID MMU_CheckFaultAddr(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32PDDevPAddr, IMG_UINT32 ui32FaultAddr) { - PVRSRV_ERROR eError; - SYS_DATA *psSysData; - RA_ARENA *psLocalDevMemArena; - IMG_HANDLE hPTPageOSMemHandle = IMG_NULL; - IMG_HANDLE hPDPageOSMemHandle = IMG_NULL; - IMG_UINT32 *pui32PD = IMG_NULL; - IMG_UINT32 *pui32PT = IMG_NULL; - IMG_CPU_PHYADDR sCpuPAddr; - IMG_DEV_PHYADDR sPTDevPAddr; - IMG_DEV_PHYADDR sPDDevPAddr; - PVRSRV_SGXDEV_INFO *psDevInfo; - IMG_UINT32 ui32PDOffset; - IMG_UINT32 ui32PTOffset; + MMU_CONTEXT *psMMUContext = psDevInfo->pvMMUContextList; - psDevInfo = (PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; - - SysAcquireData(&psSysData); - - psLocalDevMemArena = psSysData->apsLocalDevMemArena[0]; - - - if(psLocalDevMemArena == IMG_NULL) + while (psMMUContext && (psMMUContext->sPDDevPAddr.uiAddr != ui32PDDevPAddr)) { - - eError = OSAllocPages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, - SGX_MMU_PAGE_SIZE, - SGX_MMU_PAGE_SIZE, - (IMG_VOID **)&pui32PT, - &hPTPageOSMemHandle); - if (eError != PVRSRV_OK) - { - PVR_DPF((PVR_DBG_ERROR, "WorkaroundBRN22997: ERROR call to OSAllocPages failed")); - return eError; - } - ui32PTOffset = 0; - - eError = OSAllocPages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, - SGX_MMU_PAGE_SIZE, - SGX_MMU_PAGE_SIZE, - (IMG_VOID **)&pui32PD, - &hPDPageOSMemHandle); - if (eError != PVRSRV_OK) - { - PVR_DPF((PVR_DBG_ERROR, "WorkaroundBRN22997: ERROR call to OSAllocPages failed")); - return eError; - } - ui32PDOffset = 0; - - - if(pui32PT) - { - sCpuPAddr = OSMapLinToCPUPhys(hPTPageOSMemHandle, - pui32PT); - } - else - { - - sCpuPAddr = OSMemHandleToCpuPAddr(hPTPageOSMemHandle, 0); - } - sPTDevPAddr = SysCpuPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); - - if(pui32PD) - { - sCpuPAddr = OSMapLinToCPUPhys(hPDPageOSMemHandle, - pui32PD); - } - else - { - - sCpuPAddr = OSMemHandleToCpuPAddr(hPDPageOSMemHandle, 0); - } - sPDDevPAddr = SysCpuPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); - - } - else - { - - - if(RA_Alloc(psLocalDevMemArena, - SGX_MMU_PAGE_SIZE * 2, - IMG_NULL, - IMG_NULL, - 0, - SGX_MMU_PAGE_SIZE, - 0, - &(psDevInfo->sBRN22997SysPAddr.uiAddr))!= IMG_TRUE) - { - PVR_DPF((PVR_DBG_ERROR, "WorkaroundBRN22997: ERROR call to RA_Alloc failed")); - return PVRSRV_ERROR_OUT_OF_MEMORY; - } - - - sCpuPAddr = SysSysPAddrToCpuPAddr(psDevInfo->sBRN22997SysPAddr); - pui32PT = OSMapPhysToLin(sCpuPAddr, - SGX_MMU_PAGE_SIZE * 2, - PVRSRV_HAP_WRITECOMBINE|PVRSRV_HAP_KERNEL_ONLY, - &hPTPageOSMemHandle); - if(!pui32PT) - { - PVR_DPF((PVR_DBG_ERROR, "WorkaroundBRN22997: ERROR failed to map page tables")); - return PVRSRV_ERROR_BAD_MAPPING; - } - ui32PTOffset = 0; - - - sPTDevPAddr = SysCpuPAddrToDevPAddr(PVRSRV_DEVICE_TYPE_SGX, sCpuPAddr); - - pui32PD = pui32PT + SGX_MMU_PAGE_SIZE/sizeof(IMG_UINT32); - ui32PDOffset = SGX_MMU_PAGE_SIZE; - hPDPageOSMemHandle = hPTPageOSMemHandle; - sPDDevPAddr.uiAddr = sPTDevPAddr.uiAddr + SGX_MMU_PAGE_SIZE; + psMMUContext = psMMUContext->psNext; } - OSMemSet(pui32PD, 0, SGX_MMU_PAGE_SIZE); - OSMemSet(pui32PT, 0, SGX_MMU_PAGE_SIZE); - - - PDUMPMALLOCPAGETABLE(&psDeviceNode->sDevId, hPDPageOSMemHandle, ui32PDOffset, pui32PD, SGX_MMU_PAGE_SIZE, 0, PDUMP_PD_UNIQUETAG); - PDUMPMALLOCPAGETABLE(&psDeviceNode->sDevId, hPTPageOSMemHandle, ui32PTOffset, pui32PT, SGX_MMU_PAGE_SIZE, 0, PDUMP_PT_UNIQUETAG); - PDUMPMEMPTENTRIES(&psDevInfo->sMMUAttrib, hPDPageOSMemHandle, pui32PD, SGX_MMU_PAGE_SIZE, 0, IMG_TRUE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); - PDUMPMEMPTENTRIES(&psDevInfo->sMMUAttrib, hPTPageOSMemHandle, pui32PT, SGX_MMU_PAGE_SIZE, 0, IMG_TRUE, PDUMP_PT_UNIQUETAG, PDUMP_PD_UNIQUETAG); - - psDevInfo->hBRN22997PTPageOSMemHandle = hPTPageOSMemHandle; - psDevInfo->hBRN22997PDPageOSMemHandle = hPDPageOSMemHandle; - psDevInfo->sBRN22997PTDevPAddr = sPTDevPAddr; - psDevInfo->sBRN22997PDDevPAddr = sPDDevPAddr; - psDevInfo->pui32BRN22997PD = pui32PD; - psDevInfo->pui32BRN22997PT = pui32PT; - - return PVRSRV_OK; -} - - -IMG_VOID WorkaroundBRN22997ReadHostPort(PVRSRV_SGXDEV_INFO *psDevInfo) -{ - IMG_UINT32 *pui32PD = psDevInfo->pui32BRN22997PD; - IMG_UINT32 *pui32PT = psDevInfo->pui32BRN22997PT; - IMG_UINT32 ui32PDIndex; - IMG_UINT32 ui32PTIndex; - IMG_DEV_VIRTADDR sDevVAddr; - volatile IMG_UINT32 *pui32HostPort; - IMG_UINT32 ui32BIFCtrl; - - - - - pui32HostPort = (volatile IMG_UINT32*)(((IMG_UINT8*)psDevInfo->pvHostPortBaseKM) + SYS_SGX_HOSTPORT_BRN23030_OFFSET); - - - sDevVAddr.uiAddr = SYS_SGX_HOSTPORT_BASE_DEVVADDR + SYS_SGX_HOSTPORT_BRN23030_OFFSET; - - ui32PDIndex = (sDevVAddr.uiAddr & SGX_MMU_PD_MASK) >> (SGX_MMU_PAGE_SHIFT + SGX_MMU_PT_SHIFT); - ui32PTIndex = (sDevVAddr.uiAddr & SGX_MMU_PT_MASK) >> SGX_MMU_PAGE_SHIFT; - - - pui32PD[ui32PDIndex] = (psDevInfo->sBRN22997PTDevPAddr.uiAddr>>SGX_MMU_PDE_ADDR_ALIGNSHIFT) - | SGX_MMU_PDE_VALID; - - pui32PT[ui32PTIndex] = (psDevInfo->sBRN22997PTDevPAddr.uiAddr>>SGX_MMU_PTE_ADDR_ALIGNSHIFT) - | SGX_MMU_PTE_VALID; - - PDUMPMEMPTENTRIES(&psDevInfo->sMMUAttrib, psDevInfo->hBRN22997PDPageOSMemHandle, pui32PD, SGX_MMU_PAGE_SIZE, 0, IMG_TRUE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); - PDUMPMEMPTENTRIES(&psDevInfo->sMMUAttrib, psDevInfo->hBRN22997PTPageOSMemHandle, pui32PT, SGX_MMU_PAGE_SIZE, 0, IMG_TRUE, PDUMP_PT_UNIQUETAG, PDUMP_PD_UNIQUETAG); - - - OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_DIR_LIST_BASE0, - psDevInfo->sBRN22997PDDevPAddr.uiAddr); - PDUMPPDREG(&psDevInfo->sMMUAttrib, EUR_CR_BIF_DIR_LIST_BASE0, psDevInfo->sBRN22997PDDevPAddr.uiAddr, PDUMP_PD_UNIQUETAG); - - - ui32BIFCtrl = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL); - OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32BIFCtrl | EUR_CR_BIF_CTRL_INVALDC_MASK); - PDUMPREG(SGX_PDUMPREG_NAME, EUR_CR_BIF_CTRL, ui32BIFCtrl | EUR_CR_BIF_CTRL_INVALDC_MASK); - OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32BIFCtrl); - PDUMPREG(SGX_PDUMPREG_NAME, EUR_CR_BIF_CTRL, ui32BIFCtrl); - - - if (pui32HostPort) - { - - IMG_UINT32 ui32Tmp; - ui32Tmp = *pui32HostPort; - } - else + if (psMMUContext) { - PVR_DPF((PVR_DBG_ERROR,"Host Port not present for BRN22997 workaround")); - } - - - - - - - - PDUMPCOMMENT("RDW :SGXMEM:v4:%08X\r\n", sDevVAddr.uiAddr); - - PDUMPCOMMENT("SAB :SGXMEM:v4:%08X 4 0 hostport.bin", sDevVAddr.uiAddr); - - - pui32PD[ui32PDIndex] = 0; - pui32PT[ui32PTIndex] = 0; + IMG_UINT32 ui32PTIndex; + IMG_UINT32 ui32PDIndex; - - PDUMPMEMPTENTRIES(&psDevInfo->sMMUAttrib, psDevInfo->hBRN22997PDPageOSMemHandle, pui32PD, SGX_MMU_PAGE_SIZE, 0, IMG_TRUE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); - PDUMPMEMPTENTRIES(&psDevInfo->sMMUAttrib, psDevInfo->hBRN22997PTPageOSMemHandle, pui32PT, SGX_MMU_PAGE_SIZE, 0, IMG_TRUE, PDUMP_PT_UNIQUETAG, PDUMP_PD_UNIQUETAG); - - OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32BIFCtrl | EUR_CR_BIF_CTRL_INVALDC_MASK); - PDUMPREG(SGX_PDUMPREG_NAME, EUR_CR_BIF_CTRL, ui32BIFCtrl | EUR_CR_BIF_CTRL_INVALDC_MASK); - OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32BIFCtrl); - PDUMPREG(SGX_PDUMPREG_NAME, EUR_CR_BIF_CTRL, ui32BIFCtrl); -} - - -IMG_VOID WorkaroundBRN22997Free(PVRSRV_DEVICE_NODE *psDeviceNode) -{ - SYS_DATA *psSysData; - RA_ARENA *psLocalDevMemArena; - PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO*)psDeviceNode->pvDevice; - - - SysAcquireData(&psSysData); - - psLocalDevMemArena = psSysData->apsLocalDevMemArena[0]; + PVR_LOG(("Found MMU context for page fault 0x%08x", ui32FaultAddr)); + PVR_LOG(("GPU memory context is for PID=%d (%s)", psMMUContext->ui32PID, psMMUContext->szName)); - PDUMPFREEPAGETABLE(&psDeviceNode->sDevId, psDevInfo->hBRN22997PDPageOSMemHandle, psDevInfo->pui32BRN22997PD, SGX_MMU_PAGE_SIZE, 0, PDUMP_PD_UNIQUETAG); - PDUMPFREEPAGETABLE(&psDeviceNode->sDevId, psDevInfo->hBRN22997PTPageOSMemHandle, psDevInfo->pui32BRN22997PT, SGX_MMU_PAGE_SIZE, 0, PDUMP_PT_UNIQUETAG); + ui32PTIndex = (ui32FaultAddr & SGX_MMU_PT_MASK) >> SGX_MMU_PAGE_SHIFT; + ui32PDIndex = (ui32FaultAddr & SGX_MMU_PD_MASK) >> (SGX_MMU_PT_SHIFT + SGX_MMU_PAGE_SHIFT); - - if(psLocalDevMemArena == IMG_NULL) - { - if (psDevInfo->pui32BRN22997PD != IMG_NULL) + if (psMMUContext->apsPTInfoList[ui32PDIndex]) { - OSFreePages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, - SGX_MMU_PAGE_SIZE, - psDevInfo->pui32BRN22997PD, - psDevInfo->hBRN22997PDPageOSMemHandle); - } + if (psMMUContext->apsPTInfoList[ui32PDIndex]->PTPageCpuVAddr) + { + IMG_UINT32 *pui32Ptr = psMMUContext->apsPTInfoList[ui32PDIndex]->PTPageCpuVAddr; + IMG_UINT32 ui32PTE = pui32Ptr[ui32PTIndex]; - if (psDevInfo->pui32BRN22997PT != IMG_NULL) - { - OSFreePages(PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_KERNEL_ONLY, - SGX_MMU_PAGE_SIZE, - psDevInfo->pui32BRN22997PT, - psDevInfo->hBRN22997PTPageOSMemHandle); + PVR_LOG(("PDE valid: PTE = 0x%08x (PhysAddr = 0x%08x, %s)", + ui32PTE, + ui32PTE & SGX_MMU_PTE_ADDR_MASK, + ui32PTE & SGX_MMU_PTE_VALID?"valid":"Invalid")); + } + else + { + PVR_LOG(("Found PT info but no CPU address")); + } } - } - else - { - if (psDevInfo->pui32BRN22997PT != IMG_NULL) + else { - OSUnMapPhysToLin(psDevInfo->pui32BRN22997PT, - SGX_MMU_PAGE_SIZE * 2, - PVRSRV_HAP_WRITECOMBINE|PVRSRV_HAP_KERNEL_ONLY, - psDevInfo->hBRN22997PTPageOSMemHandle); - - - RA_Free(psLocalDevMemArena, psDevInfo->sBRN22997SysPAddr.uiAddr, IMG_FALSE); + PVR_LOG(("No PDE found")); } } } -#endif - #if defined(SUPPORT_EXTERNAL_SYSTEM_CACHE) +/*! +****************************************************************************** + FUNCTION: MMU_MapExtSystemCacheRegs + + PURPOSE: maps external system cache control registers into SGX MMU + + PARAMETERS: In: psDeviceNode - device node + RETURNS: +******************************************************************************/ PVRSRV_ERROR MMU_MapExtSystemCacheRegs(PVRSRV_DEVICE_NODE *psDeviceNode) { IMG_UINT32 *pui32PT; @@ -3555,12 +4442,13 @@ PVRSRV_ERROR MMU_MapExtSystemCacheRegs(PVRSRV_DEVICE_NODE *psDeviceNode) pui32PT = (IMG_UINT32 *) psDeviceNode->sDevMemoryInfo.pBMKernelContext->psMMUContext->apsPTInfoList[ui32PDIndex]->PTPageCpuVAddr; - + MakeKernelPageReadWrite(pui32PT); + /* map the PT to the registers */ pui32PT[ui32PTIndex] = (psDevInfo->sExtSysCacheRegsDevPBase.uiAddr>>SGX_MMU_PTE_ADDR_ALIGNSHIFT) | SGX_MMU_PTE_VALID; - + MakeKernelPageReadOnly(pui32PT); #if defined(PDUMP) - + /* Add the entery to the PT */ { IMG_DEV_PHYADDR sDevPAddr; IMG_CPU_PHYADDR sCpuPAddr; @@ -3598,6 +4486,15 @@ PVRSRV_ERROR MMU_MapExtSystemCacheRegs(PVRSRV_DEVICE_NODE *psDeviceNode) } +/*! +****************************************************************************** + FUNCTION: MMU_UnmapExtSystemCacheRegs + + PURPOSE: unmaps external system cache control registers + + PARAMETERS: In: psDeviceNode - device node + RETURNS: +******************************************************************************/ PVRSRV_ERROR MMU_UnmapExtSystemCacheRegs(PVRSRV_DEVICE_NODE *psDeviceNode) { SYS_DATA *psSysData; @@ -3621,11 +4518,11 @@ PVRSRV_ERROR MMU_UnmapExtSystemCacheRegs(PVRSRV_DEVICE_NODE *psDeviceNode) psLocalDevMemArena = psSysData->apsLocalDevMemArena[0]; - + /* unmap the MMU page table from the PD */ ui32PDIndex = (SGX_EXT_SYSTEM_CACHE_REGS_DEVVADDR_BASE & SGX_MMU_PD_MASK) >> (SGX_MMU_PAGE_SHIFT + SGX_MMU_PT_SHIFT); ui32PTIndex = (SGX_EXT_SYSTEM_CACHE_REGS_DEVVADDR_BASE & SGX_MMU_PT_MASK) >> SGX_MMU_PAGE_SHIFT; - + /* Only unmap it if the PT hasn't already been freed */ if (psDeviceNode->sDevMemoryInfo.pBMKernelContext->psMMUContext->apsPTInfoList[ui32PDIndex]) { if (psDeviceNode->sDevMemoryInfo.pBMKernelContext->psMMUContext->apsPTInfoList[ui32PDIndex]->PTPageCpuVAddr) @@ -3634,7 +4531,9 @@ PVRSRV_ERROR MMU_UnmapExtSystemCacheRegs(PVRSRV_DEVICE_NODE *psDeviceNode) } } + MakeKernelPageReadWrite(pui32PT); pui32PT[ui32PTIndex] = 0; + MakeKernelPageReadOnly(pui32PT); PDUMPMEMPTENTRIES(&sMMUAttrib, psDeviceNode->sDevMemoryInfo.pBMKernelContext->psMMUContext->hPDOSMemHandle, &pui32PT[ui32PTIndex], sizeof(IMG_UINT32), 0, IMG_FALSE, PDUMP_PD_UNIQUETAG, PDUMP_PT_UNIQUETAG); @@ -3644,6 +4543,16 @@ PVRSRV_ERROR MMU_UnmapExtSystemCacheRegs(PVRSRV_DEVICE_NODE *psDeviceNode) #if PAGE_TEST +/*! +****************************************************************************** + FUNCTION: PageTest + + PURPOSE: Tests page table memory, for use during device bring-up. + + PARAMETERS: In: void* pMem - page address (CPU mapped) + PARAMETERS: In: IMG_DEV_PHYADDR sDevPAddr - page device phys address + RETURNS: None, provides debug output and breaks if an error is detected. +******************************************************************************/ static IMG_VOID PageTest(IMG_VOID* pMem, IMG_DEV_PHYADDR sDevPAddr) { volatile IMG_UINT32 ui32WriteData; @@ -3661,7 +4570,7 @@ static IMG_VOID PageTest(IMG_VOID* pMem, IMG_DEV_PHYADDR sDevPAddr) if (ui32WriteData != ui32ReadData) { - + // Mem fault PVR_DPF ((PVR_DBG_ERROR, "Error - memory page test failed at device phys address 0x%08X", sDevPAddr.uiAddr + (n<<2) )); PVR_DBG_BREAK; bOK = IMG_FALSE; @@ -3677,7 +4586,7 @@ static IMG_VOID PageTest(IMG_VOID* pMem, IMG_DEV_PHYADDR sDevPAddr) if (ui32WriteData != ui32ReadData) { - + // Mem fault PVR_DPF ((PVR_DBG_ERROR, "Error - memory page test failed at device phys address 0x%08X", sDevPAddr.uiAddr + (n<<2) )); PVR_DBG_BREAK; bOK = IMG_FALSE; @@ -3695,3 +4604,8 @@ static IMG_VOID PageTest(IMG_VOID* pMem, IMG_DEV_PHYADDR sDevPAddr) } #endif +/****************************************************************************** + End of file (mmu.c) +******************************************************************************/ + + diff --git a/sgx/services4/srvkm/devices/sgx/mmu.h b/sgx/services4/srvkm/devices/sgx/mmu.h index 59b24c4..4d5160e 100644 --- a/sgx/services4/srvkm/devices/sgx/mmu.h +++ b/sgx/services4/srvkm/devices/sgx/mmu.h @@ -1,53 +1,131 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title MMU Management +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Implements basic low level control of MMU. +@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. + +*/ /**************************************************************************/ #ifndef _MMU_H_ #define _MMU_H_ #include "sgxinfokm.h" +/* +****************************************************************************** + FUNCTION: MMU_Initialise + + PURPOSE: Initialise the mmu module. + + PARAMETERS: None + RETURNS: PVRSRV_ERROR +******************************************************************************/ PVRSRV_ERROR MMU_Initialise (PVRSRV_DEVICE_NODE *psDeviceNode, MMU_CONTEXT **ppsMMUContext, IMG_DEV_PHYADDR *psPDDevPAddr); +/* +****************************************************************************** + FUNCTION: MMU_Finalise + + PURPOSE: Finalise the mmu module, deallocate all resources. + + PARAMETERS: None. + RETURNS: None. +******************************************************************************/ IMG_VOID MMU_Finalise (MMU_CONTEXT *psMMUContext); +/* +****************************************************************************** + FUNCTION: MMU_InsertHeap + + PURPOSE: Inserts shared heap into the specified context + from the kernel context + + PARAMETERS: None. + RETURNS: None. +******************************************************************************/ IMG_VOID MMU_InsertHeap(MMU_CONTEXT *psMMUContext, MMU_HEAP *psMMUHeap); +/* +****************************************************************************** + FUNCTION: MMU_Create + + PURPOSE: Create an mmu device. + + PARAMETERS: In: psMMUContext - + In: psDevArena - + Out: ppsVMArena + RETURNS: MMU_HEAP +******************************************************************************/ MMU_HEAP * MMU_Create (MMU_CONTEXT *psMMUContext, DEV_ARENA_DESCRIPTOR *psDevArena, RA_ARENA **ppsVMArena, PDUMP_MMU_ATTRIB **ppsMMUAttrib); +/* +****************************************************************************** + FUNCTION: MMU_Delete + + PURPOSE: Delete an mmu device. + + PARAMETERS: In: pMMUHeap - The mmu to delete. + RETURNS: +******************************************************************************/ IMG_VOID MMU_Delete (MMU_HEAP *pMMUHeap); +/* +****************************************************************************** + FUNCTION: MMU_Alloc + PURPOSE: Allocate space in an mmu's virtual address space. + PARAMETERS: In: pMMUHeap - MMU to allocate on. + In: uSize - Size in bytes to allocate. + Out: pActualSize - If non null receives actual size allocated. + In: uFlags - Allocation flags. + In: uDevVAddrAlignment - Required alignment. + Out: pDevVAddr - Receives base address of allocation. + RETURNS: IMG_TRUE - Success + IMG_FALSE - Failure +******************************************************************************/ IMG_BOOL MMU_Alloc (MMU_HEAP *pMMUHeap, IMG_SIZE_T uSize, @@ -56,17 +134,60 @@ MMU_Alloc (MMU_HEAP *pMMUHeap, IMG_UINT32 uDevVAddrAlignment, IMG_DEV_VIRTADDR *pDevVAddr); +/* +****************************************************************************** + FUNCTION: MMU_Free + PURPOSE: Frees space in an mmu's virtual address space. + PARAMETERS: In: pMMUHeap - MMU to free on. + In: DevVAddr - Base address of allocation. + RETURNS: IMG_TRUE - Success + IMG_FALSE - Failure +******************************************************************************/ IMG_VOID MMU_Free (MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, IMG_UINT32 ui32Size); +/* +****************************************************************************** + FUNCTION: MMU_Enable + + PURPOSE: Enable an mmu. Establishes pages tables and takes the mmu out + of bypass and waits for the mmu to acknowledge enabled. + + PARAMETERS: In: pMMUHeap - the mmu + RETURNS: None +******************************************************************************/ IMG_VOID MMU_Enable (MMU_HEAP *pMMUHeap); +/* +****************************************************************************** + FUNCTION: MMU_Disable + + PURPOSE: Disable an mmu, takes the mmu into bypass. + + PARAMETERS: In: pMMUHeap - the mmu + RETURNS: None +******************************************************************************/ IMG_VOID MMU_Disable (MMU_HEAP *pMMUHeap); +/* +****************************************************************************** + FUNCTION: MMU_MapPages + + PURPOSE: Create a mapping for a range of pages from a device physical + adddress to a specified device virtual address. + + PARAMETERS: In: pMMUHeap - the mmu. + In: DevVAddr - the device virtual address. + In: SysPAddr - the system physical address of the page to map. + In: uSize - size of memory range in bytes + In: ui32MemFlags - page table flags. + In: hUniqueTag - A unique ID for use as a tag identifier + RETURNS: None +******************************************************************************/ IMG_VOID MMU_MapPages (MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, @@ -75,22 +196,131 @@ MMU_MapPages (MMU_HEAP *pMMUHeap, IMG_UINT32 ui32MemFlags, IMG_HANDLE hUniqueTag); +/* +****************************************************************************** + FUNCTION: MMU_MapPagesSparse + + PURPOSE: Create a mapping for a range of pages from a device physical + adddress to a specified device virtual address. + + PARAMETERS: In: pMMUHeap - the mmu. + In: DevVAddr - the device virtual address. + In: SysPAddr - the system physical address of the page to map. + In: ui32ChunkSize - Size of the chunk (must be page multiple) + In: ui32NumVirtChunks - Number of virtual chunks + In: ui32NumPhysChunks - Number of physical chunks + In: pabMapChunk - Mapping array + In: ui32MemFlags - page table flags. + In: hUniqueTag - A unique ID for use as a tag identifier + RETURNS: None +******************************************************************************/ +IMG_VOID +MMU_MapPagesSparse (MMU_HEAP *pMMUHeap, + IMG_DEV_VIRTADDR DevVAddr, + IMG_SYS_PHYADDR SysPAddr, + IMG_UINT32 ui32ChunkSize, + IMG_UINT32 ui32NumVirtChunks, + IMG_UINT32 ui32NumPhysChunks, + IMG_BOOL *pabMapChunk, + IMG_UINT32 ui32MemFlags, + IMG_HANDLE hUniqueTag); + +/* +****************************************************************************** + FUNCTION: MMU_MapShadow + + PURPOSE: Create a mapping for a range of pages from a CPU virtual + adddress to a specified device virtual address. + + PARAMETERS: In: pMMUHeap - the mmu. + In: MapBaseDevVAddr - A page aligned device virtual address + to start mapping from. + In: uByteSize - A page aligned mapping length in bytes. + In: CpuVAddr - A page aligned CPU virtual address. + In: hOSMemHandle - An alternative OS specific memory handle + for mapping RAM without a CPU virtual + address + Out: pDevVAddr - deprecated + In: hUniqueTag - A unique ID for use as a tag identifier + In: ui32MemFlags - page table flags. + RETURNS: None +******************************************************************************/ IMG_VOID MMU_MapShadow (MMU_HEAP * pMMUHeap, IMG_DEV_VIRTADDR MapBaseDevVAddr, - IMG_SIZE_T uByteSize, + IMG_SIZE_T uByteSize, IMG_CPU_VIRTADDR CpuVAddr, IMG_HANDLE hOSMemHandle, IMG_DEV_VIRTADDR * pDevVAddr, IMG_UINT32 ui32MemFlags, IMG_HANDLE hUniqueTag); +/* +****************************************************************************** + FUNCTION: MMU_MapShadowSparse + + PURPOSE: Create a mapping for a range of pages from a CPU virtual + adddress to a specified device virtual address. + + PARAMETERS: In: pMMUHeap - the mmu. + In: MapBaseDevVAddr - A page aligned device virtual address + to start mapping from. + In: ui32ChunkSize - Size of the chunk (must be page multiple) + In: ui32NumVirtChunks - Number of virtual chunks + In: ui32NumPhysChunks - Number of physical chunks + In: pabMapChunk - Mapping array + In: CpuVAddr - A page aligned CPU virtual address. + In: hOSMemHandle - An alternative OS specific memory handle + for mapping RAM without a CPU virtual + address + Out: pDevVAddr - deprecated + In: hUniqueTag - A unique ID for use as a tag identifier + In: ui32MemFlags - page table flags. + RETURNS: None +******************************************************************************/ +IMG_VOID +MMU_MapShadowSparse (MMU_HEAP * pMMUHeap, + IMG_DEV_VIRTADDR MapBaseDevVAddr, + IMG_UINT32 ui32ChunkSize, + IMG_UINT32 ui32NumVirtChunks, + IMG_UINT32 ui32NumPhysChunks, + IMG_BOOL * pabMapChunk, + IMG_CPU_VIRTADDR CpuVAddr, + IMG_HANDLE hOSMemHandle, + IMG_DEV_VIRTADDR * pDevVAddr, + IMG_UINT32 ui32MemFlags, + IMG_HANDLE hUniqueTag); + +/* +****************************************************************************** + FUNCTION: MMU_UnmapPages + + PURPOSE: unmaps pages and invalidates virtual address. + + PARAMETERS: In: psMMUHeap - the mmu. + In: sDevVAddr - the device virtual address. + In: ui32PageCount - page count. + RETURNS: None +******************************************************************************/ IMG_VOID MMU_UnmapPages (MMU_HEAP *psMMUHeap, IMG_DEV_VIRTADDR sDevVAddr, IMG_UINT32 ui32PageCount, IMG_HANDLE hUniqueTag); +/* +****************************************************************************** + FUNCTION: MMU_MapScatter + + PURPOSE: Create a mapping for a list of pages to a specified device + virtual address. + + PARAMETERS: In: pMMUHeap - the mmu. + In: DevVAddr - the device virtual address. + In: psSysAddr - the list of physical addresses of the pages to + map. + RETURNS: None +******************************************************************************/ IMG_VOID MMU_MapScatter (MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR DevVAddr, @@ -100,55 +330,173 @@ MMU_MapScatter (MMU_HEAP *pMMUHeap, IMG_HANDLE hUniqueTag); +/* +****************************************************************************** + FUNCTION: MMU_GetPhysPageAddr + + PURPOSE: extracts physical address from MMU page tables + + PARAMETERS: In: pMMUHeap - the mmu + PARAMETERS: In: sDevVPageAddr - the virtual address to extract physical + page mapping from + RETURNS: IMG_DEV_PHYADDR +******************************************************************************/ IMG_DEV_PHYADDR MMU_GetPhysPageAddr(MMU_HEAP *pMMUHeap, IMG_DEV_VIRTADDR sDevVPageAddr); +/* +****************************************************************************** + FUNCTION: MMU_GetPDDevPAddr + + PURPOSE: returns PD given the MMU context (SGX to MMU API) + + PARAMETERS: In: pMMUContext - the mmu + RETURNS: IMG_DEV_PHYADDR +******************************************************************************/ IMG_DEV_PHYADDR MMU_GetPDDevPAddr(MMU_CONTEXT *pMMUContext); #ifdef SUPPORT_SGX_MMU_BYPASS +/* +****************************************************************************** + FUNCTION: EnableHostAccess + + PURPOSE: Enables Host accesses to device memory, by passing the device + MMU address translation + + PARAMETERS: In: psMMUContext + RETURNS: None +******************************************************************************/ IMG_VOID EnableHostAccess (MMU_CONTEXT *psMMUContext); +/* +****************************************************************************** + FUNCTION: DisableHostAccess + + PURPOSE: Disables Host accesses to device memory, by passing the device + MMU address translation + + PARAMETERS: In: psMMUContext + RETURNS: None +******************************************************************************/ IMG_VOID DisableHostAccess (MMU_CONTEXT *psMMUContext); #endif +/* +****************************************************************************** + FUNCTION: MMU_InvalidateDirectoryCache + + PURPOSE: Invalidates the page directory cache + + PARAMETERS: In: psDevInfo + RETURNS: None +******************************************************************************/ IMG_VOID MMU_InvalidateDirectoryCache(PVRSRV_SGXDEV_INFO *psDevInfo); -PVRSRV_ERROR MMU_BIFResetPDAlloc(PVRSRV_SGXDEV_INFO *psDevInfo); +/* +****************************************************************************** + FUNCTION: MMU_BIFResetPDAlloc -IMG_VOID MMU_BIFResetPDFree(PVRSRV_SGXDEV_INFO *psDevInfo); + PURPOSE: Allocate a dummy Page Directory which causes all virtual + addresses to page fault. -#if defined(FIX_HW_BRN_22997) && defined(FIX_HW_BRN_23030) && defined(SGX_FEATURE_HOST_PORT) -PVRSRV_ERROR WorkaroundBRN22997Alloc(PVRSRV_DEVICE_NODE *psDeviceNode); + PARAMETERS: In: psDevInfo - device info + RETURNS: PVRSRV_OK or error +******************************************************************************/ +PVRSRV_ERROR MMU_BIFResetPDAlloc(PVRSRV_SGXDEV_INFO *psDevInfo); -IMG_VOID WorkaroundBRN22997ReadHostPort(PVRSRV_SGXDEV_INFO *psDevInfo); +/* +****************************************************************************** + FUNCTION: MMU_BIFResetPDFree -IMG_VOID WorkaroundBRN22997Free(PVRSRV_DEVICE_NODE *psDeviceNode); -#endif + PURPOSE: Free resources allocated in MMU_BIFResetPDAlloc. + + PARAMETERS: In: psDevInfo - device info + RETURNS: +******************************************************************************/ +IMG_VOID MMU_BIFResetPDFree(PVRSRV_SGXDEV_INFO *psDevInfo); #if defined(SUPPORT_EXTERNAL_SYSTEM_CACHE) +/* +****************************************************************************** + FUNCTION: MMU_MapExtSystemCacheRegs + + PURPOSE: maps external system cache control registers into SGX MMU + + PARAMETERS: In: psDeviceNode - device node + RETURNS: +******************************************************************************/ PVRSRV_ERROR MMU_MapExtSystemCacheRegs(PVRSRV_DEVICE_NODE *psDeviceNode); -PVRSRV_ERROR MMU_UnmapExtSystemCacheRegs(PVRSRV_DEVICE_NODE *psDeviceNode); -#endif +/* +****************************************************************************** + FUNCTION: MMU_UnmapExtSystemCacheRegs + PURPOSE: unmaps external system cache control registers + + PARAMETERS: In: psDeviceNode - device node + RETURNS: +******************************************************************************/ +PVRSRV_ERROR MMU_UnmapExtSystemCacheRegs(PVRSRV_DEVICE_NODE *psDeviceNode); +#endif /* #if defined(SUPPORT_EXTERNAL_SYSTEM_CACHE) */ + +/* +****************************************************************************** + FUNCTION: MMU_IsHeapShared + + PURPOSE: Is this heap shared? + PARAMETERS: In: pMMU_Heap + RETURNS: true if heap is shared +******************************************************************************/ IMG_BOOL MMU_IsHeapShared(MMU_HEAP* pMMU_Heap); #if defined(FIX_HW_BRN_31620) +/* +****************************************************************************** + FUNCTION: MMU_GetCacheFlushRange + + PURPOSE: Gets device physical address of the mmu context. + + PARAMETERS: In: pMMUContext - the mmu context + Out: pui32RangeMask - Bit mask showing which PD cache + lines have changed + RETURNS: None +******************************************************************************/ IMG_VOID MMU_GetCacheFlushRange(MMU_CONTEXT *pMMUContext, IMG_UINT32 *pui32RangeMask); +/* +****************************************************************************** + FUNCTION: MMU_GetPDPhysAddr + + PURPOSE: Gets device physical address of the mmu contexts PD. + + PARAMETERS: In: pMMUContext - the mmu context + Out: psDevPAddr - Address of PD + RETURNS: None +******************************************************************************/ IMG_VOID MMU_GetPDPhysAddr(MMU_CONTEXT *pMMUContext, IMG_DEV_PHYADDR *psDevPAddr); #endif +IMG_VOID MMU_CheckFaultAddr(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32PDDevPAddr, IMG_UINT32 ui32RegVal); + #if defined(PDUMP) +/* +****************************************************************************** + FUNCTION: MMU_GetPDumpContextID + + PURPOSE: translates device mem context to unique pdump identifier + + PARAMETERS: In: hDevMemContext - device memory per-process context + RETURNS: context identifier used internally in pdump +******************************************************************************/ IMG_UINT32 MMU_GetPDumpContextID(IMG_HANDLE hDevMemContext); -#endif +#endif /* #ifdef PDUMP */ -#endif +#endif /* #ifndef _MMU_H_ */ diff --git a/sgx/services4/srvkm/devices/sgx/pb.c b/sgx/services4/srvkm/devices/sgx/pb.c index ab6523a..bcfe480 100644 --- a/sgx/services4/srvkm/devices/sgx/pb.c +++ b/sgx/services4/srvkm/devices/sgx/pb.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Parameter Buffer management functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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> @@ -35,8 +51,8 @@ #include "pdump_km.h" #include "sgxutils.h" -#ifndef __linux__ -#pragma message("TODO: Review use of OS_PAGEABLE vs OS_NON_PAGEABLE") +#if !defined(__linux__) && !defined(__QNXNTO__) +#pragma message("FIXME: Review use of OS_PAGEABLE vs OS_NON_PAGEABLE") #endif #include "lists.h" @@ -50,6 +66,8 @@ static PVRSRV_PER_PROCESS_DATA *psPerProcCreateSharedPB = IMG_NULL; static PVRSRV_ERROR SGXCleanupSharedPBDescCallback(IMG_PVOID pvParam, IMG_UINT32 ui32Param, IMG_BOOL bDummy); static PVRSRV_ERROR SGXCleanupSharedPBDescCreateLockCallback(IMG_PVOID pvParam, IMG_UINT32 ui32Param, IMG_BOOL bDummy); +/* override level pointer indirection */ +/* PRQA S 5102 12 */ IMG_EXPORT PVRSRV_ERROR SGXFindSharedPBDescKM(PVRSRV_PER_PROCESS_DATA *psPerProc, IMG_HANDLE hDevCookie, @@ -108,7 +126,7 @@ SGXFindSharedPBDescKM(PVRSRV_PER_PROCESS_DATA *psPerProc, sizeof(PVRSRV_KERNEL_MEM_INFO *) * psStubPBDesc->ui32SubKernelMemInfosCount, ppsSharedPBDescSubKernelMemInfos, 0); - + /*not nulling pointer, out of scope*/ PVR_DPF((PVR_DBG_ERROR, "SGXFindSharedPBDescKM: ResManRegisterRes failed")); @@ -173,15 +191,12 @@ ExitNotFound: static PVRSRV_ERROR SGXCleanupSharedPBDescKM(PVRSRV_STUB_PBDESC *psStubPBDescIn) { - + /*PVRSRV_STUB_PBDESC **ppsStubPBDesc;*/ IMG_UINT32 i; PVRSRV_DEVICE_NODE *psDeviceNode; psDeviceNode = (PVRSRV_DEVICE_NODE*)psStubPBDescIn->hDevCookie; - - - psStubPBDescIn->ui32RefCount--; if (psStubPBDescIn->ui32RefCount == 0) { @@ -189,7 +204,6 @@ SGXCleanupSharedPBDescKM(PVRSRV_STUB_PBDESC *psStubPBDescIn) List_PVRSRV_STUB_PBDESC_Remove(psStubPBDescIn); for(i=0 ; i<psStubPBDescIn->ui32SubKernelMemInfosCount; i++) { - PVRSRVFreeDeviceMemKM(psStubPBDescIn->hDevCookie, psStubPBDescIn->ppsSubKernelMemInfos[i]); } @@ -212,16 +226,16 @@ SGXCleanupSharedPBDescKM(PVRSRV_STUB_PBDESC *psStubPBDescIn) sizeof(PVRSRV_STUB_PBDESC), psStubPBDescIn, 0); - + /*not nulling pointer, copy on stack*/ - + /* signal the microkernel to clear its sTAHWPBDesc and s3DHWPBDesc values in sTA3DCtl */ SGXCleanupRequest(psDeviceNode, &sHWPBDescDevVAddr, PVRSRV_CLEANUPCMD_PB, CLEANUP_WITH_POLL); } return PVRSRV_OK; - + /*return PVRSRV_ERROR_INVALID_PARAMS;*/ } static PVRSRV_ERROR SGXCleanupSharedPBDescCallback(IMG_PVOID pvParam, IMG_UINT32 ui32Param, IMG_BOOL bDummy) @@ -281,7 +295,10 @@ SGXAddSharedPBDescKM(PVRSRV_PER_PROCESS_DATA *psPerProc, PVRSRV_SGXDEV_INFO *psSGXDevInfo; PRESMAN_ITEM psResItem; - + /* + * The caller must have previously called SGXFindSharedPBDesc with + * bLockOnFailure set, and not managed to find a suitable shared PB. + */ if (psPerProcCreateSharedPB != psPerProc) { goto NoAdd; @@ -309,7 +326,11 @@ SGXAddSharedPBDescKM(PVRSRV_PER_PROCESS_DATA *psPerProc, } - + /* + * We make the caller think the add was successful, + * but return the existing shared PB desc rather than + * a new one. + */ psResItem = ResManRegisterRes(psPerProc->hResManContext, RESMAN_TYPE_SHARED_PB_DESC, psStubPBDesc, @@ -324,7 +345,10 @@ SGXAddSharedPBDescKM(PVRSRV_PER_PROCESS_DATA *psPerProc, goto NoAddKeepPB; } - + /* + * The caller will unreference the PB desc after + * a successful add, so up the reference count. + */ psStubPBDesc->ui32RefCount++; *phSharedPBDesc = (IMG_HANDLE)psResItem; @@ -423,7 +447,8 @@ SGXAddSharedPBDescKM(PVRSRV_PER_PROCESS_DATA *psPerProc, } psStubPBDesc->hDevCookie = hDevCookie; - + /* Finally everything was prepared successfully so link the new + * PB in to place. */ List_PVRSRV_STUB_PBDESC_Insert(&(psSGXDevInfo->psStubPBDescListKM), psStubPBDesc); @@ -446,7 +471,7 @@ NoAdd: sizeof(PVRSRV_STUB_PBDESC), psStubPBDesc, 0); - + /*not nulling pointer, out of scope*/ } NoAddKeepPB: @@ -464,3 +489,6 @@ NoAddKeepPB: return eRet; } +/****************************************************************************** + End of file (pb.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/devices/sgx/sgx_bridge_km.h b/sgx/services4/srvkm/devices/sgx/sgx_bridge_km.h index 8fb3002..8da3e9f 100644 --- a/sgx/services4/srvkm/devices/sgx/sgx_bridge_km.h +++ b/sgx/services4/srvkm/devices/sgx/sgx_bridge_km.h @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title SGX Bridge Functionality +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Header for the SGX Bridge code +@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. + +*/ /**************************************************************************/ #if !defined(__SGX_BRIDGE_KM_H__) #define __SGX_BRIDGE_KM_H__ @@ -114,6 +131,47 @@ PVRSRV_ERROR DevInitSGXPart2KM(PVRSRV_PER_PROCESS_DATA *psPerProc, SGX_BRIDGE_INIT_INFO *psInitInfo); #endif +/*! + * ***************************************************************************** + * @brief Looks for a parameter buffer description that corresponds to + * a buffer of size ui32TotalPBSize, optionally taking the lock + * needed for SharedPBCreation on failure. + * + * Note if a PB Desc is found then its internal reference counter + * is automatically incremented. It is your responsability to call + * SGXUnrefSharedPBDesc to decrement this reference and free associated + * resources when you are done. + * + * If bLockOnFailure is set, and a suitable shared PB isn't found, + * an internal flag is set, allowing this process to create a + * shared PB. Any other process calling this function with + * bLockOnFailure set, will receive the return code + * PVRSRV_ERROR_PROCESSING_BLOCKED, indicating that it needs + * to retry the function call. The internal flag is cleared + * when this process creates a shared PB. + * + * Note: You are responsible for freeing the list returned in + * pppsSharedPBDescSubKernelMemInfos + * via OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + * sizeof(PVRSRV_KERNEL_MEM_INFO *) + * * ui32SharedPBDescSubKernelMemInfosCount, + * ppsSharedPBDescSubKernelMemInfos, + * NULL); + * + * @param[in] psPerProc + * @param[in] hDevCookie + * @param[in] bLockOnError + * @param[in] ui32TotalPBSize + * @param[in] phSharedPBDesc + * @param[out] ppsSharedPBDescKernelMemInfo + * @param[out] ppsHWPBDescKernelMemInfo + * @param[out] pppsSharedPBDescSubKernelMemInfos A list of integral sub meminfos. + * @param[out] ui32SharedPBDescSubKernelMemInfosCount + * + * @return PVRSRV_ERROR + ********************************************************************************/ +/* disable QAC pointer level check for over 2 */ +/* PRQA S 5102++ */ IMG_IMPORT PVRSRV_ERROR SGXFindSharedPBDescKM(PVRSRV_PER_PROCESS_DATA *psPerProc, IMG_HANDLE hDevCookie, @@ -127,9 +185,58 @@ SGXFindSharedPBDescKM(PVRSRV_PER_PROCESS_DATA *psPerProc, PVRSRV_KERNEL_MEM_INFO ***pppsSharedPBDescSubKernelMemInfos, IMG_UINT32 *ui32SharedPBDescSubKernelMemInfosCount); +/*! + * ***************************************************************************** + * @brief Decrements the reference counter and frees all userspace resources + * associated with a SharedPBDesc. + * + * @param hSharedPBDesc + * + * @return PVRSRV_ERROR + ********************************************************************************/ IMG_IMPORT PVRSRV_ERROR SGXUnrefSharedPBDescKM(IMG_HANDLE hSharedPBDesc); +/*! + * ***************************************************************************** + * @brief Links a new SharedPBDesc into a kernel managed list that can + * then be queried by other clients. + * + * As a side affect this function also dissociates the SharedPBDesc + * from the calling process so that the memory won't be freed if the + * process dies/exits. (The kernel assumes responsability over the + * memory at the same time) + * + * As well as the psSharedPBDescKernelMemInfo you must also pass + * a complete list of other meminfos that are integral to the + * shared PB description. (Although the kernel doesn't have direct + * access to the shared PB desc it still needs to be able to + * clean up all the associated resources when it is no longer + * in use.) + * + * If the dissociation fails then all the memory associated with + * the psSharedPBDescKernelMemInfo and all entries in psKernelMemInfos + * will be freed by kernel services! Because of this, you are + * responsible for freeing the corresponding client meminfos _before_ + * calling SGXAddSharedPBDescKM. + * + * This function will return an error unless a succesful call to + * SGXFindSharedPBDesc, with bLockOnFailure set, has been made. + * + * @param psPerProc + * @param hDevCookie + * @param psSharedPBDescKernelMemInfo + * @param psHWPBDescKernelMemInfo + * @param psBlockKernelMemInfo + * @param ui32TotalPBSize The size of the associated parameter buffer + * @param ppsSharedPBDescSubKernelMemInfos A list of other meminfos integral to + * the shared PB description. + * @param ui32SharedPBDescSubKernelMemInfosCount The number of entires in + * psKernelMemInfos + * @param sHWPBDescDevVAddr The device virtual address of the HWPBDesc + * + * @return PVRSRV_ERROR + ********************************************************************************/ IMG_IMPORT PVRSRV_ERROR SGXAddSharedPBDescKM(PVRSRV_PER_PROCESS_DATA *psPerProc, IMG_HANDLE hDevCookie, @@ -144,6 +251,16 @@ SGXAddSharedPBDescKM(PVRSRV_PER_PROCESS_DATA *psPerProc, IMG_DEV_VIRTADDR sHWPBDescDevVAddr); +/*! + * ***************************************************************************** + * @brief Gets device information that is not intended to be passed + on beyond the srvclient libs. + * + * @param[in] hDevCookie + * @param[out] psSGXInternalDevInfo + * + * @return + ********************************************************************************/ IMG_IMPORT PVRSRV_ERROR SGXGetInternalDevInfoKM(IMG_HANDLE hDevCookie, #if defined (SUPPORT_SID_INTERFACE) @@ -156,5 +273,8 @@ SGXGetInternalDevInfoKM(IMG_HANDLE hDevCookie, } #endif -#endif +#endif /* __SGX_BRIDGE_KM_H__ */ +/****************************************************************************** + End of file (sgx_bridge_km.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/devices/sgx/sgxconfig.h b/sgx/services4/srvkm/devices/sgx/sgxconfig.h index dddc6f5..dc024bc 100644 --- a/sgx/services4/srvkm/devices/sgx/sgxconfig.h +++ b/sgx/services4/srvkm/devices/sgx/sgxconfig.h @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title device configuration +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #ifndef __SGXCONFIG_H__ #define __SGXCONFIG_H__ @@ -41,6 +57,14 @@ #define SGX_KERNEL_DATA_HEAP_OFFSET 0x00000000 #endif +#if !defined(ION_HEAP_SIZE) && defined(SUPPORT_ION) + /* Default the Ion heap to 16MB */ + #define ION_HEAP_SIZE 0x01000000 +#else + #define ION_HEAP_SIZE 0 +#endif + + #if SGX_FEATURE_ADDRESS_SPACE_SIZE == 32 #if defined(FIX_HW_BRN_31620) #if defined(SGX_FEATURE_2D_HARDWARE) @@ -51,10 +75,20 @@ #define SGX_GENERAL_HEAP_BASE 0x08000000 #define SGX_GENERAL_HEAP_SIZE (0xB8000000-0x00001000) - + /* + * For hybrid PB we have to split virtual PB range between the shared + * PB and percontext PB due to the fact we only have one heap config + * per device. + * If hybrid PB is enabled we split the space acording to HYBRID_SHARED_PB_SIZE. + * i.e. HYBRID_SHARED_PB_SIZE defines the size of the shared PB and the + * remainder is the size of the percontext PB. + * If hybrid PB is not enabled then we still create both heaps (helps keep + * the code clean) and define the size of the unused one to 0 + */ + #define SGX_3DPARAMETERS_HEAP_SIZE 0x10000000 - + /* By default we split the PB 50/50 */ #if !defined(HYBRID_SHARED_PB_SIZE) #define HYBRID_SHARED_PB_SIZE (SGX_3DPARAMETERS_HEAP_SIZE >> 1) #endif @@ -76,10 +110,10 @@ #endif #define SGX_SHARED_3DPARAMETERS_HEAP_BASE 0xC0000000 - + /* Size is defiend above */ #define SGX_PERCONTEXT_3DPARAMETERS_HEAP_BASE (SGX_SHARED_3DPARAMETERS_HEAP_BASE + SGX_SHARED_3DPARAMETERS_SIZE) - + /* Size is defiend above */ #define SGX_TADATA_HEAP_BASE 0xD0000000 #define SGX_TADATA_HEAP_SIZE (0x0D000000-0x00001000) @@ -99,21 +133,17 @@ #define SGX_KERNEL_DATA_HEAP_BASE (0xF0000000+SGX_KERNEL_DATA_HEAP_OFFSET) #define SGX_KERNEL_DATA_HEAP_SIZE (0x03000000-(0x00001000+SGX_KERNEL_DATA_HEAP_OFFSET)) - + /* Actual Pixel and Vertex shared heaps sizes may be reduced by + * override - see SGX_USE_CODE_SEGMENT_RANGE_BITS.*/ #define SGX_PIXELSHADER_HEAP_BASE 0xF4000000 #define SGX_PIXELSHADER_HEAP_SIZE (0x05000000-0x00001000) #define SGX_VERTEXSHADER_HEAP_BASE 0xFC000000 #define SGX_VERTEXSHADER_HEAP_SIZE (0x02000000-0x00001000) -#else +#else /* FIX_HW_BRN_31620 */ #if defined(SGX_FEATURE_2D_HARDWARE) #define SGX_2D_HEAP_BASE 0x00100000 #define SGX_2D_HEAP_SIZE (0x08000000-0x00100000-0x00001000) - #else - #if defined(FIX_HW_BRN_26915) - #define SGX_CGBUFFER_HEAP_BASE 0x00100000 - #define SGX_CGBUFFER_HEAP_SIZE (0x08000000-0x00100000-0x00001000) - #endif #endif #if defined(SUPPORT_SGX_GENERAL_MAPPING_HEAP) @@ -121,13 +151,51 @@ #define SGX_GENERAL_MAPPING_HEAP_SIZE (0x08000000-0x00001000) #endif - #define SGX_GENERAL_HEAP_BASE 0x10000000 - #define SGX_GENERAL_HEAP_SIZE (0xC2000000-0x00001000) + #if !defined(SUPPORT_MEMORY_TILING) + #if defined (SUPPORT_ION) + #define SGX_GENERAL_HEAP_BASE 0x10000000 + #define SGX_GENERAL_HEAP_SIZE (0xC2000000-ION_HEAP_SIZE-0x00001000) + + #define SGX_ION_HEAP_BASE (SGX_GENERAL_HEAP_BASE+SGX_GENERAL_HEAP_SIZE+0x00001000) + #define SGX_ION_HEAP_SIZE (ION_HEAP_SIZE-0x00001000) + #else + #define SGX_GENERAL_HEAP_BASE 0x10000000 + #define SGX_GENERAL_HEAP_SIZE (0xC2000000-0x00001000) + #endif + #else + #include <sgx_msvdx_defs.h> + /* Create heaps with memory tiling enabled. + * SGX HW limit is 10 heaps. + */ + /* Tiled heap space is taken from general heap */ + #define SGX_GENERAL_HEAP_BASE 0x10000000 + #define SGX_GENERAL_HEAP_SIZE (0xB5000000-0x00001000) + + #define SGX_VPB_TILED_HEAP_STRIDE TILING_TILE_STRIDE_2K + #define SGX_VPB_TILED_HEAP_BASE 0xC5000000 + #define SGX_VPB_TILED_HEAP_SIZE (0x0D000000-0x00001000) + + /* Check tiled heap base alignment */ + #if((SGX_VPB_TILED_HEAP_BASE & SGX_BIF_TILING_ADDR_INV_MASK) != 0) + #error "sgxconfig.h: SGX_VPB_TILED_HEAP has insufficient alignment" + #endif + + #endif /* SUPPORT_MEMORY_TILING */ + + /* + * For hybrid PB we have to split virtual PB range between the shared + * PB and percontext PB due to the fact we only have one heap config + * per device. + * If hybrid PB is enabled we split the space acording to HYBRID_SHARED_PB_SIZE. + * i.e. HYBRID_SHARED_PB_SIZE defines the size of the shared PB and the + * remainder is the size of the percontext PB. + * If hybrid PB is not enabled then we still create both heaps (helps keep + * the code clean) and define the size of the unused one to 0 + */ - #define SGX_3DPARAMETERS_HEAP_SIZE 0x10000000 - + /* By default we split the PB 50/50 */ #if !defined(HYBRID_SHARED_PB_SIZE) #define HYBRID_SHARED_PB_SIZE (SGX_3DPARAMETERS_HEAP_SIZE >> 1) #endif @@ -149,10 +217,10 @@ #endif #define SGX_SHARED_3DPARAMETERS_HEAP_BASE 0xD2000000 - + /* Size is defiend above */ #define SGX_PERCONTEXT_3DPARAMETERS_HEAP_BASE (SGX_SHARED_3DPARAMETERS_HEAP_BASE + SGX_SHARED_3DPARAMETERS_SIZE) - + /* Size is defiend above */ #define SGX_TADATA_HEAP_BASE 0xE2000000 #define SGX_TADATA_HEAP_SIZE (0x0D000000-0x00001000) @@ -172,16 +240,17 @@ #define SGX_KERNEL_DATA_HEAP_BASE (0xF4000000+SGX_KERNEL_DATA_HEAP_OFFSET) #define SGX_KERNEL_DATA_HEAP_SIZE (0x05000000-(0x00001000+SGX_KERNEL_DATA_HEAP_OFFSET)) - + /* Actual Pixel and Vertex shared heaps sizes may be reduced by + * override - see SGX_USE_CODE_SEGMENT_RANGE_BITS.*/ #define SGX_PIXELSHADER_HEAP_BASE 0xF9000000 #define SGX_PIXELSHADER_HEAP_SIZE (0x05000000-0x00001000) #define SGX_VERTEXSHADER_HEAP_BASE 0xFE000000 #define SGX_VERTEXSHADER_HEAP_SIZE (0x02000000-0x00001000) -#endif - +#endif /* FIX_HW_BRN_31620 */ + /* signal we've identified the core by the build */ #define SGX_CORE_IDENTIFIED -#endif +#endif /* SGX_FEATURE_ADDRESS_SPACE_SIZE == 32 */ #if SGX_FEATURE_ADDRESS_SPACE_SIZE == 28 @@ -190,18 +259,38 @@ #define SGX_GENERAL_MAPPING_HEAP_SIZE (0x01800000-0x00001000-0x00001000) #define SGX_GENERAL_HEAP_BASE 0x01800000 -// #define SGX_GENERAL_HEAP_SIZE (0x07000000-0x00001000) - #define SGX_GENERAL_HEAP_SIZE (0x0A000000-0x00001000) + #define SGX_GENERAL_HEAP_SIZE (0x07000000-ION_HEAP_SIZE-0x00001000) #else #define SGX_GENERAL_HEAP_BASE 0x00001000 -// #define SGX_GENERAL_HEAP_SIZE (0x08800000-0x00001000-0x00001000) - #define SGX_GENERAL_HEAP_SIZE (0x0B800000-0x00001000-0x00001000) +#if defined(SUPPORT_LARGE_GENERAL_HEAP) + #define SGX_GENERAL_HEAP_SIZE (0x0B800000-ION_HEAP_SIZE-0x00001000-0x00001000) +#else + #define SGX_GENERAL_HEAP_SIZE (0x08800000-ION_HEAP_SIZE-0x00001000-0x00001000) #endif - -// #define SGX_3DPARAMETERS_HEAP_SIZE 0x04000000 +#endif + +#if defined(SUPPORT_ION) + #define SGX_ION_HEAP_BASE (SGX_GENERAL_HEAP_BASE+SGX_GENERAL_HEAP_SIZE+0x00001000) + #define SGX_ION_HEAP_SIZE (ION_HEAP_SIZE-0x00001000) +#endif + /* + * For hybrid PB we have to split virtual PB range between the shared + * PB and percontext PB due to the fact we only have one heap config + * per device. + * If hybrid PB is enabled we split the space acording to HYBRID_SHARED_PB_SIZE. + * i.e. HYBRID_SHARED_PB_SIZE defines the size of the shared PB and the + * remainder is the size of the percontext PB. + * If hybrid PB is not enabled then we still create both heaps (helps keep + * the code clean) and define the size of the unused one to 0 + */ +#if defined(SUPPORT_LARGE_GENERAL_HEAP) #define SGX_3DPARAMETERS_HEAP_SIZE 0x01000000 - +#else + #define SGX_3DPARAMETERS_HEAP_SIZE 0x04000000 +#endif + + /* By default we split the PB 50/50 */ #if !defined(HYBRID_SHARED_PB_SIZE) #define HYBRID_SHARED_PB_SIZE (SGX_3DPARAMETERS_HEAP_SIZE >> 1) #endif @@ -222,11 +311,16 @@ #endif #endif -// #define SGX_SHARED_3DPARAMETERS_HEAP_BASE 0x08800000 +#if defined(SUPPORT_LARGE_GENERAL_HEAP) #define SGX_SHARED_3DPARAMETERS_HEAP_BASE 0x0B800000 +#else + #define SGX_SHARED_3DPARAMETERS_HEAP_BASE 0x08800000 +#endif + + /* Size is defined above */ #define SGX_PERCONTEXT_3DPARAMETERS_HEAP_BASE (SGX_SHARED_3DPARAMETERS_HEAP_BASE + SGX_SHARED_3DPARAMETERS_SIZE) - + /* Size is defined above */ #define SGX_TADATA_HEAP_BASE 0x0C800000 #define SGX_TADATA_HEAP_SIZE (0x01000000-0x00001000) @@ -252,15 +346,20 @@ #define SGX_VERTEXSHADER_HEAP_BASE 0x0FC00000 #define SGX_VERTEXSHADER_HEAP_SIZE (0x00200000-0x00001000) - + /* signal we've identified the core by the build */ #define SGX_CORE_IDENTIFIED -#endif +#endif /* SGX_FEATURE_ADDRESS_SPACE_SIZE == 28 */ #if !defined(SGX_CORE_IDENTIFIED) #error "sgxconfig.h: ERROR: unspecified SGX Core version" #endif +/********************************************************************************* + * + * SGX_PDSPIXEL_CODEDATA_HEAP_BASE + 64MB range must include PDSVERTEX_CODEDATA and KERNEL_CODE heaps + * + ********************************************************************************/ #if !defined (SGX_FEATURE_EDM_VERTEX_PDSADDR_FULL_RANGE) #if ((SGX_KERNEL_CODE_HEAP_BASE + SGX_KERNEL_CODE_HEAP_SIZE - SGX_PDSPIXEL_CODEDATA_HEAP_BASE) > 0x4000000) #error "sgxconfig.h: ERROR: SGX_KERNEL_CODE_HEAP_BASE out of range of SGX_PDSPIXEL_CODEDATA_HEAP_BASE" @@ -271,18 +370,33 @@ #endif #endif +/********************************************************************************* + * + * The General Mapping heap must be within the 2D requestor range of the 2D heap base + * + ********************************************************************************/ #if defined(SGX_FEATURE_2D_HARDWARE) && defined(SUPPORT_SGX_GENERAL_MAPPING_HEAP) #if ((SGX_GENERAL_MAPPING_HEAP_BASE + SGX_GENERAL_MAPPING_HEAP_SIZE - SGX_2D_HEAP_BASE) >= EUR_CR_BIF_TWOD_REQ_BASE_ADDR_MASK) #error "sgxconfig.h: ERROR: SGX_GENERAL_MAPPING_HEAP inaccessable by 2D requestor" #endif #endif +/********************************************************************************* + * + * The kernel code heap base must be aligned to a USSE code page + * + ********************************************************************************/ #if defined (EURASIA_USE_CODE_PAGE_SIZE) #if ((SGX_KERNEL_CODE_HEAP_BASE & (EURASIA_USE_CODE_PAGE_SIZE - 1)) != 0) #error "sgxconfig.h: ERROR: Kernel code heap base misalignment" #endif #endif +/********************************************************************************* + * + * Heap overlap check + * + ********************************************************************************/ #if defined(SGX_FEATURE_2D_HARDWARE) #if defined(SUPPORT_SGX_GENERAL_MAPPING_HEAP) #if ((SGX_2D_HEAP_BASE + SGX_2D_HEAP_SIZE) >= SGX_GENERAL_MAPPING_HEAP_BASE) @@ -293,18 +407,6 @@ #error "sgxconfig.h: ERROR: SGX_2D_HEAP overlaps SGX_GENERAL_HEAP_BASE" #endif #endif -#else - #if defined(FIX_HW_BRN_26915) - #if defined(SUPPORT_SGX_GENERAL_MAPPING_HEAP) - #if ((SGX_CGBUFFER_HEAP_BASE + SGX_CGBUFFER_HEAP_SIZE) >= SGX_GENERAL_MAPPING_HEAP_BASE) - #error "sgxconfig.h: ERROR: SGX_CGBUFFER_HEAP overlaps SGX_GENERAL_MAPPING_HEAP" - #endif - #else - #if ((SGX_CGBUFFER_HEAP_BASE + SGX_CGBUFFER_HEAP_SIZE) >= SGX_GENERAL_HEAP_BASE) - #error "sgxconfig.h: ERROR: SGX_CGBUFFER_HEAP overlaps SGX_GENERAL_HEAP_BASE" - #endif - #endif - #endif #endif #if defined(SUPPORT_SGX_GENERAL_MAPPING_HEAP) @@ -319,8 +421,22 @@ #endif #endif -#if ((SGX_GENERAL_HEAP_BASE + SGX_GENERAL_HEAP_SIZE) >= SGX_SHARED_3DPARAMETERS_HEAP_BASE) - #error "sgxconfig.h: ERROR: SGX_GENERAL_HEAP overlaps SGX_3DPARAMETERS_HEAP" +#if defined(SUPPORT_MEMORY_TILING) + #if ((SGX_GENERAL_HEAP_BASE + SGX_GENERAL_HEAP_SIZE) >= SGX_VPB_TILED_HEAP_BASE) + #error "sgxconfig.h: ERROR: SGX_GENERAL_HEAP overlaps SGX_VPB_TILED_HEAP" + #endif + #if ((SGX_VPB_TILED_HEAP_BASE + SGX_VPB_TILED_HEAP_SIZE) >= SGX_SHARED_3DPARAMETERS_HEAP_BASE) + #error "sgxconfig.h: ERROR: SGX_VPB_TILED_HEAP overlaps SGX_3DPARAMETERS_HEAP" + #endif +#else + #if defined(SUPPORT_ION) + #if ((SGX_ION_HEAP_BASE + SGX_ION_HEAP_SIZE) >= SGX_SHARED_3DPARAMETERS_HEAP_BASE) + #error "sgxconfig.h: ERROR: SGX_ION_HEAP overlaps SGX_3DPARAMETERS_HEAP" + #endif + #endif + #if ((SGX_GENERAL_HEAP_BASE + SGX_GENERAL_HEAP_SIZE) >= SGX_SHARED_3DPARAMETERS_HEAP_BASE) + #error "sgxconfig.h: ERROR: SGX_GENERAL_HEAP overlaps SGX_3DPARAMETERS_HEAP" + #endif #endif #if (((SGX_PERCONTEXT_3DPARAMETERS_HEAP_BASE + SGX_PERCONTEXT_3DPARAMETERS_HEAP_SIZE) >= SGX_TADATA_HEAP_BASE) && (SGX_PERCONTEXT_3DPARAMETERS_HEAP_SIZE > 0)) @@ -359,5 +475,8 @@ #error "sgxconfig.h: ERROR: SGX_VERTEXSHADER_HEAP_BASE size cause wraparound" #endif -#endif +#endif /* __SGXCONFIG_H__ */ +/***************************************************************************** + End of file (sgxconfig.h) +*****************************************************************************/ diff --git a/sgx/services4/srvkm/devices/sgx/sgxinfokm.h b/sgx/services4/srvkm/devices/sgx/sgxinfokm.h index 55bc9e4..af00041 100644 --- a/sgx/services4/srvkm/devices/sgx/sgxinfokm.h +++ b/sgx/services4/srvkm/devices/sgx/sgxinfokm.h @@ -1,29 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ - +/*************************************************************************/ /*! +@Title SGX kernel services structues/functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Structures and inline functions for KM services component +@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. + +*/ /**************************************************************************/ #ifndef __SGXINFOKM_H__ #define __SGXINFOKM_H__ @@ -38,11 +54,23 @@ extern "C" { #endif +/****************************************************************************/ +/* kernel only defines: */ +/****************************************************************************/ +/* SGXDeviceMap Flag defines */ #define SGX_HOSTPORT_PRESENT 0x00000001UL +/* + SGX PDUMP register bank name (prefix) +*/ #define SGX_PDUMPREG_NAME "SGXREG" +/****************************************************************************/ +/* kernel only structures: */ +/****************************************************************************/ + +/*Forward declaration*/ typedef struct _PVRSRV_STUB_PBDESC_ PVRSRV_STUB_PBDESC; @@ -58,106 +86,106 @@ typedef struct _PVRSRV_SGXDEV_INFO_ IMG_UINT32 ui32CoreConfig; IMG_UINT32 ui32CoreFlags; - + /* Kernel mode linear address of device registers */ IMG_PVOID pvRegsBaseKM; #if defined(SGX_FEATURE_HOST_PORT) - + /* Kernel mode linear address of host port */ IMG_PVOID pvHostPortBaseKM; - + /* HP size */ IMG_UINT32 ui32HPSize; - + /* HP syspaddr */ IMG_SYS_PHYADDR sHPSysPAddr; #endif - + /* FIXME: The alloc for this should go through OSAllocMem in future */ IMG_HANDLE hRegMapping; - + /* System physical address of device registers*/ IMG_SYS_PHYADDR sRegsPhysBase; - + /* Register region size in bytes */ IMG_UINT32 ui32RegSize; #if defined(SUPPORT_EXTERNAL_SYSTEM_CACHE) - + /* external system cache register region size in bytes */ IMG_UINT32 ui32ExtSysCacheRegsSize; - + /* external system cache register device relative physical address */ IMG_DEV_PHYADDR sExtSysCacheRegsDevPBase; - + /* ptr to page table */ IMG_UINT32 *pui32ExtSystemCacheRegsPT; - + /* handle to page table alloc/mapping */ IMG_HANDLE hExtSystemCacheRegsPTPageOSMemHandle; - + /* sys phys addr of PT */ IMG_SYS_PHYADDR sExtSystemCacheRegsPTSysPAddr; #endif - + /* SGX clock speed */ IMG_UINT32 ui32CoreClockSpeed; IMG_UINT32 ui32uKernelTimerClock; + IMG_BOOL bSGXIdle; PVRSRV_STUB_PBDESC *psStubPBDescListKM; - + /* kernel memory context info */ IMG_DEV_PHYADDR sKernelPDDevPAddr; + IMG_UINT32 ui32HeapCount; /*!< heap count */ IMG_VOID *pvDeviceMemoryHeap; - PPVRSRV_KERNEL_MEM_INFO psKernelCCBMemInfo; - PVRSRV_SGX_KERNEL_CCB *psKernelCCB; - PPVRSRV_SGX_CCB_INFO psKernelCCBInfo; - PPVRSRV_KERNEL_MEM_INFO psKernelCCBCtlMemInfo; - PVRSRV_SGX_CCB_CTL *psKernelCCBCtl; - PPVRSRV_KERNEL_MEM_INFO psKernelCCBEventKickerMemInfo; - IMG_UINT32 *pui32KernelCCBEventKicker; + PPVRSRV_KERNEL_MEM_INFO psKernelCCBMemInfo; /*!< meminfo for CCB in device accessible memory */ + PVRSRV_SGX_KERNEL_CCB *psKernelCCB; /*!< kernel mode linear address of CCB in device accessible memory */ + PPVRSRV_SGX_CCB_INFO psKernelCCBInfo; /*!< CCB information structure */ + PPVRSRV_KERNEL_MEM_INFO psKernelCCBCtlMemInfo; /*!< meminfo for CCB control in device accessible memory */ + PVRSRV_SGX_CCB_CTL *psKernelCCBCtl; /*!< kernel mode linear address of CCB control in device accessible memory */ + PPVRSRV_KERNEL_MEM_INFO psKernelCCBEventKickerMemInfo; /*!< meminfo for kernel CCB event kicker */ + IMG_UINT32 *pui32KernelCCBEventKicker; /*!< kernel mode linear address of kernel CCB event kicker */ #if defined(PDUMP) - IMG_UINT32 ui32KernelCCBEventKickerDumpVal; -#endif - PVRSRV_KERNEL_MEM_INFO *psKernelSGXMiscMemInfo; - IMG_UINT32 aui32HostKickAddr[SGXMKIF_CMD_MAX]; + IMG_UINT32 ui32KernelCCBEventKickerDumpVal; /*!< pdump copy of the kernel CCB event kicker */ +#endif /* PDUMP */ + PVRSRV_KERNEL_MEM_INFO *psKernelSGXMiscMemInfo; /*!< kernel mode linear address of SGX misc info buffer */ + IMG_UINT32 aui32HostKickAddr[SGXMKIF_CMD_MAX]; /*!< ukernel host kick offests */ #if defined(SGX_SUPPORT_HWPROFILING) PPVRSRV_KERNEL_MEM_INFO psKernelHWProfilingMemInfo; #endif - PPVRSRV_KERNEL_MEM_INFO psKernelHWPerfCBMemInfo; - PPVRSRV_KERNEL_MEM_INFO psKernelTASigBufferMemInfo; - PPVRSRV_KERNEL_MEM_INFO psKernel3DSigBufferMemInfo; + PPVRSRV_KERNEL_MEM_INFO psKernelHWPerfCBMemInfo; /*!< Meminfo for hardware performace circular buffer */ + PPVRSRV_KERNEL_MEM_INFO psKernelTASigBufferMemInfo; /*!< Meminfo for TA signature buffer */ + PPVRSRV_KERNEL_MEM_INFO psKernel3DSigBufferMemInfo; /*!< Meminfo for 3D signature buffer */ #if defined(FIX_HW_BRN_29702) - PPVRSRV_KERNEL_MEM_INFO psKernelCFIMemInfo; + PPVRSRV_KERNEL_MEM_INFO psKernelCFIMemInfo; /*!< Meminfo for cfi */ #endif #if defined(FIX_HW_BRN_29823) - PPVRSRV_KERNEL_MEM_INFO psKernelDummyTermStreamMemInfo; + PPVRSRV_KERNEL_MEM_INFO psKernelDummyTermStreamMemInfo; /*!< Meminfo for dummy terminate stream */ #endif -#if defined(SGX_FEATURE_VDM_CONTEXT_SWITCH) && defined(FIX_HW_BRN_31425) - PPVRSRV_KERNEL_MEM_INFO psKernelVDMSnapShotBufferMemInfo; - PPVRSRV_KERNEL_MEM_INFO psKernelVDMCtrlStreamBufferMemInfo; +#if defined(SGX_FEATURE_VDM_CONTEXT_SWITCH) && defined(FIX_HW_BRN_31559) + PPVRSRV_KERNEL_MEM_INFO psKernelVDMSnapShotBufferMemInfo; /*!< Meminfo for dummy snapshot buffer */ + PPVRSRV_KERNEL_MEM_INFO psKernelVDMCtrlStreamBufferMemInfo; /*!< Meminfo for dummy control stream */ #endif #if defined(SGX_FEATURE_VDM_CONTEXT_SWITCH) && \ defined(FIX_HW_BRN_33657) && defined(SUPPORT_SECURE_33657_FIX) - PPVRSRV_KERNEL_MEM_INFO psKernelVDMStateUpdateBufferMemInfo; + PPVRSRV_KERNEL_MEM_INFO psKernelVDMStateUpdateBufferMemInfo; /*!< Meminfo for state update buffer */ #endif #if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) - PPVRSRV_KERNEL_MEM_INFO psKernelEDMStatusBufferMemInfo; + PPVRSRV_KERNEL_MEM_INFO psKernelEDMStatusBufferMemInfo; /*!< Meminfo for EDM status buffer */ #endif -#if defined(SGX_FEATURE_OVERLAPPED_SPM) - PPVRSRV_KERNEL_MEM_INFO psKernelTmpRgnHeaderMemInfo; -#endif - + /* Client reference count */ IMG_UINT32 ui32ClientRefCount; - + /* cache control word for micro kernel cache flush/invalidates */ IMG_UINT32 ui32CacheControl; - + /* client-side build options */ IMG_UINT32 ui32ClientBuildOptions; - + /* client-side microkernel structure sizes */ SGX_MISCINFO_STRUCT_SIZES sSGXStructSizes; - - - + /* + if we don't preallocate the pagetables we must + insert newly allocated page tables dynamically + */ IMG_VOID *pvMMUContextList; - + /* Copy of registry ForcePTOff entry */ IMG_BOOL bForcePTOff; IMG_UINT32 ui32EDMTaskReg0; @@ -172,10 +200,10 @@ typedef struct _PVRSRV_SGXDEV_INFO_ IMG_UINT32 ui32MasterClkGateStatusMask; IMG_UINT32 ui32MasterClkGateStatus2Reg; IMG_UINT32 ui32MasterClkGateStatus2Mask; -#endif +#endif /* SGX_FEATURE_MP */ SGX_INIT_SCRIPTS sScripts; - + /* Members associated with dummy PD needed for BIF reset */ IMG_HANDLE hBIFResetPDOSMemHandle; IMG_DEV_PHYADDR sBIFResetPDDevPAddr; IMG_DEV_PHYADDR sBIFResetPTDevPAddr; @@ -183,32 +211,22 @@ typedef struct _PVRSRV_SGXDEV_INFO_ IMG_UINT32 *pui32BIFResetPD; IMG_UINT32 *pui32BIFResetPT; -#if defined(FIX_HW_BRN_22997) && defined(FIX_HW_BRN_23030) && defined(SGX_FEATURE_HOST_PORT) - - IMG_HANDLE hBRN22997PTPageOSMemHandle; - IMG_HANDLE hBRN22997PDPageOSMemHandle; - IMG_DEV_PHYADDR sBRN22997PTDevPAddr; - IMG_DEV_PHYADDR sBRN22997PDDevPAddr; - IMG_UINT32 *pui32BRN22997PT; - IMG_UINT32 *pui32BRN22997PD; - IMG_SYS_PHYADDR sBRN22997SysPAddr; -#endif #if defined(SUPPORT_HW_RECOVERY) - + /* Timeout callback handle */ IMG_HANDLE hTimer; - + /* HW recovery Time stamp */ IMG_UINT32 ui32TimeStamp; #endif - + /* Number of SGX resets */ IMG_UINT32 ui32NumResets; - + /* host control */ PVRSRV_KERNEL_MEM_INFO *psKernelSGXHostCtlMemInfo; SGXMKIF_HOST_CTL *psSGXHostCtl; - + /* TA/3D control */ PVRSRV_KERNEL_MEM_INFO *psKernelSGXTA3DCtlMemInfo; #if defined(FIX_HW_BRN_31272) || defined(FIX_HW_BRN_31780) || defined(FIX_HW_BRN_33920) @@ -217,7 +235,7 @@ typedef struct _PVRSRV_SGXDEV_INFO_ IMG_UINT32 ui32Flags; - + /* memory tiling range usage */ IMG_UINT32 ui32MemTilingUsage; #if defined(PDUMP) @@ -225,7 +243,7 @@ typedef struct _PVRSRV_SGXDEV_INFO_ #endif #if defined(SUPPORT_SGX_MMU_DUMMY_PAGE) - + /* SGX MMU dummy page details */ IMG_VOID *pvDummyPTPageCpuVAddr; IMG_DEV_PHYADDR sDummyPTDevPAddr; IMG_HANDLE hDummyPTPageOSMemHandle; @@ -239,12 +257,12 @@ typedef struct _PVRSRV_SGXDEV_INFO_ IMG_UINT32 asSGXDevData[SGX_MAX_DEV_DATA]; #if defined(FIX_HW_BRN_31620) - + /* Dummy page refs */ IMG_VOID *pvBRN31620DummyPageCpuVAddr; IMG_HANDLE hBRN31620DummyPageOSMemHandle; IMG_DEV_PHYADDR sBRN31620DummyPageDevPAddr; - + /* Dummy PT refs */ IMG_VOID *pvBRN31620DummyPTCpuVAddr; IMG_HANDLE hBRN31620DummyPTOSMemHandle; IMG_DEV_PHYADDR sBRN31620DummyPTDevPAddr; @@ -264,11 +282,13 @@ typedef struct _SGX_TIMING_INFORMATION_ IMG_UINT32 ui32uKernelFreq; } SGX_TIMING_INFORMATION; +/* FIXME Rename this structure to sg more generalised as it's been extended*/ +/* SGX device map */ typedef struct _SGX_DEVICE_MAP_ { IMG_UINT32 ui32Flags; - + /* Registers */ IMG_SYS_PHYADDR sRegsSysPBase; IMG_CPU_PHYADDR sRegsCpuPBase; IMG_CPU_VIRTADDR pvRegsCpuVBase; @@ -280,7 +300,7 @@ typedef struct _SGX_DEVICE_MAP_ IMG_UINT32 ui32HPSize; #endif - + /* Local Device Memory Region: (if present) */ IMG_SYS_PHYADDR sLocalMemSysPBase; IMG_DEV_PHYADDR sLocalMemDevPBase; IMG_CPU_PHYADDR sLocalMemCpuPBase; @@ -291,15 +311,15 @@ typedef struct _SGX_DEVICE_MAP_ IMG_DEV_PHYADDR sExtSysCacheRegsDevPBase; #endif - + /* device interrupt IRQ */ IMG_UINT32 ui32IRQ; #if !defined(SGX_DYNAMIC_TIMING_INFO) - + /* timing information*/ SGX_TIMING_INFORMATION sTimingInfo; #endif #if defined(PDUMP) - + /* pdump memory region name */ IMG_CHAR *pszPDumpDevName; #endif } SGX_DEVICE_MAP; @@ -321,15 +341,19 @@ struct _PVRSRV_STUB_PBDESC_ PVRSRV_STUB_PBDESC **ppsThis; }; +/*! + ****************************************************************************** + * CCB control structure for SGX + *****************************************************************************/ typedef struct _PVRSRV_SGX_CCB_INFO_ { - PVRSRV_KERNEL_MEM_INFO *psCCBMemInfo; - PVRSRV_KERNEL_MEM_INFO *psCCBCtlMemInfo; - SGXMKIF_COMMAND *psCommands; - IMG_UINT32 *pui32WriteOffset; - volatile IMG_UINT32 *pui32ReadOffset; + PVRSRV_KERNEL_MEM_INFO *psCCBMemInfo; /*!< meminfo for CCB in device accessible memory */ + PVRSRV_KERNEL_MEM_INFO *psCCBCtlMemInfo; /*!< meminfo for CCB control in device accessible memory */ + SGXMKIF_COMMAND *psCommands; /*!< linear address of the array of commands */ + IMG_UINT32 *pui32WriteOffset; /*!< linear address of the write offset into array of commands */ + volatile IMG_UINT32 *pui32ReadOffset; /*!< linear address of the read offset into array of commands */ #if defined(PDUMP) - IMG_UINT32 ui32CCBDumpWOff; + IMG_UINT32 ui32CCBDumpWOff; /*!< for pdumping */ #endif } PVRSRV_SGX_CCB_INFO; @@ -371,9 +395,6 @@ typedef struct _SGX_BRIDGE_INIT_INFO_KM_ #if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) IMG_HANDLE hKernelEDMStatusBufferMemInfo; #endif -#if defined(SGX_FEATURE_OVERLAPPED_SPM) - IMG_HANDLE hKernelTmpRgnHeaderMemInfo; -#endif IMG_UINT32 ui32EDMTaskReg0; IMG_UINT32 ui32EDMTaskReg1; @@ -381,7 +402,11 @@ typedef struct _SGX_BRIDGE_INIT_INFO_KM_ IMG_UINT32 ui32ClkGateStatusReg; IMG_UINT32 ui32ClkGateStatusMask; #if defined(SGX_FEATURE_MP) -#endif +// IMG_UINT32 ui32MasterClkGateStatusReg; +// IMG_UINT32 ui32MasterClkGateStatusMask; +// IMG_UINT32 ui32MasterClkGateStatus2Reg; +// IMG_UINT32 ui32MasterClkGateStatus2Mask; +#endif /* SGX_FEATURE_MP */ IMG_UINT32 ui32CacheControl; @@ -406,7 +431,7 @@ typedef struct _SGX_CCB_KICK_KM_ IMG_UINT32 ui32NumDstSyncObjects; IMG_HANDLE hKernelHWSyncListMemInfo; - + /* DST syncs */ IMG_HANDLE *pahDstSyncHandles; IMG_UINT32 ui32NumTAStatusVals; @@ -425,11 +450,11 @@ typedef struct _SGX_CCB_KICK_KM_ IMG_BOOL bTerminateOrAbort; #endif - + /* CCB offset of data structure associated with this kick */ IMG_UINT32 ui32CCBOffset; #if defined(SUPPORT_SGX_GENERALISED_SYNCOBJECTS) - + /* SRC and DST syncs */ IMG_UINT32 ui32NumTASrcSyncs; IMG_HANDLE ahTASrcKernelSyncInfo[SGX_MAX_TA_SRC_SYNCS]; IMG_UINT32 ui32NumTADstSyncs; @@ -437,12 +462,12 @@ typedef struct _SGX_CCB_KICK_KM_ IMG_UINT32 ui32Num3DSrcSyncs; IMG_HANDLE ah3DSrcKernelSyncInfo[SGX_MAX_3D_SRC_SYNCS]; #else - + /* SRC syncs */ IMG_UINT32 ui32NumSrcSyncs; - IMG_HANDLE ahSrcKernelSyncInfo[SGX_MAX_SRC_SYNCS]; + IMG_HANDLE ahSrcKernelSyncInfo[SGX_MAX_SRC_SYNCS_TA]; #endif - + /* TA/3D dependency data */ IMG_BOOL bTADependency; IMG_HANDLE hTA3DSyncInfo; @@ -493,13 +518,13 @@ typedef struct _PVRSRV_2D_SGX_KICK_KM_ IMG_UINT32 ui32NumSrcSync; IMG_HANDLE ahSrcSyncInfo[SGX_MAX_2D_SRC_SYNC_OPS]; - + /* need to be able to check reads and writes on dest, and update writes */ IMG_HANDLE hDstSyncInfo; - + /* need to be able to check reads and writes on TA ops, and update writes */ IMG_HANDLE hTASyncInfo; - + /* need to be able to check reads and writes on 2D ops, and update writes */ IMG_HANDLE h3DSyncInfo; IMG_UINT32 ui32PDumpFlags; @@ -507,9 +532,12 @@ typedef struct _PVRSRV_2D_SGX_KICK_KM_ IMG_UINT32 ui32CCBDumpWOff; #endif } PVRSRV_2D_SGX_KICK_KM, *PPVRSRV_2D_SGX_KICK_KM; -#endif -#endif +#endif /* defined(SGX_FEATURE_2D_HARDWARE) */ +#endif /* #if defined(TRANSFER_QUEUE) */ +/****************************************************************************/ +/* kernel only functions prototypes */ +/****************************************************************************/ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode); IMG_VOID SGXOSTimer(IMG_VOID *pvData); @@ -543,12 +571,18 @@ PVRSRV_ERROR SGXPostClockSpeedChange(IMG_HANDLE hDevHandle, IMG_VOID SGXPanic(PVRSRV_SGXDEV_INFO *psDevInfo); +IMG_VOID SGXDumpDebugInfo (PVRSRV_SGXDEV_INFO *psDevInfo, + IMG_BOOL bDumpSGXRegs); + PVRSRV_ERROR SGXDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode); #if defined(SGX_DYNAMIC_TIMING_INFO) IMG_VOID SysGetSGXTimingInformation(SGX_TIMING_INFORMATION *psSGXTimingInfo); #endif +/****************************************************************************/ +/* kernel only functions: */ +/****************************************************************************/ #if defined(NO_HARDWARE) static INLINE IMG_VOID NoHardwareGenerateEvent(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32StatusRegister, @@ -570,5 +604,8 @@ static INLINE IMG_VOID NoHardwareGenerateEvent(PVRSRV_SGXDEV_INFO *psDevInfo, } #endif -#endif +#endif /* __SGXINFOKM_H__ */ +/***************************************************************************** + End of file (sgxinfokm.h) +*****************************************************************************/ diff --git a/sgx/services4/srvkm/devices/sgx/sgxinit.c b/sgx/services4/srvkm/devices/sgx/sgxinit.c index 0b7d074..b794321 100644 --- a/sgx/services4/srvkm/devices/sgx/sgxinit.c +++ b/sgx/services4/srvkm/devices/sgx/sgxinit.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Device specific initialisation routines +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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> @@ -52,9 +68,26 @@ #include "lists.h" #include "srvkm.h" #include "ttrace.h" -#define VAR(x) #x - +#if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) + +static const IMG_CHAR *SGXUKernelStatusString(IMG_UINT32 code) +{ + switch(code) + { +#define MKTC_ST(x) \ + case x: \ + return #x; +#include "sgx_ukernel_status_codes.h" + default: + return "(Unknown)"; + } +} + +#endif /* defined(PVRSRV_USSE_EDM_STATUS_DEBUG) */ + +#define VAR(x) #x +/* PRQA S 0881 11 */ /* ignore 'order of evaluation' warning */ #define CHECK_SIZE(NAME) \ { \ if (psSGXStructSizes->ui32Sizeof_##NAME != psDevInfo->sSGXStructSizes.ui32Sizeof_##NAME) \ @@ -76,20 +109,37 @@ static PVRSRV_ERROR SGXGetMiscInfoUkernel(PVRSRV_SGXDEV_INFO *psDevInfo, PVRSRV_DEVICE_NODE *psDeviceNode, IMG_HANDLE hDevMemContext); -static IMG_VOID SGXDumpDebugInfo (PVRSRV_SGXDEV_INFO *psDevInfo, - IMG_BOOL bDumpSGXRegs); - #if defined(PDUMP) static PVRSRV_ERROR SGXResetPDump(PVRSRV_DEVICE_NODE *psDeviceNode); #endif +/*! +******************************************************************************* + + @Function SGXCommandComplete + + @Description + + SGX command complete handler + + @Input psDeviceNode - SGX device node + + @Return none + +******************************************************************************/ static IMG_VOID SGXCommandComplete(PVRSRV_DEVICE_NODE *psDeviceNode) { #if defined(OS_SUPPORTS_IN_LISR) if (OSInLISR(psDeviceNode->psSysData)) { - + /* + * We shouldn't call SGXScheduleProcessQueuesKM in an + * LISR, as it may attempt to power up SGX. + * We assume that the LISR will schedule the MISR, which + * will test the following flag, and call + * SGXScheduleProcessQueuesKM if the flag is set. + */ psDeviceNode->bReProcessDeviceCommandComplete = IMG_TRUE; } else @@ -101,18 +151,47 @@ static IMG_VOID SGXCommandComplete(PVRSRV_DEVICE_NODE *psDeviceNode) #endif } +/*! +******************************************************************************* + + @Function DeinitDevInfo + + @Description + + Deinits DevInfo + + @Input none + + @Return none + +******************************************************************************/ static IMG_UINT32 DeinitDevInfo(PVRSRV_SGXDEV_INFO *psDevInfo) { if (psDevInfo->psKernelCCBInfo != IMG_NULL) { - - + /* + Free CCB info. + */ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_SGX_CCB_INFO), psDevInfo->psKernelCCBInfo, IMG_NULL); } return PVRSRV_OK; } +/*! +******************************************************************************* + + @Function InitDevInfo + + @Description + + Loads DevInfo + + @Input psDeviceNode + + @Return PVRSRV_ERROR + +******************************************************************************/ static PVRSRV_ERROR InitDevInfo(PVRSRV_PER_PROCESS_DATA *psPerProc, PVRSRV_DEVICE_NODE *psDeviceNode, #if defined (SUPPORT_SID_INTERFACE) @@ -163,7 +242,7 @@ static PVRSRV_ERROR InitDevInfo(PVRSRV_PER_PROCESS_DATA *psPerProc, #if defined(FIX_HW_BRN_29823) psDevInfo->psKernelDummyTermStreamMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelDummyTermStreamMemInfo; #endif -#if defined(SGX_FEATURE_VDM_CONTEXT_SWITCH) && defined(FIX_HW_BRN_31425) +#if defined(SGX_FEATURE_VDM_CONTEXT_SWITCH) && defined(FIX_HW_BRN_31559) psDevInfo->psKernelVDMSnapShotBufferMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelVDMSnapShotBufferMemInfo; psDevInfo->psKernelVDMCtrlStreamBufferMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelVDMCtrlStreamBufferMemInfo; #endif @@ -174,20 +253,19 @@ static PVRSRV_ERROR InitDevInfo(PVRSRV_PER_PROCESS_DATA *psPerProc, #if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) psDevInfo->psKernelEDMStatusBufferMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelEDMStatusBufferMemInfo; #endif -#if defined(SGX_FEATURE_OVERLAPPED_SPM) - psDevInfo->psKernelTmpRgnHeaderMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelTmpRgnHeaderMemInfo; -#endif -#if defined(SGX_FEATURE_SPM_MODE_0) - psDevInfo->psKernelTmpDPMStateMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelTmpDPMStateMemInfo; -#endif - + /* + * Assign client-side build options for later verification + */ psDevInfo->ui32ClientBuildOptions = psInitInfo->ui32ClientBuildOptions; - + /* + * Assign microkernel IF structure sizes for later verification + */ psDevInfo->sSGXStructSizes = psInitInfo->sSGXStructSizes; - - + /* + Setup the kernel version of the CCB control + */ eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_SGX_CCB_INFO), (IMG_VOID **)&psKernelCCBInfo, 0, @@ -207,8 +285,9 @@ static PVRSRV_ERROR InitDevInfo(PVRSRV_PER_PROCESS_DATA *psPerProc, psKernelCCBInfo->pui32ReadOffset = &psDevInfo->psKernelCCBCtl->ui32ReadOffset; psDevInfo->psKernelCCBInfo = psKernelCCBInfo; - - + /* + Copy the USE code addresses for the host kick. + */ OSMemCopy(psDevInfo->aui32HostKickAddr, psInitInfo->aui32HostKickAddr, SGXMKIF_CMD_MAX * sizeof(psDevInfo->aui32HostKickAddr[0])); @@ -227,10 +306,10 @@ static PVRSRV_ERROR InitDevInfo(PVRSRV_PER_PROCESS_DATA *psPerProc, psDevInfo->ui32MasterClkGateStatusMask = psInitInfo->ui32MasterClkGateStatusMask; psDevInfo->ui32MasterClkGateStatus2Reg = psInitInfo->ui32MasterClkGateStatus2Reg; psDevInfo->ui32MasterClkGateStatus2Mask = psInitInfo->ui32MasterClkGateStatus2Mask; -#endif +#endif /* SGX_FEATURE_MP */ - + /* Initialise Dev Data */ OSMemCopy(&psDevInfo->asSGXDevData, &psInitInfo->asInitDevData, sizeof(psDevInfo->asSGXDevData)); return PVRSRV_OK; @@ -262,6 +341,15 @@ static PVRSRV_ERROR SGXRunScript(PVRSRV_SGXDEV_INFO *psDevInfo, SGX_INIT_COMMAND PDUMPREG(SGX_PDUMPREG_NAME, psComm->sWriteHWReg.ui32Offset, psComm->sWriteHWReg.ui32Value); break; } + case SGX_INIT_OP_READ_HW_REG: + { + OSReadHWReg(psDevInfo->pvRegsBaseKM, psComm->sReadHWReg.ui32Offset); +#if defined(PDUMP) + PDUMPCOMMENT("SGXRunScript: Read HW reg operation"); + PDumpRegRead(SGX_PDUMPREG_NAME, psComm->sReadHWReg.ui32Offset, PDUMP_FLAGS_CONTINUOUS); +#endif + break; + } #if defined(PDUMP) case SGX_INIT_OP_PDUMP_HW_REG: { @@ -275,7 +363,7 @@ static PVRSRV_ERROR SGXRunScript(PVRSRV_SGXDEV_INFO *psDevInfo, SGX_INIT_COMMAND return PVRSRV_OK; } case SGX_INIT_OP_ILLEGAL: - + /* FALLTHROUGH */ default: { PVR_DPF((PVR_DBG_ERROR,"SGXRunScript: PC %d: Illegal command: %d", ui32PC, psComm->eOp)); @@ -288,6 +376,93 @@ static PVRSRV_ERROR SGXRunScript(PVRSRV_SGXDEV_INFO *psDevInfo, SGX_INIT_COMMAND return PVRSRV_ERROR_UNKNOWN_SCRIPT_OPERATION; } +#if defined(SUPPORT_MEMORY_TILING) +static PVRSRV_ERROR SGX_AllocMemTilingRangeInt(PVRSRV_SGXDEV_INFO *psDevInfo, + IMG_UINT32 ui32Start, + IMG_UINT32 ui32End, + IMG_UINT32 ui32TilingStride, + IMG_UINT32 *pui32RangeIndex) +{ + IMG_UINT32 i; + IMG_UINT32 ui32Offset; + IMG_UINT32 ui32Val; + + /* HW supports 10 ranges */ + for(i=0; i < SGX_BIF_NUM_TILING_RANGES; i++) + { + if((psDevInfo->ui32MemTilingUsage & (1U << i)) == 0) + { + /* mark in use */ + psDevInfo->ui32MemTilingUsage |= 1U << i; + /* output range index if the caller wants it */ + if(pui32RangeIndex != IMG_NULL) + { + *pui32RangeIndex = i; + } + goto RangeAllocated; + } + } + + PVR_DPF((PVR_DBG_ERROR,"SGX_AllocMemTilingRange: all tiling ranges in use")); + return PVRSRV_ERROR_EXCEEDED_HW_LIMITS; + +RangeAllocated: + + /* An improperly aligned range could cause BIF not to tile some memory which is intended to be tiled, + * or cause BIF to tile some memory which is not intended to be. + */ + if(ui32Start & ~SGX_BIF_TILING_ADDR_MASK) + { + PVR_DPF((PVR_DBG_WARNING,"SGX_AllocMemTilingRangeInt: Tiling range start (0x%08X) fails" + "alignment test", ui32Start)); + } + if((ui32End + 0x00001000) & ~SGX_BIF_TILING_ADDR_MASK) + { + PVR_DPF((PVR_DBG_WARNING,"SGX_AllocMemTilingRangeInt: Tiling range end (0x%08X) fails" + "alignment test", ui32End)); + } + + ui32Offset = EUR_CR_BIF_TILE0 + (i<<2); + + ui32Val = ((ui32TilingStride << EUR_CR_BIF_TILE0_CFG_SHIFT) & EUR_CR_BIF_TILE0_CFG_MASK) + | (((ui32End>>SGX_BIF_TILING_ADDR_LSB) << EUR_CR_BIF_TILE0_MAX_ADDRESS_SHIFT) & EUR_CR_BIF_TILE0_MAX_ADDRESS_MASK) + | (((ui32Start>>SGX_BIF_TILING_ADDR_LSB) << EUR_CR_BIF_TILE0_MIN_ADDRESS_SHIFT) & EUR_CR_BIF_TILE0_MIN_ADDRESS_MASK) + | (EUR_CR_BIF_TILE0_ENABLE << EUR_CR_BIF_TILE0_CFG_SHIFT); + + OSWriteHWReg(psDevInfo->pvRegsBaseKM, ui32Offset, ui32Val); + PDUMPREG(SGX_PDUMPREG_NAME, ui32Offset, ui32Val); + +#if defined(SGX_FEATURE_BIF_WIDE_TILING_AND_4K_ADDRESS) + ui32Offset = EUR_CR_BIF_TILE0_ADDR_EXT + (i<<2); + + ui32Val = (((ui32End>>SGX_BIF_TILING_EXT_ADDR_LSB) << EUR_CR_BIF_TILE0_ADDR_EXT_MAX_SHIFT) & EUR_CR_BIF_TILE0_ADDR_EXT_MAX_MASK) + | (((ui32Start>>SGX_BIF_TILING_EXT_ADDR_LSB) << EUR_CR_BIF_TILE0_ADDR_EXT_MIN_SHIFT) & EUR_CR_BIF_TILE0_ADDR_EXT_MIN_MASK); + + OSWriteHWReg(psDevInfo->pvRegsBaseKM, ui32Offset, ui32Val); + PDUMPREG(SGX_PDUMPREG_NAME, ui32Offset, ui32Val); +#endif /* SGX_FEATURE_BIF_WIDE_TILING_AND_4K_ADDRESS */ + + return PVRSRV_OK; +} + +#endif /* SUPPORT_MEMORY_TILING */ + +/*! +******************************************************************************* + + @Function SGXInitialise + + @Description + + (client invoked) chip-reset and initialisation + + @Input pvDeviceNode - device info. structure + @Input bHardwareRecovery - true if recovering powered hardware, + false if powering up + + @Return PVRSRV_ERROR + +******************************************************************************/ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_BOOL bHardwareRecovery) { @@ -297,16 +472,17 @@ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO *psDevInfo, static IMG_BOOL bFirstTime = IMG_TRUE; #if defined(PDUMP) IMG_BOOL bPDumpIsSuspended = PDumpIsSuspended(); -#endif +#endif /* PDUMP */ #if defined(SGX_FEATURE_MP) - + /* Slave core clocks must be enabled during reset */ #else SGXInitClocks(psDevInfo, PDUMP_FLAGS_CONTINUOUS); -#endif - +#endif /* SGX_FEATURE_MP */ - + /* + Part 1 of the initialisation script runs before resetting SGX. + */ PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "SGX initialisation script part 1\n"); eError = SGXRunScript(psDevInfo, psDevInfo->sScripts.asInitCommandsPart1, SGX_MAX_INIT_COMMANDS); if (eError != PVRSRV_OK) @@ -316,27 +492,33 @@ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO *psDevInfo, } PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "End of SGX initialisation script part 1\n"); - + /* Reset the chip */ psDevInfo->ui32NumResets++; - SGXReset(psDevInfo, bFirstTime || bHardwareRecovery, PDUMP_FLAGS_CONTINUOUS); + +#if !defined(SGX_FEATURE_MP) + bHardwareRecovery |= bFirstTime; +#endif /* SGX_FEATURE_MP */ + + SGXReset(psDevInfo, bHardwareRecovery, PDUMP_FLAGS_CONTINUOUS); #if defined(EUR_CR_POWER) #if defined(SGX531) - - - - - + /* + Disable half the pipes. + 531 has 2 pipes within a 4 pipe framework, so + the 2 redundant pipes must be disabled even + though they do not exist. + */ OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_POWER, 1); PDUMPREG(SGX_PDUMPREG_NAME, EUR_CR_POWER, 1); #else - + /* set the default pipe count (all fully enabled) */ OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_POWER, 0); PDUMPREG(SGX_PDUMPREG_NAME, EUR_CR_POWER, 0); #endif #endif - + /* Initialise the kernel CCB event kicker value */ *psDevInfo->pui32KernelCCBEventKicker = 0; #if defined(PDUMP) if (!bPDumpIsSuspended) @@ -347,10 +529,42 @@ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO *psDevInfo, sizeof(*psDevInfo->pui32KernelCCBEventKicker), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelCCBEventKickerMemInfo)); } -#endif +#endif /* PDUMP */ - +#if defined(SUPPORT_MEMORY_TILING) + { + /* Initialise EUR_CR_BIF_TILE registers for any tiling heaps */ + DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap = psDevInfo->pvDeviceMemoryHeap; + IMG_UINT32 i; + + psDevInfo->ui32MemTilingUsage = 0; + + for(i=0; i<psDevInfo->ui32HeapCount; i++) + { + if(psDeviceMemoryHeap[i].ui32XTileStride > 0) + { + /* Set up the HW control registers */ + eError = SGX_AllocMemTilingRangeInt( + psDevInfo, + psDeviceMemoryHeap[i].sDevVAddrBase.uiAddr, + psDeviceMemoryHeap[i].sDevVAddrBase.uiAddr + + psDeviceMemoryHeap[i].ui32HeapSize, + psDeviceMemoryHeap[i].ui32XTileStride, + NULL); + if(eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "Unable to allocate SGX BIF tiling range for heap: %s", + psDeviceMemoryHeap[i].pszName)); + break; + } + } + } + } +#endif + /* + Part 2 of the initialisation script runs after resetting SGX. + */ PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "SGX initialisation script part 2\n"); eError = SGXRunScript(psDevInfo, psDevInfo->sScripts.asInitCommandsPart2, SGX_MAX_INIT_COMMANDS); if (eError != PVRSRV_OK) @@ -360,7 +574,7 @@ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO *psDevInfo, } PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "End of SGX initialisation script part 2\n"); - + /* Record the system timestamp for the microkernel */ psSGXHostCtl->ui32HostClock = OSClockus(); psSGXHostCtl->ui32InitStatus = 0; @@ -373,7 +587,7 @@ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO *psDevInfo, MAKEUNIQUETAG(psSGXHostCtlMemInfo)); PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "Initialise the microkernel\n"); -#endif +#endif /* PDUMP */ #if defined(SGX_FEATURE_MULTI_EVENT_KICK) OSWriteMemoryBarrier(); @@ -386,13 +600,14 @@ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO *psDevInfo, OSWriteHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_SELECT(EUR_CR_EVENT_KICK, 0), EUR_CR_EVENT_KICK_NOW_MASK); -#endif +#endif /* SGX_FEATURE_MULTI_EVENT_KICK */ OSMemoryBarrier(); #if defined(PDUMP) - - + /* + Dump the host kick. + */ if (!bPDumpIsSuspended) { #if defined(SGX_FEATURE_MULTI_EVENT_KICK) @@ -408,13 +623,14 @@ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO *psDevInfo, PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelCCBEventKickerMemInfo)); PDUMPREG(SGX_PDUMPREG_NAME, SGX_MP_CORE_SELECT(EUR_CR_EVENT_KICK, 0), EUR_CR_EVENT_KICK_NOW_MASK); -#endif +#endif /* SGX_FEATURE_MULTI_EVENT_KICK */ } -#endif +#endif /* PDUMP */ #if !defined(NO_HARDWARE) - - + /* + Wait for the microkernel to finish initialising. + */ if (PollForValueKM(&psSGXHostCtl->ui32InitStatus, PVRSRV_USSE_EDM_INIT_COMPLETE, PVRSRV_USSE_EDM_INIT_COMPLETE, @@ -423,13 +639,13 @@ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_FALSE) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "SGXInitialise: Wait for uKernel initialisation failed")); - #if !defined(FIX_HW_BRN_23281) + SGXDumpDebugInfo(psDevInfo, IMG_FALSE); PVR_DBG_BREAK; - #endif + return PVRSRV_ERROR_RETRY; } -#endif +#endif /* NO_HARDWARE */ #if defined(PDUMP) PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, @@ -441,14 +657,7 @@ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO *psDevInfo, PDUMP_POLL_OPERATOR_EQUAL, PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psSGXHostCtlMemInfo)); -#endif - -#if defined(FIX_HW_BRN_22997) && defined(FIX_HW_BRN_23030) && defined(SGX_FEATURE_HOST_PORT) - - - - WorkaroundBRN22997ReadHostPort(psDevInfo); -#endif +#endif /* PDUMP */ PVR_ASSERT(psDevInfo->psKernelCCBCtl->ui32ReadOffset == psDevInfo->psKernelCCBCtl->ui32WriteOffset); @@ -457,13 +666,27 @@ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO *psDevInfo, return PVRSRV_OK; } +/*! +******************************************************************************* + + @Function SGXDeinitialise + + @Description + + (client invoked) chip-reset and deinitialisation + + @Input hDevCookie - device info. handle + + @Return PVRSRV_ERROR + +******************************************************************************/ PVRSRV_ERROR SGXDeinitialise(IMG_HANDLE hDevCookie) { PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO *) hDevCookie; PVRSRV_ERROR eError; - + /* Did SGXInitialise map the SGX registers in? */ if (psDevInfo->pvRegsBaseKM == IMG_NULL) { return PVRSRV_OK; @@ -480,6 +703,20 @@ PVRSRV_ERROR SGXDeinitialise(IMG_HANDLE hDevCookie) } +/*! +******************************************************************************* + + @Function DevInitSGXPart1 + + @Description + + Reset and initialise Chip + + @Input pvDeviceNode - device info. structure + + @Return PVRSRV_ERROR + +******************************************************************************/ static PVRSRV_ERROR DevInitSGXPart1 (IMG_VOID *pvDeviceNode) { IMG_HANDLE hDevMemHeap = IMG_NULL; @@ -491,7 +728,7 @@ static PVRSRV_ERROR DevInitSGXPart1 (IMG_VOID *pvDeviceNode) DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap; PVRSRV_ERROR eError; - + /* pdump info about the core */ PDUMPCOMMENT("SGX Core Version Information: %s", SGX_CORE_FRIENDLY_NAME); #if defined(SGX_FEATURE_MP) @@ -500,7 +737,7 @@ static PVRSRV_ERROR DevInitSGXPart1 (IMG_VOID *pvDeviceNode) #else PDUMPCOMMENT("SGX Multi-processor: %d TA cores, %d 3D cores", SGX_FEATURE_MP_CORE_COUNT_TA, SGX_FEATURE_MP_CORE_COUNT_3D); #endif - #endif + #endif /* SGX_FEATURE_MP */ #if (SGX_CORE_REV == 0) PDUMPCOMMENT("SGX Core Revision Information: head RTL"); @@ -512,12 +749,12 @@ static PVRSRV_ERROR DevInitSGXPart1 (IMG_VOID *pvDeviceNode) PDUMPCOMMENT("SGX System Level Cache is present\r\n"); #if defined(SGX_BYPASS_SYSTEM_CACHE) PDUMPCOMMENT("SGX System Level Cache is bypassed\r\n"); - #endif - #endif + #endif /* SGX_BYPASS_SYSTEM_CACHE */ + #endif /* SGX_FEATURE_SYSTEM_CACHE */ PDUMPCOMMENT("SGX Initialisation Part 1"); - + /* Allocate device control block */ if(OSAllocMem( PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_SGXDEV_INFO), (IMG_VOID **)&psDevInfo, IMG_NULL, @@ -528,17 +765,18 @@ static PVRSRV_ERROR DevInitSGXPart1 (IMG_VOID *pvDeviceNode) } OSMemSet (psDevInfo, 0, sizeof(PVRSRV_SGXDEV_INFO)); - + /* setup info from jdisplayconfig.h (variations controlled by build) */ psDevInfo->eDeviceType = DEV_DEVICE_TYPE; psDevInfo->eDeviceClass = DEV_DEVICE_CLASS; - + /* Store the devinfo as its needed by dynamically enumerated systems called from BM */ psDeviceNode->pvDevice = (IMG_PVOID)psDevInfo; - + /* get heap info from the devnode */ + psDevInfo->ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount; psDevInfo->pvDeviceMemoryHeap = (IMG_VOID*)psDeviceMemoryHeap; - + /* create the kernel memory context */ hKernelDevMemContext = BM_CreateContext(psDeviceNode, &sPDDevPAddr, IMG_NULL, @@ -551,7 +789,7 @@ static PVRSRV_ERROR DevInitSGXPart1 (IMG_VOID *pvDeviceNode) psDevInfo->sKernelPDDevPAddr = sPDDevPAddr; - + /* create the kernel, shared and shared_exported heaps */ for(i=0; i<psDeviceNode->sDevMemoryInfo.ui32HeapCount; i++) { switch(psDeviceMemoryHeap[i].DevMemHeapType) @@ -560,14 +798,15 @@ static PVRSRV_ERROR DevInitSGXPart1 (IMG_VOID *pvDeviceNode) case DEVICE_MEMORY_HEAP_SHARED: case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: { - + /* Shared PB heap could be zero size */ if (psDeviceMemoryHeap[i].ui32HeapSize > 0) { hDevMemHeap = BM_CreateHeap (hKernelDevMemContext, &psDeviceMemoryHeap[i]); - - - + /* + in the case of kernel context heaps just store + the heap handle in the heap info structure + */ psDeviceMemoryHeap[i].hDevMemHeap = hDevMemHeap; } break; @@ -577,7 +816,7 @@ static PVRSRV_ERROR DevInitSGXPart1 (IMG_VOID *pvDeviceNode) #if defined(PDUMP) if(hDevMemHeap) { - + /* set up the MMU pdump info */ psDevInfo->sMMUAttrib = *((BM_HEAP*)hDevMemHeap)->psMMUAttrib; } #endif @@ -591,6 +830,23 @@ static PVRSRV_ERROR DevInitSGXPart1 (IMG_VOID *pvDeviceNode) return PVRSRV_OK; } +/*! +******************************************************************************* + + @Function SGXGetInfoForSrvinitKM + + @Description + + Get SGX related information necessary for initilisation server + + @Input hDevHandle - device handle + psInitInfo - pointer to structure for returned information + + @Output psInitInfo - pointer to structure containing returned information + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR SGXGetInfoForSrvinitKM(IMG_HANDLE hDevHandle, PVRSRV_HEAP_INFO_KM *pasHeapInfo, IMG_DEV_PHYADDR *psPDDevPAddr) @@ -625,6 +881,20 @@ PVRSRV_ERROR SGXGetInfoForSrvinitKM(IMG_HANDLE hDevHandle, SGX_BRIDGE_INFO_FOR_S return eError; } +/*! +******************************************************************************* + + @Function DevInitSGXPart2KM + + @Description + + Reset and initialise Chip + + @Input pvDeviceNode - device info. structure + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR DevInitSGXPart2KM (PVRSRV_PER_PROCESS_DATA *psPerProc, IMG_HANDLE hDevHandle, @@ -645,8 +915,9 @@ PVRSRV_ERROR DevInitSGXPart2KM (PVRSRV_PER_PROCESS_DATA *psPerProc, psDeviceNode = (PVRSRV_DEVICE_NODE *)hDevHandle; psDevInfo = (PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; - - + /* + Init devinfo + */ eError = InitDevInfo(psPerProc, psDeviceNode, psInitInfo); if (eError != PVRSRV_OK) { @@ -663,14 +934,14 @@ PVRSRV_ERROR DevInitSGXPart2KM (PVRSRV_PER_PROCESS_DATA *psPerProc, return PVRSRV_ERROR_INIT_FAILURE; } - + /* Registers already mapped? */ if (psSGXDeviceMap->pvRegsCpuVBase) { psDevInfo->pvRegsBaseKM = psSGXDeviceMap->pvRegsCpuVBase; } else { - + /* Map Regs */ psDevInfo->pvRegsBaseKM = OSMapPhysToLin(psSGXDeviceMap->sRegsCpuPBase, psSGXDeviceMap->ui32RegsSize, PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED, @@ -688,7 +959,7 @@ PVRSRV_ERROR DevInitSGXPart2KM (PVRSRV_PER_PROCESS_DATA *psPerProc, #if defined(SGX_FEATURE_HOST_PORT) if (psSGXDeviceMap->ui32Flags & SGX_HOSTPORT_PRESENT) { - + /* Map Host Port */ psDevInfo->pvHostPortBaseKM = OSMapPhysToLin(psSGXDeviceMap->sHPCpuPBase, psSGXDeviceMap->ui32HPSize, PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED, @@ -701,21 +972,21 @@ PVRSRV_ERROR DevInitSGXPart2KM (PVRSRV_PER_PROCESS_DATA *psPerProc, psDevInfo->ui32HPSize = psSGXDeviceMap->ui32HPSize; psDevInfo->sHPSysPAddr = psSGXDeviceMap->sHPSysPBase; } -#endif +#endif/* #ifdef SGX_FEATURE_HOST_PORT */ #if defined (SYS_USING_INTERRUPTS) - + /* Set up ISR callback information. */ psDeviceNode->pvISRData = psDeviceNode; - + /* ISR handler address was set up earlier */ PVR_ASSERT(psDeviceNode->pfnDeviceISR == SGX_ISRHandler); -#endif +#endif /* SYS_USING_INTERRUPTS */ - + /* Prevent the microkernel being woken up before there is something to do. */ psDevInfo->psSGXHostCtl->ui32PowerStatus |= PVRSRV_USSE_EDM_POWMAN_NO_WORK; eDefaultPowerState = PVRSRV_DEV_POWER_STATE_OFF; - + /* Register the device with the power manager. */ eError = PVRSRVRegisterPowerDevice (psDeviceNode->sDevId.ui32DeviceIndex, &SGXPrePowerState, &SGXPostPowerState, &SGXPreClockSpeedChange, &SGXPostClockSpeedChange, @@ -728,17 +999,8 @@ PVRSRV_ERROR DevInitSGXPart2KM (PVRSRV_PER_PROCESS_DATA *psPerProc, return eError; } -#if defined(FIX_HW_BRN_22997) && defined(FIX_HW_BRN_23030) && defined(SGX_FEATURE_HOST_PORT) - eError = WorkaroundBRN22997Alloc(psDeviceNode); - if (eError != PVRSRV_OK) - { - PVR_DPF((PVR_DBG_ERROR,"SGXInitialise : Failed to alloc memory for BRN22997 workaround")); - return eError; - } -#endif - #if defined(SUPPORT_EXTERNAL_SYSTEM_CACHE) - + /* map the external system cache control registers into the SGX MMU */ psDevInfo->ui32ExtSysCacheRegsSize = psSGXDeviceMap->ui32ExtSysCacheRegsSize; psDevInfo->sExtSysCacheRegsDevPBase = psSGXDeviceMap->sExtSysCacheRegsDevPBase; eError = MMU_MapExtSystemCacheRegs(psDeviceNode); @@ -747,10 +1009,11 @@ PVRSRV_ERROR DevInitSGXPart2KM (PVRSRV_PER_PROCESS_DATA *psPerProc, PVR_DPF((PVR_DBG_ERROR,"SGXInitialise : Failed to map external system cache registers")); return eError; } -#endif - - +#endif /* SUPPORT_EXTERNAL_SYSTEM_CACHE */ + /* + Initialise the Kernel CCB + */ OSMemSet(psDevInfo->psKernelCCB, 0, sizeof(PVRSRV_SGX_KERNEL_CCB)); OSMemSet(psDevInfo->psKernelCCBCtl, 0, sizeof(PVRSRV_SGX_CCB_CTL)); OSMemSet(psDevInfo->pui32KernelCCBEventKicker, 0, sizeof(*psDevInfo->pui32KernelCCBEventKicker)); @@ -767,6 +1030,20 @@ failed_init_dev_info: return eError; } +/*! +******************************************************************************* + + @Function DevDeInitSGX + + @Description + + Reset and deinitialise Chip + + @Input pvDeviceNode - device info. structure + + @Return PVRSRV_ERROR + +******************************************************************************/ static PVRSRV_ERROR DevDeInitSGX (IMG_VOID *pvDeviceNode) { PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE *)pvDeviceNode; @@ -778,7 +1055,7 @@ static PVRSRV_ERROR DevDeInitSGX (IMG_VOID *pvDeviceNode) if (!psDevInfo) { - + /* Can happen if DevInitSGX failed */ PVR_DPF((PVR_DBG_ERROR,"DevDeInitSGX: Null DevInfo")); return PVRSRV_OK; } @@ -794,29 +1071,26 @@ static PVRSRV_ERROR DevDeInitSGX (IMG_VOID *pvDeviceNode) } psDevInfo->hTimer = IMG_NULL; } -#endif +#endif /* SUPPORT_HW_RECOVERY */ #if defined(SUPPORT_EXTERNAL_SYSTEM_CACHE) - + /* unmap the external system cache control registers */ eError = MMU_UnmapExtSystemCacheRegs(psDeviceNode); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"DevDeInitSGX: Failed to unmap ext system cache registers")); return eError; } -#endif - -#if defined(FIX_HW_BRN_22997) && defined(FIX_HW_BRN_23030) && defined(SGX_FEATURE_HOST_PORT) - WorkaroundBRN22997Free(psDeviceNode); -#endif +#endif /* SUPPORT_EXTERNAL_SYSTEM_CACHE */ MMU_BIFResetPDFree(psDevInfo); - - + /* + DeinitDevInfo the DevInfo + */ DeinitDevInfo(psDevInfo); - + /* Destroy heaps. */ psDeviceMemoryHeap = (DEVICE_MEMORY_HEAP_INFO *)psDevInfo->pvDeviceMemoryHeap; for(ui32Heap=0; ui32Heap<psDeviceNode->sDevMemoryInfo.ui32HeapCount; ui32Heap++) { @@ -835,7 +1109,7 @@ static PVRSRV_ERROR DevDeInitSGX (IMG_VOID *pvDeviceNode) } } - + /* Destroy the kernel context. */ eError = BM_DestroyContext(psDeviceNode->sDevMemoryInfo.pBMKernelContext, IMG_NULL); if (eError != PVRSRV_OK) { @@ -843,7 +1117,7 @@ static PVRSRV_ERROR DevDeInitSGX (IMG_VOID *pvDeviceNode) return eError; } - + /* remove the device from the power manager */ eError = PVRSRVRemovePowerDevice (((PVRSRV_DEVICE_NODE*)pvDeviceNode)->sDevId.ui32DeviceIndex); if (eError != PVRSRV_OK) { @@ -858,10 +1132,10 @@ static PVRSRV_ERROR DevDeInitSGX (IMG_VOID *pvDeviceNode) return eError; } - + /* Only unmap the registers if they were mapped here */ if (!psSGXDeviceMap->pvRegsCpuVBase) { - + /* UnMap Regs */ if (psDevInfo->pvRegsBaseKM != IMG_NULL) { OSUnMapPhysToLin(psDevInfo->pvRegsBaseKM, @@ -874,7 +1148,7 @@ static PVRSRV_ERROR DevDeInitSGX (IMG_VOID *pvDeviceNode) #if defined(SGX_FEATURE_HOST_PORT) if (psSGXDeviceMap->ui32Flags & SGX_HOSTPORT_PRESENT) { - + /* unMap Host Port */ if (psDevInfo->pvHostPortBaseKM != IMG_NULL) { OSUnMapPhysToLin(psDevInfo->pvHostPortBaseKM, @@ -883,10 +1157,10 @@ static PVRSRV_ERROR DevDeInitSGX (IMG_VOID *pvDeviceNode) IMG_NULL); } } -#endif +#endif /* #ifdef SGX_FEATURE_HOST_PORT */ - + /* DeAllocate devinfo */ OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_SGXDEV_INFO), psDevInfo, @@ -896,7 +1170,7 @@ static PVRSRV_ERROR DevDeInitSGX (IMG_VOID *pvDeviceNode) if (psDeviceMemoryHeap != IMG_NULL) { - + /* Free the device memory heap info. */ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(DEVICE_MEMORY_HEAP_INFO) * SGX_MAX_HEAP_ID, psDeviceMemoryHeap, @@ -909,6 +1183,22 @@ static PVRSRV_ERROR DevDeInitSGX (IMG_VOID *pvDeviceNode) #if defined(RESTRICTED_REGISTERS) && defined(SGX_FEATURE_MP) +/*! +******************************************************************************* + + @Function SGXDumpMasterDebugReg + + @Description + + Dump a single SGX debug register value + + @Input psDevInfo - SGX device info + @Input pszName - string used for logging + @Input ui32RegAddr - SGX register offset + + @Return IMG_VOID + +******************************************************************************/ static IMG_VOID SGXDumpMasterDebugReg (PVRSRV_SGXDEV_INFO *psDevInfo, IMG_CHAR *pszName, IMG_UINT32 ui32RegAddr) @@ -918,8 +1208,25 @@ static IMG_VOID SGXDumpMasterDebugReg (PVRSRV_SGXDEV_INFO *psDevInfo, PVR_LOG(("(HYD) %s%08X", pszName, ui32RegVal)); } -#endif +#endif /* defined(RESTRICTED_REGISTERS) */ + +/*! +******************************************************************************* + + @Function SGXDumpDebugReg + + @Description + Dump a single SGX debug register value + + @Input psDevInfo - SGX device info + @Input ui32CoreNum - processor number + @Input pszName - string used for logging + @Input ui32RegAddr - SGX register offset + + @Return IMG_VOID + +******************************************************************************/ static IMG_VOID SGXDumpDebugReg (PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32CoreNum, IMG_CHAR *pszName, @@ -930,8 +1237,24 @@ static IMG_VOID SGXDumpDebugReg (PVRSRV_SGXDEV_INFO *psDevInfo, PVR_LOG(("(P%u) %s%08X", ui32CoreNum, pszName, ui32RegVal)); } -static IMG_VOID SGXDumpDebugInfo (PVRSRV_SGXDEV_INFO *psDevInfo, - IMG_BOOL bDumpSGXRegs) +/*! +******************************************************************************* + + @Function SGXDumpDebugInfo + + @Description + + Dump useful debugging info + + @Input psDevInfo - SGX device info + @Input bDumpSGXRegs - Whether to dump SGX debug registers. Must not be done + when SGX is not powered. + + @Return IMG_VOID + +******************************************************************************/ +IMG_VOID SGXDumpDebugInfo (PVRSRV_SGXDEV_INFO *psDevInfo, + IMG_BOOL bDumpSGXRegs) { IMG_UINT32 ui32CoreNum; @@ -967,7 +1290,7 @@ static IMG_VOID SGXDumpDebugInfo (PVRSRV_SGXDEV_INFO *psDevInfo, #endif for (ui32CoreNum = 0; ui32CoreNum < SGX_FEATURE_MP_CORE_COUNT_3D; ui32CoreNum++) { - + /* Dump HW event status */ SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_EVENT_STATUS: ", EUR_CR_EVENT_STATUS); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_EVENT_STATUS2: ", EUR_CR_EVENT_STATUS2); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_BIF_CTRL: ", EUR_CR_BIF_CTRL); @@ -981,16 +1304,71 @@ static IMG_VOID SGXDumpDebugInfo (PVRSRV_SGXDEV_INFO *psDevInfo, #if defined(EUR_CR_PDS_PC_BASE) SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_PDS_PC_BASE: ", EUR_CR_PDS_PC_BASE); #endif +#if defined(RESTRICTED_REGISTERS) + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_BIF_BANK_SET: ", EUR_CR_BIF_BANK_SET); + + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_CLKGATECTL: ", EUR_CR_CLKGATECTL); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_CLKGATESTATUS: ", EUR_CR_CLKGATESTATUS); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_MTE_CTRL: ", EUR_CR_MTE_CTRL); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_EVENT_OTHER_PDS_EXEC: ", EUR_CR_EVENT_OTHER_PDS_EXEC); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_EVENT_OTHER_PDS_DATA: ", EUR_CR_EVENT_OTHER_PDS_DATA); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_EVENT_OTHER_PDS_INFO: ", EUR_CR_EVENT_OTHER_PDS_INFO); + + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_ZLS_PAGE_THRESHOLD: ", EUR_CR_DPM_ZLS_PAGE_THRESHOLD); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_TA_GLOBAL_LIST: ", EUR_CR_DPM_TA_GLOBAL_LIST); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_STATE_CONTEXT_ID: ", EUR_CR_DPM_STATE_CONTEXT_ID); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_CONTEXT_PB_BASE: ", EUR_CR_DPM_CONTEXT_PB_BASE); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_TA_ALLOC_FREE_LIST_STATUS1: ", EUR_CR_DPM_TA_ALLOC_FREE_LIST_STATUS1); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_3D_FREE_LIST_STATUS1: ", EUR_CR_DPM_3D_FREE_LIST_STATUS1); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_TA_ALLOC_FREE_LIST_STATUS2: ", EUR_CR_DPM_TA_ALLOC_FREE_LIST_STATUS2); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_3D_FREE_LIST_STATUS2: ", EUR_CR_DPM_3D_FREE_LIST_STATUS2); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_ABORT_STATUS_MTILE: ", EUR_CR_DPM_ABORT_STATUS_MTILE); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_PAGE_STATUS: ", EUR_CR_DPM_PAGE_STATUS); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_PAGE: ", EUR_CR_DPM_PAGE); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_GLOBAL_PAGE_STATUS: ", EUR_CR_DPM_GLOBAL_PAGE_STATUS); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_VDM_CONTEXT_LOAD_STATUS: ", EUR_CR_VDM_CONTEXT_LOAD_STATUS); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_VDM_CONTEXT_STORE_STATUS: ", EUR_CR_VDM_CONTEXT_STORE_STATUS); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_VDM_TASK_KICK_STATUS: ", EUR_CR_VDM_TASK_KICK_STATUS); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_VDM_CONTEXT_STORE_STATE0: ", EUR_CR_VDM_CONTEXT_STORE_STATE0); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_VDM_CONTEXT_STORE_STATE1: ", EUR_CR_VDM_CONTEXT_STORE_STATE1); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_REQUESTING: ", EUR_CR_DPM_REQUESTING); + SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_REQUESTING: ", EUR_CR_DPM_REQUESTING); + +#endif } } - +/* This code only works for _real_ single memory context chips */ +#if !defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) && !defined(FIX_HW_BRN_31620) + { + IMG_UINT32 ui32RegVal; + IMG_UINT32 ui32PDDevPAddr; + + /* + If there was a SGX pagefault check the page table too see if the + host thinks the fault is correct + */ + ui32RegVal = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_INT_STAT); + if (ui32RegVal & EUR_CR_BIF_INT_STAT_PF_N_RW_MASK) + { + ui32RegVal = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_FAULT); + ui32RegVal &= EUR_CR_BIF_FAULT_ADDR_MASK; + ui32PDDevPAddr = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_DIR_LIST_BASE0); + ui32PDDevPAddr &= EUR_CR_BIF_DIR_LIST_BASE0_ADDR_MASK; + MMU_CheckFaultAddr(psDevInfo, ui32PDDevPAddr, ui32RegVal); + } + } +#endif + /* + Dump out the outstanding queue items. + */ QueueDumpDebugInfo(); { - - + /* + Dump out the Host control. + */ SGXMKIF_HOST_CTL *psSGXHostCtl = psDevInfo->psSGXHostCtl; IMG_UINT32 *pui32HostCtlBuffer = (IMG_UINT32 *)psSGXHostCtl; IMG_UINT32 ui32LoopCounter; @@ -1014,8 +1392,9 @@ static IMG_VOID SGXDumpDebugInfo (PVRSRV_SGXDEV_INFO *psDevInfo, } { - - + /* + Dump out the TA/3D control. + */ IMG_UINT32 *pui32TA3DCtlBuffer = psDevInfo->psKernelSGXTA3DCtlMemInfo->pvLinAddrKM; IMG_UINT32 ui32LoopCounter; @@ -1041,11 +1420,13 @@ static IMG_VOID SGXDumpDebugInfo (PVRSRV_SGXDEV_INFO *psDevInfo, ui32WriteOffset = *pui32MKTraceBuffer; pui32MKTraceBuffer++; - PVR_LOG(("Last SGX microkernel status code: %08X", ui32LastStatusCode)); + PVR_LOG(("Last SGX microkernel status code: %08X %s", + ui32LastStatusCode, SGXUKernelStatusString(ui32LastStatusCode))); #if defined(PVRSRV_DUMP_MK_TRACE) - - + /* + Dump the raw microkernel trace buffer to the log. + */ { IMG_UINT32 ui32LoopCounter; @@ -1056,17 +1437,19 @@ static IMG_VOID SGXDumpDebugInfo (PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 *pui32BufPtr; pui32BufPtr = pui32MKTraceBuffer + (((ui32WriteOffset + ui32LoopCounter) % SGXMK_TRACE_BUFFER_SIZE) * 4); - PVR_LOG(("\t(MKT-%X) %08X %08X %08X %08X", ui32LoopCounter, - pui32BufPtr[2], pui32BufPtr[3], pui32BufPtr[1], pui32BufPtr[0])); + PVR_LOG(("\t(MKT-%X) %08X %08X %08X %08X %s", ui32LoopCounter, + pui32BufPtr[2], pui32BufPtr[3], pui32BufPtr[1], pui32BufPtr[0], + SGXUKernelStatusString(pui32BufPtr[0]))); } } - #endif + #endif /* PVRSRV_DUMP_MK_TRACE */ } - #endif + #endif /* PVRSRV_USSE_EDM_STATUS_DEBUG */ { - - + /* + Dump out the kernel CCB. + */ PVR_LOG(("SGX Kernel CCB WO:0x%X RO:0x%X", psDevInfo->psKernelCCBCtl->ui32WriteOffset, psDevInfo->psKernelCCBCtl->ui32ReadOffset)); @@ -1088,7 +1471,7 @@ static IMG_VOID SGXDumpDebugInfo (PVRSRV_SGXDEV_INFO *psDevInfo, psCommand->ui32Data[2], psCommand->ui32Data[3])); } } - #endif + #endif /* PVRSRV_DUMP_KERNEL_CCB */ } #if defined (TTRACE) PVRSRVDumpTimeTraceBuffers(); @@ -1098,6 +1481,24 @@ static IMG_VOID SGXDumpDebugInfo (PVRSRV_SGXDEV_INFO *psDevInfo, #if defined(SYS_USING_INTERRUPTS) || defined(SUPPORT_HW_RECOVERY) +/*! +******************************************************************************* + + @Function HWRecoveryResetSGX + + @Description + + Resets SGX + + Note: may be called from an ISR so should not call pdump. + + @Input psDevInfo - dev info + + @Input ui32Component - core component to reset + + @Return IMG_VOID + +******************************************************************************/ static IMG_VOID HWRecoveryResetSGX (PVRSRV_DEVICE_NODE *psDeviceNode, IMG_UINT32 ui32Component, @@ -1106,17 +1507,25 @@ IMG_VOID HWRecoveryResetSGX (PVRSRV_DEVICE_NODE *psDeviceNode, PVRSRV_ERROR eError; PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO*)psDeviceNode->pvDevice; SGXMKIF_HOST_CTL *psSGXHostCtl = (SGXMKIF_HOST_CTL *)psDevInfo->psSGXHostCtl; - - PVR_UNREFERENCED_PARAMETER(ui32Component); - +#if defined(SUPPORT_HWRECOVERY_TRACE_LIMIT) + static IMG_UINT32 ui32Clockinus = 0; + static IMG_UINT32 ui32HWRecoveryCount=0; + IMG_UINT32 ui32TempClockinus=0; +#endif + + PVR_UNREFERENCED_PARAMETER(ui32Component); + /* + Ensure that hardware recovery is serialised with any power transitions. + */ eError = PVRSRVPowerLock(ui32CallerID, IMG_FALSE); if(eError != PVRSRV_OK) { - - - + /* + Unable to obtain lock because there is already a power transition + in progress. + */ PVR_DPF((PVR_DBG_WARNING,"HWRecoveryResetSGX: Power transition in progress")); return; } @@ -1124,47 +1533,74 @@ IMG_VOID HWRecoveryResetSGX (PVRSRV_DEVICE_NODE *psDeviceNode, psSGXHostCtl->ui32InterruptClearFlags |= PVRSRV_USSE_EDM_INTERRUPT_HWR; PVR_LOG(("HWRecoveryResetSGX: SGX Hardware Recovery triggered")); - + +#if defined(SUPPORT_HWRECOVERY_TRACE_LIMIT) +/* + * The following defines are system specific and should be defined in + * the corresponding sysconfig.h file. The values indicated are examples only. + SYS_SGX_HWRECOVERY_TRACE_RESET_TIME_PERIOD 5000000 //(5 Seconds) + SYS_SGX_MAX_HWRECOVERY_OCCURANCE_COUNT 5 + */ + ui32TempClockinus = OSClockus(); + if((ui32TempClockinus-ui32Clockinus) < SYS_SGX_HWRECOVERY_TRACE_RESET_TIME_PERIOD){ + ui32HWRecoveryCount++; + if(SYS_SGX_MAX_HWRECOVERY_OCCURANCE_COUNT <= ui32HWRecoveryCount){ + OSPanic(); + } + }else{ + ui32Clockinus = ui32TempClockinus; + SGXDumpDebugInfo(psDeviceNode->pvDevice, IMG_TRUE); + ui32HWRecoveryCount = 0; + } +#else SGXDumpDebugInfo(psDeviceNode->pvDevice, IMG_TRUE); - +#endif + /* Suspend pdumping. */ PDUMPSUSPEND(); - -#if defined(FIX_HW_BRN_23281) - - for (eError = PVRSRV_ERROR_RETRY; eError == PVRSRV_ERROR_RETRY;) -#endif - { - eError = SGXInitialise(psDevInfo, IMG_TRUE); - } + /* Reset and re-initialise SGX. */ + eError = SGXInitialise(psDevInfo, IMG_TRUE); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"HWRecoveryResetSGX: SGXInitialise failed (%d)", eError)); } - + /* Resume pdumping. */ PDUMPRESUME(); PVRSRVPowerUnlock(ui32CallerID); - + /* Send a dummy kick so that we start processing again */ SGXScheduleProcessQueuesKM(psDeviceNode); - - + /* Flush any old commands from the queues. */ PVRSRVProcessQueues(IMG_TRUE); } -#endif +#endif /* #if defined(SYS_USING_INTERRUPTS) || defined(SUPPORT_HW_RECOVERY) */ #if defined(SUPPORT_HW_RECOVERY) +/*! +****************************************************************************** + + @Function SGXOSTimer + + @Description + + Timer function for SGX + + @Input pvData - private data + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_VOID SGXOSTimer(IMG_VOID *pvData) { PVRSRV_DEVICE_NODE *psDeviceNode = pvData; PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; static IMG_UINT32 ui32EDMTasks = 0; - static IMG_UINT32 ui32LockupCounter = 0; + static IMG_UINT32 ui32LockupCounter = 0; /* To prevent false positives */ static IMG_UINT32 ui32OpenCLDelayCounter = 0; static IMG_UINT32 ui32NumResets = 0; #if defined(FIX_HW_BRN_31093) @@ -1175,17 +1611,21 @@ IMG_VOID SGXOSTimer(IMG_VOID *pvData) IMG_BOOL bLockup = IMG_FALSE; IMG_BOOL bPoweredDown; - + /* increment a timestamp */ psDevInfo->ui32TimeStamp++; #if defined(NO_HARDWARE) bPoweredDown = IMG_TRUE; #else bPoweredDown = (SGXIsDevicePowered(psDeviceNode)) ? IMG_FALSE : IMG_TRUE; -#endif +#endif /* NO_HARDWARE */ - - + /* + * Check whether EDM timer tasks are getting scheduled. If not, assume + * that SGX has locked up and reset the chip. + */ + + /* Check whether the timer should be running */ if (bPoweredDown) { ui32LockupCounter = 0; @@ -1195,7 +1635,7 @@ IMG_VOID SGXOSTimer(IMG_VOID *pvData) } else { - + /* The PDS timer should be running. */ ui32CurrentEDMTasks = OSReadHWReg(psDevInfo->pvRegsBaseKM, psDevInfo->ui32EDMTaskReg0); if (psDevInfo->ui32EDMTaskReg1 != 0) { @@ -1224,31 +1664,31 @@ IMG_VOID SGXOSTimer(IMG_VOID *pvData) #if defined(FIX_HW_BRN_31093) if (bBRN31093Inval == IMG_FALSE) { - + /* It could be a BIF hang so do a INVAL_PTE */ #if defined(FIX_HW_BRN_29997) IMG_UINT32 ui32BIFCtrl; - + /* Pause the BIF before issuing the invalidate */ ui32BIFCtrl = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL); OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32BIFCtrl | EUR_CR_BIF_CTRL_PAUSE_MASK); - + /* delay for 200 clocks */ SGXWaitClocks(psDevInfo, 200); #endif - + /* Flag that we have attempt to un-block the BIF */ bBRN31093Inval = IMG_TRUE; OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL_INVAL, EUR_CR_BIF_CTRL_INVAL_PTE_MASK); - + /* delay for 200 clocks */ SGXWaitClocks(psDevInfo, 200); #if defined(FIX_HW_BRN_29997) - + /* un-pause the BIF by restoring the BIF_CTRL */ OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32BIFCtrl); #endif } else #endif { - PVR_DPF((PVR_DBG_ERROR, "SGXOSTimer() detected SGX lockup (0x%x tasks)", ui32EDMTasks)); + PVR_DPF((PVR_DBG_ERROR, "SGXOSTimer() detected SGX lockup (0x%x tasks)", ui32EDMTasks)); bLockup = IMG_TRUE; (psDevInfo->psSGXHostCtl)->ui32OpenCLDelayCount = 0; @@ -1271,24 +1711,28 @@ SGX_NoUKernel_LockUp: { SGXMKIF_HOST_CTL *psSGXHostCtl = (SGXMKIF_HOST_CTL *)psDevInfo->psSGXHostCtl; - + /* increment the counter so we know the host detected the lockup */ psSGXHostCtl->ui32HostDetectedLockups ++; - + /* Reset the chip and process the queues. */ HWRecoveryResetSGX(psDeviceNode, 0, ISR_ID); } } -#endif +#endif /* defined(SUPPORT_HW_RECOVERY) */ + #if defined(SYS_USING_INTERRUPTS) +/* + SGX ISR Handler +*/ IMG_BOOL SGX_ISRHandler (IMG_VOID *pvData) { IMG_BOOL bInterruptProcessed = IMG_FALSE; - + /* Real Hardware */ { IMG_UINT32 ui32EventStatus, ui32EventEnable; IMG_UINT32 ui32EventClear = 0; @@ -1299,7 +1743,7 @@ IMG_BOOL SGX_ISRHandler (IMG_VOID *pvData) PVRSRV_DEVICE_NODE *psDeviceNode; PVRSRV_SGXDEV_INFO *psDevInfo; - + /* check for null pointers */ if(pvData == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "SGX_ISRHandler: Invalid params\n")); @@ -1312,18 +1756,20 @@ IMG_BOOL SGX_ISRHandler (IMG_VOID *pvData) ui32EventStatus = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_STATUS); ui32EventEnable = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_HOST_ENABLE); - + /* test only the unmasked bits */ ui32EventStatus &= ui32EventEnable; #if defined(SGX_FEATURE_DATA_BREAKPOINTS) ui32EventStatus2 = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_STATUS2); ui32EventEnable2 = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_HOST_ENABLE2); - + /* test only the unmasked bits */ ui32EventStatus2 &= ui32EventEnable2; -#endif +#endif /* defined(SGX_FEATURE_DATA_BREAKPOINTS) */ - + /* Thought: is it better to insist that the bit assignment in + the "clear" register(s) matches that of the "status" register(s)? + It would greatly simplify this LISR */ if (ui32EventStatus & EUR_CR_EVENT_STATUS_SW_EVENT_MASK) { @@ -1340,16 +1786,16 @@ IMG_BOOL SGX_ISRHandler (IMG_VOID *pvData) { ui32EventClear2 |= EUR_CR_EVENT_HOST_CLEAR2_DATA_BREAKPOINT_TRAPPED_MASK; } -#endif +#endif /* defined(SGX_FEATURE_DATA_BREAKPOINTS) */ if (ui32EventClear || ui32EventClear2) { bInterruptProcessed = IMG_TRUE; - + /* Clear master interrupt bit */ ui32EventClear |= EUR_CR_EVENT_HOST_CLEAR_MASTER_INTERRUPT_MASK; - + /* clear the events */ OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_HOST_CLEAR, ui32EventClear); OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_HOST_CLEAR2, ui32EventClear2); } @@ -1359,6 +1805,9 @@ IMG_BOOL SGX_ISRHandler (IMG_VOID *pvData) } +/* + SGX MISR Handler +*/ static IMG_VOID SGX_MISRHandler (IMG_VOID *pvData) { PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE *)pvData; @@ -1380,80 +1829,27 @@ static IMG_VOID SGX_MISRHandler (IMG_VOID *pvData) SGXTestActivePowerEvent(psDeviceNode, ISR_ID); } -#endif - - +#endif /* #if defined (SYS_USING_INTERRUPTS) */ #if defined(SUPPORT_MEMORY_TILING) + +IMG_INTERNAL PVRSRV_ERROR SGX_AllocMemTilingRange(PVRSRV_DEVICE_NODE *psDeviceNode, - PVRSRV_KERNEL_MEM_INFO *psMemInfo, - IMG_UINT32 ui32TilingStride, - IMG_UINT32 *pui32RangeIndex) + PVRSRV_KERNEL_MEM_INFO *psMemInfo, + IMG_UINT32 ui32XTileStride, + IMG_UINT32 *pui32RangeIndex) { -#if defined(SGX_FEATURE_BIF_WIDE_TILING_AND_4K_ADDRESS) - PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; - IMG_UINT32 i; - IMG_UINT32 ui32Start; - IMG_UINT32 ui32End; - IMG_UINT32 ui32Offset; - IMG_UINT32 ui32Val; - - - for(i=0; i<10; i++) - { - if((psDevInfo->ui32MemTilingUsage & (1U << i)) == 0) - { - - psDevInfo->ui32MemTilingUsage |= 1U << i; - - *pui32RangeIndex = i; - goto RangeAllocated; - } - } - - PVR_DPF((PVR_DBG_ERROR,"SGX_AllocMemTilingRange: all tiling ranges in use")); - return PVRSRV_ERROR_EXCEEDED_HW_LIMITS; - -RangeAllocated: - ui32Offset = EUR_CR_BIF_TILE0 + (i<<2); - - ui32Start = psMemInfo->sDevVAddr.uiAddr; - ui32End = ui32Start + psMemInfo->uAllocSize + SGX_MMU_PAGE_SIZE - 1; - - ui32Val = ((ui32TilingStride << EUR_CR_BIF_TILE0_CFG_SHIFT) & EUR_CR_BIF_TILE0_CFG_MASK) - | (((ui32End>>20) << EUR_CR_BIF_TILE0_MAX_ADDRESS_SHIFT) & EUR_CR_BIF_TILE0_MAX_ADDRESS_MASK) - | (((ui32Start>>20) << EUR_CR_BIF_TILE0_MIN_ADDRESS_SHIFT) & EUR_CR_BIF_TILE0_MIN_ADDRESS_MASK) - | (0x8 << EUR_CR_BIF_TILE0_CFG_SHIFT); - - - OSWriteHWReg(psDevInfo->pvRegsBaseKM, ui32Offset, ui32Val); - PDUMPREG(SGX_PDUMPREG_NAME, ui32Offset, ui32Val); - - ui32Offset = EUR_CR_BIF_TILE0_ADDR_EXT + (i<<2); - - ui32Val = (((ui32End>>12) << EUR_CR_BIF_TILE0_ADDR_EXT_MAX_SHIFT) & EUR_CR_BIF_TILE0_ADDR_EXT_MAX_MASK) - | (((ui32Start>>12) << EUR_CR_BIF_TILE0_ADDR_EXT_MIN_SHIFT) & EUR_CR_BIF_TILE0_ADDR_EXT_MIN_MASK); - - - OSWriteHWReg(psDevInfo->pvRegsBaseKM, ui32Offset, ui32Val); - PDUMPREG(SGX_PDUMPREG_NAME, ui32Offset, ui32Val); - - return PVRSRV_OK; -#else - PVR_UNREFERENCED_PARAMETER(psDeviceNode); - PVR_UNREFERENCED_PARAMETER(psMemInfo); - PVR_UNREFERENCED_PARAMETER(ui32TilingStride); - PVR_UNREFERENCED_PARAMETER(pui32RangeIndex); - - PVR_DPF((PVR_DBG_ERROR,"SGX_AllocMemTilingRange: device does not support memory tiling")); - return PVRSRV_ERROR_NOT_SUPPORTED; -#endif + return SGX_AllocMemTilingRangeInt(psDeviceNode->pvDevice, + psMemInfo->sDevVAddr.uiAddr, + psMemInfo->sDevVAddr.uiAddr + ((IMG_UINT32) psMemInfo->uAllocSize) + SGX_MMU_PAGE_SIZE - 1, + ui32XTileStride, + pui32RangeIndex); } +IMG_INTERNAL PVRSRV_ERROR SGX_FreeMemTilingRange(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_UINT32 ui32RangeIndex) { -#if defined(SGX_FEATURE_BIF_WIDE_TILING_AND_4K_ADDRESS) PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; IMG_UINT32 ui32Offset; IMG_UINT32 ui32Val; @@ -1464,27 +1860,21 @@ PVRSRV_ERROR SGX_FreeMemTilingRange(PVRSRV_DEVICE_NODE *psDeviceNode, return PVRSRV_ERROR_INVALID_PARAMS; } - + /* clear the usage bit */ psDevInfo->ui32MemTilingUsage &= ~(1<<ui32RangeIndex); - + /* disable the range */ ui32Offset = EUR_CR_BIF_TILE0 + (ui32RangeIndex<<2); ui32Val = 0; - OSWriteHWReg(psDevInfo->pvRegsBaseKM, ui32Offset, ui32Val); PDUMPREG(SGX_PDUMPREG_NAME, ui32Offset, ui32Val); return PVRSRV_OK; -#else - PVR_UNREFERENCED_PARAMETER(psDeviceNode); - PVR_UNREFERENCED_PARAMETER(ui32RangeIndex); - - PVR_DPF((PVR_DBG_ERROR,"SGX_FreeMemTilingRange: device does not support memory tiling")); - return PVRSRV_ERROR_NOT_SUPPORTED; -#endif } -#endif + +#endif /* defined(SUPPORT_MEMORY_TILING) */ + static IMG_VOID SGXCacheInvalidate(PVRSRV_DEVICE_NODE *psDeviceNode) { @@ -1494,20 +1884,34 @@ static IMG_VOID SGXCacheInvalidate(PVRSRV_DEVICE_NODE *psDeviceNode) psDevInfo->ui32CacheControl |= SGXMKIF_CC_INVAL_BIF_SL; #else PVR_UNREFERENCED_PARAMETER(psDevInfo); - #endif + #endif /* SGX_FEATURE_MP */ } +/*! +******************************************************************************* + + @Function SGXRegisterDevice + + @Description + + Registers the device with the system + + @Input: psDeviceNode - device node + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) { DEVICE_MEMORY_INFO *psDevMemoryInfo; DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; - + /* setup details that never change */ psDeviceNode->sDevId.eDeviceType = DEV_DEVICE_TYPE; psDeviceNode->sDevId.eDeviceClass = DEV_DEVICE_CLASS; #if defined(PDUMP) { - + /* memory space names are set up in system code */ SGX_DEVICE_MAP *psSGXDeviceMemMap; SysGetDeviceMemoryMap(PVRSRV_DEVICE_TYPE_SGX, (IMG_VOID**)&psSGXDeviceMemMap); @@ -1517,7 +1921,7 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) } psDeviceNode->sDevId.pszPDumpRegName = SGX_PDUMPREG_NAME; -#endif +#endif /* PDUMP */ psDeviceNode->pfnInitDevice = &DevInitSGXPart1; psDeviceNode->pfnDeInitDevice = &DevDeInitSGX; @@ -1527,8 +1931,9 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceNode->pfnPDumpInitDevice = &SGXResetPDump; psDeviceNode->pfnMMUGetContextID = &MMU_GetPDumpContextID; #endif - - + /* + MMU callbacks + */ psDeviceNode->pfnMMUInitialise = &MMU_Initialise; psDeviceNode->pfnMMUFinalise = &MMU_Finalise; psDeviceNode->pfnMMUInsertHeap = &MMU_InsertHeap; @@ -1552,9 +1957,13 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceNode->pfnMMUGetCacheFlushRange = IMG_NULL; psDeviceNode->pfnMMUGetPDPhysAddr = IMG_NULL; #endif -#if defined (SYS_USING_INTERRUPTS) - + psDeviceNode->pfnMMUMapPagesSparse = &MMU_MapPagesSparse; + psDeviceNode->pfnMMUMapShadowSparse = &MMU_MapShadowSparse; +#if defined (SYS_USING_INTERRUPTS) + /* + SGX ISR handler + */ psDeviceNode->pfnDeviceISR = SGX_ISRHandler; psDeviceNode->pfnDeviceMISR = SGX_MISRHandler; #endif @@ -1564,22 +1973,24 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceNode->pfnFreeMemTilingRange = SGX_FreeMemTilingRange; #endif - - + /* + SGX command complete handler + */ psDeviceNode->pfnDeviceCommandComplete = &SGXCommandComplete; psDeviceNode->pfnCacheInvalidate = SGXCacheInvalidate; - - + /* + and setup the device's memory map: + */ psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo; - + /* size of address space */ psDevMemoryInfo->ui32AddressSpaceSizeLog2 = SGX_FEATURE_ADDRESS_SPACE_SIZE; - + /* flags, backing store details to be specified by system */ psDevMemoryInfo->ui32Flags = 0; - + /* device memory heap info about each heap in a device address space */ if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP, sizeof(DEVICE_MEMORY_HEAP_INFO) * SGX_MAX_HEAP_ID, (IMG_VOID **)&psDevMemoryInfo->psDeviceMemoryHeap, 0, @@ -1592,10 +2003,12 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap; - + /* + setup heaps + Note: backing store to be setup by system (defaults to UMA) + */ - - + /************* general ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_GENERAL_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_GENERAL_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_GENERAL_HEAP_SIZE; @@ -1605,16 +2018,50 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceMemoryHeap->pszName = "General"; psDeviceMemoryHeap->pszBSName = "General BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; - + /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; #if !defined(SUPPORT_SGX_GENERAL_MAPPING_HEAP) - + /* specify the mapping heap ID for this device */ psDevMemoryInfo->ui32MappingHeapID = (IMG_UINT32)(psDeviceMemoryHeap - psDevMemoryInfo->psDeviceMemoryHeap); #endif - psDeviceMemoryHeap++; + psDeviceMemoryHeap++;/* advance to the next heap */ +#if defined(SUPPORT_MEMORY_TILING) + /************* VPB tiling ***************/ + psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_VPB_TILED_HEAP_ID); + psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_VPB_TILED_HEAP_BASE; + psDeviceMemoryHeap->ui32HeapSize = SGX_VPB_TILED_HEAP_SIZE; + psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE + | PVRSRV_MEM_RAM_BACKED_ALLOCATION + | PVRSRV_HAP_SINGLE_PROCESS; + psDeviceMemoryHeap->pszName = "VPB Tiled"; + psDeviceMemoryHeap->pszBSName = "VPB Tiled BS"; + psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; + /* set the default (4k). System can override these as required */ + psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; + psDeviceMemoryHeap->ui32XTileStride = SGX_VPB_TILED_HEAP_STRIDE; + PVR_DPF((PVR_DBG_WARNING, "VPB tiling heap tiling stride = 0x%x", psDeviceMemoryHeap->ui32XTileStride)); + psDeviceMemoryHeap++;/* advance to the next heap */ +#endif - +#if defined(SUPPORT_ION) + /************* Ion Heap ***************/ + psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_ION_HEAP_ID); + psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_ION_HEAP_BASE; + psDeviceMemoryHeap->ui32HeapSize = SGX_ION_HEAP_SIZE; + psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE + | PVRSRV_HAP_SINGLE_PROCESS; + psDeviceMemoryHeap->pszName = "Ion"; + psDeviceMemoryHeap->pszBSName = "Ion BS"; + psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; + /* specify the ion heap ID for this device */ + psDevMemoryInfo->ui32IonHeapID = SGX_ION_HEAP_ID; + /* set the default (4k). System can override these as required */ + psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; + psDeviceMemoryHeap++;/* advance to the next heap */ +#endif + + /************* TA data ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_TADATA_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_TADATA_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_TADATA_HEAP_SIZE; @@ -1624,12 +2071,12 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceMemoryHeap->pszName = "TA Data"; psDeviceMemoryHeap->pszBSName = "TA Data BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; - + /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; - psDeviceMemoryHeap++; + psDeviceMemoryHeap++;/* advance to the next heap */ - + /************* kernel code ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_CODE_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_KERNEL_CODE_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_KERNEL_CODE_HEAP_SIZE; @@ -1639,12 +2086,12 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceMemoryHeap->pszName = "Kernel Code"; psDeviceMemoryHeap->pszBSName = "Kernel Code BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; - + /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; - psDeviceMemoryHeap++; + psDeviceMemoryHeap++;/* advance to the next heap */ - + /************* Kernel Video Data ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_DATA_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_KERNEL_DATA_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_KERNEL_DATA_HEAP_SIZE; @@ -1654,20 +2101,21 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceMemoryHeap->pszName = "KernelData"; psDeviceMemoryHeap->pszBSName = "KernelData BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; - + /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; - psDeviceMemoryHeap++; + psDeviceMemoryHeap++;/* advance to the next heap */ - + /************* PixelShaderUSSE ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_PIXELSHADER_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_PIXELSHADER_HEAP_BASE; - - - - - - + /* + The actual size of the pixel and vertex shader heap must be such that all + addresses are within range of the one of the USSE code base registers, but + the addressable range is hardware-dependent. + SGX_PIXELSHADER_HEAP_SIZE is defined to be the maximum possible size + to ensure that the heap layout is consistent across all SGXs. + */ psDeviceMemoryHeap->ui32HeapSize = ((10 << SGX_USE_CODE_SEGMENT_RANGE_BITS) - 0x00001000); PVR_ASSERT(psDeviceMemoryHeap->ui32HeapSize <= SGX_PIXELSHADER_HEAP_SIZE); psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE @@ -1676,15 +2124,15 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceMemoryHeap->pszName = "PixelShaderUSSE"; psDeviceMemoryHeap->pszBSName = "PixelShaderUSSE BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; - + /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; - psDeviceMemoryHeap++; + psDeviceMemoryHeap++;/* advance to the next heap */ - + /************* VertexShaderUSSE ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_VERTEXSHADER_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_VERTEXSHADER_HEAP_BASE; - + /* See comment above with PixelShaderUSSE ui32HeapSize */ psDeviceMemoryHeap->ui32HeapSize = ((4 << SGX_USE_CODE_SEGMENT_RANGE_BITS) - 0x00001000); PVR_ASSERT(psDeviceMemoryHeap->ui32HeapSize <= SGX_VERTEXSHADER_HEAP_SIZE); psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE @@ -1693,12 +2141,12 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceMemoryHeap->pszName = "VertexShaderUSSE"; psDeviceMemoryHeap->pszBSName = "VertexShaderUSSE BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; - + /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; - psDeviceMemoryHeap++; + psDeviceMemoryHeap++;/* advance to the next heap */ - + /************* PDS Pixel Code/Data ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_PDSPIXEL_CODEDATA_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_PDSPIXEL_CODEDATA_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_PDSPIXEL_CODEDATA_HEAP_SIZE; @@ -1708,12 +2156,12 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceMemoryHeap->pszName = "PDSPixelCodeData"; psDeviceMemoryHeap->pszBSName = "PDSPixelCodeData BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; - + /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; - psDeviceMemoryHeap++; + psDeviceMemoryHeap++;/* advance to the next heap */ - + /************* PDS Vertex Code/Data ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_PDSVERTEX_CODEDATA_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_PDSVERTEX_CODEDATA_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_PDSVERTEX_CODEDATA_HEAP_SIZE; @@ -1723,12 +2171,12 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceMemoryHeap->pszName = "PDSVertexCodeData"; psDeviceMemoryHeap->pszBSName = "PDSVertexCodeData BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; - + /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; - psDeviceMemoryHeap++; + psDeviceMemoryHeap++;/* advance to the next heap */ - + /************* CacheCoherent ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_SYNCINFO_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_SYNCINFO_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_SYNCINFO_HEAP_SIZE; @@ -1738,14 +2186,14 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceMemoryHeap->pszName = "CacheCoherent"; psDeviceMemoryHeap->pszBSName = "CacheCoherent BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; - + /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; - + /* set the sync heap id */ psDevMemoryInfo->ui32SyncHeapID = (IMG_UINT32)(psDeviceMemoryHeap - psDevMemoryInfo->psDeviceMemoryHeap); - psDeviceMemoryHeap++; + psDeviceMemoryHeap++;/* advance to the next heap */ - + /************* Shared 3D Parameters ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_SHARED_3DPARAMETERS_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_SHARED_3DPARAMETERS_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_SHARED_3DPARAMETERS_HEAP_SIZE; @@ -1756,11 +2204,11 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) | PVRSRV_HAP_MULTI_PROCESS; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; - + /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; - psDeviceMemoryHeap++; + psDeviceMemoryHeap++;/* advance to the next heap */ - + /************* Percontext 3D Parameters ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_PERCONTEXT_3DPARAMETERS_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_PERCONTEXT_3DPARAMETERS_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_PERCONTEXT_3DPARAMETERS_HEAP_SIZE; @@ -1770,13 +2218,13 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; - + /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; - psDeviceMemoryHeap++; + psDeviceMemoryHeap++;/* advance to the next heap */ #if defined(SUPPORT_SGX_GENERAL_MAPPING_HEAP) - + /************* General Mapping ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_GENERAL_MAPPING_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_GENERAL_MAPPING_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_GENERAL_MAPPING_HEAP_SIZE; @@ -1786,28 +2234,29 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) psDeviceMemoryHeap->pszName = "GeneralMapping"; psDeviceMemoryHeap->pszBSName = "GeneralMapping BS"; #if defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) && defined(FIX_HW_BRN_23410) - - - - - - - + /* + if((2D hardware is enabled) + && (multi-mem contexts enabled) + && (BRN23410 is present)) + - then don't make the heap per-context otherwise + the TA and 2D requestors must always be aligned to + the same address space which could affect performance + */ psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; - #else + #else /* defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) && defined(FIX_HW_BRN_23410) */ psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; - #endif + #endif /* defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) && defined(FIX_HW_BRN_23410) */ - + /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; - + /* specify the mapping heap ID for this device */ psDevMemoryInfo->ui32MappingHeapID = (IMG_UINT32)(psDeviceMemoryHeap - psDevMemoryInfo->psDeviceMemoryHeap); - psDeviceMemoryHeap++; -#endif + psDeviceMemoryHeap++;/* advance to the next heap */ +#endif /* #if defined(SUPPORT_SGX_GENERAL_MAPPING_HEAP) */ #if defined(SGX_FEATURE_2D_HARDWARE) - + /************* 2D HW Heap ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_2D_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_2D_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_2D_HEAP_SIZE; @@ -1816,33 +2265,14 @@ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) | PVRSRV_HAP_SINGLE_PROCESS; psDeviceMemoryHeap->pszName = "2D"; psDeviceMemoryHeap->pszBSName = "2D BS"; - psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; - + /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; - psDeviceMemoryHeap++; -#endif - + psDeviceMemoryHeap++;/* advance to the next heap */ +#endif /* #if defined(SGX_FEATURE_2D_HARDWARE) */ -#if defined(FIX_HW_BRN_26915) - - - psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_CGBUFFER_HEAP_ID); - psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_CGBUFFER_HEAP_BASE; - psDeviceMemoryHeap->ui32HeapSize = SGX_CGBUFFER_HEAP_SIZE; - psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE - | PVRSRV_MEM_RAM_BACKED_ALLOCATION - | PVRSRV_HAP_SINGLE_PROCESS; - psDeviceMemoryHeap->pszName = "CGBuffer"; - psDeviceMemoryHeap->pszBSName = "CGBuffer BS"; - psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; - - psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; - psDeviceMemoryHeap++; -#endif - - + /* set the heap count */ psDevMemoryInfo->ui32HeapCount = (IMG_UINT32)(psDeviceMemoryHeap - psDevMemoryInfo->psDeviceMemoryHeap); return PVRSRV_OK; @@ -1858,32 +2288,64 @@ PVRSRV_ERROR SGXResetPDump(PVRSRV_DEVICE_NODE *psDeviceNode) return PVRSRV_OK; } -#endif +#endif /* PDUMP */ + + +/*! +******************************************************************************* + + @Function SGXGetClientInfoKM + + @Description Gets the client information + @Input hDevCookie + @Output psClientInfo + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR SGXGetClientInfoKM(IMG_HANDLE hDevCookie, SGX_CLIENT_INFO* psClientInfo) { PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO *)((PVRSRV_DEVICE_NODE *)hDevCookie)->pvDevice; - - + /* + If this is the first client to connect to SGX perform initialisation + */ psDevInfo->ui32ClientRefCount++; - - + /* + Copy information to the client info. + */ psClientInfo->ui32ProcessID = OSGetCurrentProcessIDKM(); - - + /* + Copy requested information. + */ OSMemCopy(&psClientInfo->asDevData, &psDevInfo->asSGXDevData, sizeof(psClientInfo->asDevData)); - + /* just return OK */ return PVRSRV_OK; } +/*! +******************************************************************************* + + @Function SGXPanic + + @Description + + Called when an unrecoverable situation is detected. Dumps SGX debug + information and tells the OS to panic. + + @Input psDevInfo - SGX device info + + @Return IMG_VOID + +******************************************************************************/ IMG_VOID SGXPanic(PVRSRV_SGXDEV_INFO *psDevInfo) { PVR_LOG(("SGX panic")); @@ -1892,6 +2354,21 @@ IMG_VOID SGXPanic(PVRSRV_SGXDEV_INFO *psDevInfo) } +/*! +******************************************************************************* + + @Function SGXDevInitCompatCheck + + @Description + + Check compatibility of host driver and microkernel (DDK and build options) + for SGX devices at services/device initialisation + + @Input psDeviceNode - device node + + @Return PVRSRV_ERROR - depending on mismatch found + +******************************************************************************/ PVRSRV_ERROR SGXDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode) { PVRSRV_ERROR eError; @@ -1899,12 +2376,12 @@ PVRSRV_ERROR SGXDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode) IMG_UINT32 ui32BuildOptions, ui32BuildOptionsMismatch; #if !defined(NO_HARDWARE) PPVRSRV_KERNEL_MEM_INFO psMemInfo; - PVRSRV_SGX_MISCINFO_INFO *psSGXMiscInfoInt; + PVRSRV_SGX_MISCINFO_INFO *psSGXMiscInfoInt; /*!< internal misc info for ukernel */ PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; - SGX_MISCINFO_STRUCT_SIZES *psSGXStructSizes; + SGX_MISCINFO_STRUCT_SIZES *psSGXStructSizes; /*!< microkernel structure sizes */ IMG_BOOL bStructSizesFailed; - + /* Exceptions list for core rev check, format is pairs of (hw rev, sw rev) */ IMG_BOOL bCheckCoreRev; const IMG_UINT32 aui32CoreRevExceptions[] = { @@ -1914,7 +2391,7 @@ PVRSRV_ERROR SGXDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode) IMG_UINT i; #endif - + /* Ensure it's a SGX device */ if(psDeviceNode->sDevId.eDeviceType != PVRSRV_DEVICE_TYPE_SGX) { PVR_LOG(("(FAIL) SGXInit: Device not of type SGX")); @@ -1924,8 +2401,16 @@ PVRSRV_ERROR SGXDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode) psDevInfo = psDeviceNode->pvDevice; - - + /* + * 1. Check kernel-side and client-side build options + * 2. Ensure ukernel DDK version and driver DDK version are compatible + * 3. Check ukernel build options against kernel-side build options + */ + + /* + * Check KM build options against client-side host driver + */ + ui32BuildOptions = (SGX_BUILD_OPTIONS); if (ui32BuildOptions != psDevInfo->ui32ClientBuildOptions) { @@ -1954,13 +2439,15 @@ PVRSRV_ERROR SGXDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode) #if !defined (NO_HARDWARE) psMemInfo = psDevInfo->psKernelSGXMiscMemInfo; - + /* Clear state (not strictly necessary since this is the first call) */ psSGXMiscInfoInt = psMemInfo->pvLinAddrKM; psSGXMiscInfoInt->ui32MiscInfoFlags = 0; psSGXMiscInfoInt->ui32MiscInfoFlags |= PVRSRV_USSE_MISCINFO_GET_STRUCT_SIZES; eError = SGXGetMiscInfoUkernel(psDevInfo, psDeviceNode, IMG_NULL); - + /* + * Validate DDK version + */ if(eError != PVRSRV_OK) { PVR_LOG(("(FAIL) SGXInit: Unable to validate device DDK version")); @@ -1976,7 +2463,6 @@ PVRSRV_ERROR SGXDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode) PVR_LOG(("(FAIL) SGXInit: Incompatible driver DDK revision (%d)/device DDK revision (%d).", PVRVERSION_BUILD, psSGXFeatures->ui32DDKBuild)); eError = PVRSRV_ERROR_DDK_VERSION_MISMATCH; - PVR_DBG_BREAK; goto chk_exit; } else @@ -1985,17 +2471,22 @@ PVRSRV_ERROR SGXDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode) PVRVERSION_BUILD, psSGXFeatures->ui32DDKBuild)); } - + /* + * Check hardware core revision is compatible with the one in software + */ if (psSGXFeatures->ui32CoreRevSW == 0) { - - + /* + Head core revision cannot be checked. + */ PVR_LOG(("SGXInit: HW core rev (%x) check skipped.", psSGXFeatures->ui32CoreRev)); } else { - + /* For some cores the hw/sw core revisions are expected not to match. For these + * exceptional cases the core rev compatibility check should be skipped. + */ bCheckCoreRev = IMG_TRUE; for(i=0; i<ui32NumCoreExceptions; i+=2) { @@ -2026,7 +2517,9 @@ PVRSRV_ERROR SGXDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode) } } - + /* + * Check ukernel structure sizes are the same as those in the driver + */ psSGXStructSizes = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->sSGXStructSizes; bStructSizesFailed = IMG_FALSE; @@ -2061,7 +2554,10 @@ PVRSRV_ERROR SGXDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode) PVR_DPF((PVR_DBG_MESSAGE, "SGXInit: SGXMKIF structure sizes match. [ OK ]")); } - + /* + * Check ukernel build options against KM host driver + */ + ui32BuildOptions = psSGXFeatures->ui32BuildOptions; if (ui32BuildOptions != (SGX_BUILD_OPTIONS)) { @@ -2086,7 +2582,7 @@ PVRSRV_ERROR SGXDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode) { PVR_DPF((PVR_DBG_MESSAGE, "SGXInit: Driver and microkernel build options match. [ OK ]")); } -#endif +#endif // NO_HARDWARE eError = PVRSRV_OK; chk_exit: @@ -2097,16 +2593,27 @@ chk_exit: #endif } +/* + * @Function SGXGetMiscInfoUkernel + * + * @Description Returns misc info (e.g. SGX build info/flags) from microkernel + * + * @Input psDevInfo : device info from init phase + * @Input psDeviceNode : device node, used for scheduling ukernel to query SGX features + * + * @Return PVRSRV_ERROR : + * + */ static PVRSRV_ERROR SGXGetMiscInfoUkernel(PVRSRV_SGXDEV_INFO *psDevInfo, PVRSRV_DEVICE_NODE *psDeviceNode, IMG_HANDLE hDevMemContext) { PVRSRV_ERROR eError; - SGXMKIF_COMMAND sCommandData; - PVRSRV_SGX_MISCINFO_INFO *psSGXMiscInfoInt; - PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; - SGX_MISCINFO_STRUCT_SIZES *psSGXStructSizes; + SGXMKIF_COMMAND sCommandData; /* CCB command data */ + PVRSRV_SGX_MISCINFO_INFO *psSGXMiscInfoInt; /*!< internal misc info for ukernel */ + PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; /*!< sgx features for client */ + SGX_MISCINFO_STRUCT_SIZES *psSGXStructSizes; /*!< internal info: microkernel structure sizes */ PPVRSRV_KERNEL_MEM_INFO psMemInfo = psDevInfo->psKernelSGXMiscMemInfo; @@ -2121,12 +2628,12 @@ PVRSRV_ERROR SGXGetMiscInfoUkernel(PVRSRV_SGXDEV_INFO *psDevInfo, psSGXMiscInfoInt->ui32MiscInfoFlags &= ~PVRSRV_USSE_MISCINFO_READY; - + /* Reset SGX features */ OSMemSet(psSGXFeatures, 0, sizeof(*psSGXFeatures)); OSMemSet(psSGXStructSizes, 0, sizeof(*psSGXStructSizes)); - - sCommandData.ui32Data[1] = psMemInfo->sDevVAddr.uiAddr; + /* set up buffer address for SGX features in CCB */ + sCommandData.ui32Data[1] = psMemInfo->sDevVAddr.uiAddr; /* device V addr of output buffer */ PDUMPCOMMENT("Microkernel kick for SGXGetMiscInfo"); eError = SGXScheduleCCBCommandKM(psDeviceNode, @@ -2143,7 +2650,9 @@ PVRSRV_ERROR SGXGetMiscInfoUkernel(PVRSRV_SGXDEV_INFO *psDevInfo, return eError; } - + /* FIXME: DWORD value to determine code path in ukernel? + * E.g. could use getMiscInfo to obtain register values for diagnostics? */ + #if !defined(NO_HARDWARE) { IMG_BOOL bExit; @@ -2158,20 +2667,33 @@ PVRSRV_ERROR SGXGetMiscInfoUkernel(PVRSRV_SGXDEV_INFO *psDevInfo, } } END_LOOP_UNTIL_TIMEOUT(); - + /*if the loop exited because a timeout*/ if (!bExit) { PVR_DPF((PVR_DBG_ERROR, "SGXGetMiscInfoUkernel: Timeout occurred waiting for misc info.")); return PVRSRV_ERROR_TIMEOUT; } } -#endif +#endif /* NO_HARDWARE */ return PVRSRV_OK; } +/* + * @Function SGXGetMiscInfoKM + * + * @Description Returns miscellaneous SGX info + * + * @Input psDevInfo : device info from init phase + * @Input psDeviceNode : device node, used for scheduling ukernel to query SGX features + * + * @Output psMiscInfo : query request plus user-mode mem for holding returned data + * + * @Return PVRSRV_ERROR : + * + */ IMG_EXPORT PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, SGX_MISC_INFO *psMiscInfo, @@ -2182,7 +2704,7 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, PPVRSRV_KERNEL_MEM_INFO psMemInfo = psDevInfo->psKernelSGXMiscMemInfo; IMG_UINT32 *pui32MiscInfoFlags = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->ui32MiscInfoFlags; - + /* Reset the misc info state flags */ *pui32MiscInfoFlags = 0; #if !defined(SUPPORT_SGX_EDM_MEMORY_DEBUG) @@ -2203,14 +2725,14 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32EndRegVal; SGXMKIF_COMMAND sCommandData; - + /* Set or Clear BP? */ if(psMiscInfo->uData.sSGXBreakpointInfo.bBPEnable) { - + /* set the break point */ IMG_DEV_VIRTADDR sBPDevVAddr = psMiscInfo->uData.sSGXBreakpointInfo.sBPDevVAddr; IMG_DEV_VIRTADDR sBPDevVAddrEnd = psMiscInfo->uData.sSGXBreakpointInfo.sBPDevVAddrEnd; - + /* BP address */ ui32StartRegVal = sBPDevVAddr.uiAddr & EUR_CR_BREAKPOINT0_START_ADDRESS_MASK; ui32EndRegVal = sBPDevVAddrEnd.uiAddr & EUR_CR_BREAKPOINT0_END_ADDRESS_MASK; @@ -2219,7 +2741,7 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, ui32CtrlREnable = psMiscInfo->uData.sSGXBreakpointInfo.bRead; ui32CtrlTrapEnable = psMiscInfo->uData.sSGXBreakpointInfo.bTrapped; - + /* normal data BP */ ui32RegVal = ((ui32MaskDM<<EUR_CR_BREAKPOINT0_MASK_DM_SHIFT) & EUR_CR_BREAKPOINT0_MASK_DM_MASK) | ((ui32CtrlWEnable<<EUR_CR_BREAKPOINT0_CTRL_WENABLE_SHIFT) & EUR_CR_BREAKPOINT0_CTRL_WENABLE_MASK) | ((ui32CtrlREnable<<EUR_CR_BREAKPOINT0_CTRL_RENABLE_SHIFT) & EUR_CR_BREAKPOINT0_CTRL_RENABLE_MASK) | @@ -2227,17 +2749,17 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, } else { - + /* clear the break point */ ui32RegVal = ui32StartRegVal = ui32EndRegVal = 0; } - + /* setup the command */ sCommandData.ui32Data[0] = psMiscInfo->uData.sSGXBreakpointInfo.ui32BPIndex; sCommandData.ui32Data[1] = ui32StartRegVal; sCommandData.ui32Data[2] = ui32EndRegVal; sCommandData.ui32Data[3] = ui32RegVal; - + /* clear signal flags */ psDevInfo->psSGXHostCtl->ui32BPSetClearSignal = 0; PDUMPCOMMENT("Microkernel kick for setting a data breakpoint"); @@ -2256,7 +2778,7 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, } #if defined(NO_HARDWARE) - + /* clear signal flags */ psDevInfo->psSGXHostCtl->ui32BPSetClearSignal = 0; #else { @@ -2268,43 +2790,46 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, if (psDevInfo->psSGXHostCtl->ui32BPSetClearSignal != 0) { bExit = IMG_TRUE; - + /* clear signal flags */ psDevInfo->psSGXHostCtl->ui32BPSetClearSignal = 0; break; } } END_LOOP_UNTIL_TIMEOUT(); - + /*if the loop exited because a timeout*/ if (!bExit) { PVR_DPF((PVR_DBG_ERROR, "SGXGetMiscInfoKM: Timeout occurred waiting BP set/clear")); return PVRSRV_ERROR_TIMEOUT; } } -#endif +#endif /* NO_HARDWARE */ return PVRSRV_OK; } case SGX_MISC_INFO_REQUEST_POLL_BREAKPOINT: { - - - - - - - + /* This request checks to see whether a breakpoint has + been trapped. If so, it returns the number of the + breakpoint number that was trapped in ui32BPIndex, + sTrappedBPDevVAddr to the address which was trapped, + and sets bTrappedBP. Otherwise, bTrappedBP will be + false, and other fields should be ignored. */ + /* The uKernel is not used, since if we are stopped on a + breakpoint, it is not possible to guarantee that the + uKernel would be able to run */ #if !defined(NO_HARDWARE) #if defined(SGX_FEATURE_MP) IMG_BOOL bTrappedBPMaster; IMG_UINT32 ui32CoreNum, ui32TrappedBPCoreNum; #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) IMG_UINT32 ui32PipeNum, ui32TrappedBPPipeNum; +/* ui32PipeNum is the pipe number plus 1, or 0 to represent "partition" */ #define NUM_PIPES_PLUS_ONE (SGX_FEATURE_PERPIPE_BKPT_REGS_NUMPIPES+1) #endif IMG_BOOL bTrappedBPAny; -#endif +#endif /* defined(SGX_FEATURE_MP) */ IMG_BOOL bFoundOne; #if defined(SGX_FEATURE_MP) @@ -2312,14 +2837,15 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, bTrappedBPMaster = !!(EUR_CR_MASTER_BREAKPOINT_TRAPPED_MASK & OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_BREAKPOINT)); bTrappedBPAny = bTrappedBPMaster; #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) - ui32TrappedBPPipeNum = 0; + ui32TrappedBPPipeNum = 0; /* just to keep the (incorrect) compiler happy */ #endif for (ui32CoreNum = 0; ui32CoreNum < SGX_FEATURE_MP_CORE_COUNT_3D; ui32CoreNum++) { #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) - - - + /* FIXME: this macro makes the assumption that the PARTITION regs are the same + distance before the PIPE0 regs as the PIPE1 regs are after it, _and_ + assumes that the fields in the partition regs are in the same place + in the pipe regs. Need to validate these assumptions, or assert them */ #define SGX_MP_CORE_PIPE_SELECT(r,c,p) \ ((SGX_MP_CORE_SELECT(EUR_CR_PARTITION_##r,c) + p*(EUR_CR_PIPE0_##r-EUR_CR_PARTITION_##r))) for (ui32PipeNum = 0; ui32PipeNum < NUM_PIPES_PLUS_ONE; ui32PipeNum++) @@ -2337,23 +2863,23 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, ui32TrappedBPPipeNum = ui32PipeNum; } } -#else +#else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ bFoundOne = !!(EUR_CR_BREAKPOINT_TRAPPED_MASK & OSReadHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_SELECT(EUR_CR_BREAKPOINT, ui32CoreNum))); if (bFoundOne) { bTrappedBPAny = IMG_TRUE; ui32TrappedBPCoreNum = ui32CoreNum; } -#endif +#endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ } psMiscInfo->uData.sSGXBreakpointInfo.bTrappedBP = bTrappedBPAny; -#else +#else /* defined(SGX_FEATURE_MP) */ #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) #error Not yet considered the case for per-pipe regs in non-mp case #endif psMiscInfo->uData.sSGXBreakpointInfo.bTrappedBP = 0 != (EUR_CR_BREAKPOINT_TRAPPED_MASK & OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BREAKPOINT)); -#endif +#endif /* defined(SGX_FEATURE_MP) */ if (psMiscInfo->uData.sSGXBreakpointInfo.bTrappedBP) { @@ -2363,14 +2889,14 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) ui32Info0 = OSReadHWReg(psDevInfo->pvRegsBaseKM, bTrappedBPMaster?EUR_CR_MASTER_BREAKPOINT_TRAP_INFO0:SGX_MP_CORE_PIPE_SELECT(BREAKPOINT_TRAP_INFO0, ui32TrappedBPCoreNum, ui32TrappedBPPipeNum)); ui32Info1 = OSReadHWReg(psDevInfo->pvRegsBaseKM, bTrappedBPMaster?EUR_CR_MASTER_BREAKPOINT_TRAP_INFO1:SGX_MP_CORE_PIPE_SELECT(BREAKPOINT_TRAP_INFO1, ui32TrappedBPCoreNum, ui32TrappedBPPipeNum)); -#else +#else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ ui32Info0 = OSReadHWReg(psDevInfo->pvRegsBaseKM, bTrappedBPMaster?EUR_CR_MASTER_BREAKPOINT_TRAP_INFO0:SGX_MP_CORE_SELECT(EUR_CR_BREAKPOINT_TRAP_INFO0, ui32TrappedBPCoreNum)); ui32Info1 = OSReadHWReg(psDevInfo->pvRegsBaseKM, bTrappedBPMaster?EUR_CR_MASTER_BREAKPOINT_TRAP_INFO1:SGX_MP_CORE_SELECT(EUR_CR_BREAKPOINT_TRAP_INFO1, ui32TrappedBPCoreNum)); -#endif -#else +#endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ +#else /* defined(SGX_FEATURE_MP) */ ui32Info0 = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BREAKPOINT_TRAP_INFO0); ui32Info1 = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BREAKPOINT_TRAP_INFO1); -#endif +#endif /* defined(SGX_FEATURE_MP) */ #ifdef SGX_FEATURE_PERPIPE_BKPT_REGS psMiscInfo->uData.sSGXBreakpointInfo.ui32BPIndex = (ui32Info1 & EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_NUMBER_MASK) >> EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_NUMBER_SHIFT; @@ -2379,41 +2905,41 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, psMiscInfo->uData.sSGXBreakpointInfo.bTrappedBPRead = !!(ui32Info1 & EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_RNW_MASK); psMiscInfo->uData.sSGXBreakpointInfo.ui32TrappedBPDataMaster = (ui32Info1 & EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_DATA_MASTER_MASK) >> EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_DATA_MASTER_SHIFT; psMiscInfo->uData.sSGXBreakpointInfo.ui32TrappedBPTag = (ui32Info1 & EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_TAG_MASK) >> EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_TAG_SHIFT; -#else +#else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ psMiscInfo->uData.sSGXBreakpointInfo.ui32BPIndex = (ui32Info1 & EUR_CR_BREAKPOINT_TRAP_INFO1_NUMBER_MASK) >> EUR_CR_BREAKPOINT_TRAP_INFO1_NUMBER_SHIFT; psMiscInfo->uData.sSGXBreakpointInfo.sTrappedBPDevVAddr.uiAddr = ui32Info0 & EUR_CR_BREAKPOINT_TRAP_INFO0_ADDRESS_MASK; psMiscInfo->uData.sSGXBreakpointInfo.ui32TrappedBPBurstLength = (ui32Info1 & EUR_CR_BREAKPOINT_TRAP_INFO1_SIZE_MASK) >> EUR_CR_BREAKPOINT_TRAP_INFO1_SIZE_SHIFT; psMiscInfo->uData.sSGXBreakpointInfo.bTrappedBPRead = !!(ui32Info1 & EUR_CR_BREAKPOINT_TRAP_INFO1_RNW_MASK); psMiscInfo->uData.sSGXBreakpointInfo.ui32TrappedBPDataMaster = (ui32Info1 & EUR_CR_BREAKPOINT_TRAP_INFO1_DATA_MASTER_MASK) >> EUR_CR_BREAKPOINT_TRAP_INFO1_DATA_MASTER_SHIFT; psMiscInfo->uData.sSGXBreakpointInfo.ui32TrappedBPTag = (ui32Info1 & EUR_CR_BREAKPOINT_TRAP_INFO1_TAG_MASK) >> EUR_CR_BREAKPOINT_TRAP_INFO1_TAG_SHIFT; -#endif +#endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ #if defined(SGX_FEATURE_MP) #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) - + /* mp, per-pipe regbanks */ psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum = bTrappedBPMaster?65535:(ui32TrappedBPCoreNum + (ui32TrappedBPPipeNum<<10)); -#else - +#else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ + /* mp, regbanks unsplit */ psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum = bTrappedBPMaster?65535:ui32TrappedBPCoreNum; -#endif -#else +#endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ +#else /* defined(SGX_FEATURE_MP) */ #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) - + /* non-mp, per-pipe regbanks */ #error non-mp perpipe regs not yet supported -#else - +#else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ + /* non-mp */ psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum = 65534; -#endif -#endif +#endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ +#endif /* defined(SGX_FEATURE_MP) */ } -#endif +#endif /* !defined(NO_HARDWARE) */ return PVRSRV_OK; } case SGX_MISC_INFO_REQUEST_RESUME_BREAKPOINT: { - - - + /* This request resumes from the currently trapped breakpoint. */ + /* Core number must be supplied */ + /* Polls for notify to be acknowledged by h/w */ #if !defined(NO_HARDWARE) #if defined(SGX_FEATURE_MP) IMG_UINT32 ui32CoreNum; @@ -2421,7 +2947,7 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) IMG_UINT32 ui32PipeNum; #endif -#endif +#endif /* defined(SGX_FEATURE_MP) */ IMG_UINT32 ui32OldSeqNum, ui32NewSeqNum; #if defined(SGX_FEATURE_MP) @@ -2429,14 +2955,14 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, ui32PipeNum = psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum >> 10; ui32CoreNum = psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum & 1023; bMaster = psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum > 32767; -#else +#else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ ui32CoreNum = psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum; bMaster = ui32CoreNum > SGX_FEATURE_MP_CORE_COUNT_3D; -#endif +#endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ if (bMaster) { - - + /* master */ + /* EUR_CR_MASTER_BREAKPOINT_TRAPPED_MASK | EUR_CR_MASTER_BREAKPOINT_SEQNUM_MASK */ ui32OldSeqNum = 0x1c & OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_BREAKPOINT); OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_BREAKPOINT_TRAP, EUR_CR_MASTER_BREAKPOINT_TRAP_WRNOTIFY_MASK | EUR_CR_MASTER_BREAKPOINT_TRAP_CONTINUE_MASK); do @@ -2446,9 +2972,9 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, while (ui32OldSeqNum == ui32NewSeqNum); } else -#endif +#endif /* defined(SGX_FEATURE_MP) */ { - + /* core */ #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) ui32OldSeqNum = 0x1c & OSReadHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_PIPE_SELECT(BREAKPOINT, ui32CoreNum, ui32PipeNum)); OSWriteHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_PIPE_SELECT(BREAKPOINT_TRAP, ui32CoreNum, ui32PipeNum), EUR_CR_PARTITION_BREAKPOINT_TRAP_WRNOTIFY_MASK | EUR_CR_PARTITION_BREAKPOINT_TRAP_CONTINUE_MASK); @@ -2457,7 +2983,7 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, ui32NewSeqNum = 0x1c & OSReadHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_PIPE_SELECT(BREAKPOINT, ui32CoreNum, ui32PipeNum)); } while (ui32OldSeqNum == ui32NewSeqNum); -#else +#else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ ui32OldSeqNum = 0x1c & OSReadHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_SELECT(EUR_CR_BREAKPOINT, ui32CoreNum)); OSWriteHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_SELECT(EUR_CR_BREAKPOINT_TRAP, ui32CoreNum), EUR_CR_BREAKPOINT_TRAP_WRNOTIFY_MASK | EUR_CR_BREAKPOINT_TRAP_CONTINUE_MASK); do @@ -2465,12 +2991,12 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, ui32NewSeqNum = 0x1c & OSReadHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_SELECT(EUR_CR_BREAKPOINT, ui32CoreNum)); } while (ui32OldSeqNum == ui32NewSeqNum); -#endif +#endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ } -#endif +#endif /* !defined(NO_HARDWARE) */ return PVRSRV_OK; } -#endif +#endif /* SGX_FEATURE_DATA_BREAKPOINTS) */ case SGX_MISC_INFO_REQUEST_CLOCKSPEED: { @@ -2498,13 +3024,15 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, case SGX_MISC_INFO_REQUEST_SPM: { - + /* this is dealt with in UM */ return PVRSRV_OK; } case SGX_MISC_INFO_REQUEST_SGXREV: { PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; +// PPVRSRV_KERNEL_MEM_INFO psMemInfo = psDevInfo->psKernelSGXMiscMemInfo; + eError = SGXGetMiscInfoUkernel(psDevInfo, psDeviceNode, hDevMemContext); if(eError != PVRSRV_OK) { @@ -2514,10 +3042,10 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, } psSGXFeatures = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->sSGXFeatures; - + /* Copy SGX features into misc info struct, to return to client */ psMiscInfo->uData.sSGXFeatures = *psSGXFeatures; - + /* Debug output */ PVR_DPF((PVR_DBG_MESSAGE, "SGXGetMiscInfoKM: Core 0x%x, sw ID 0x%x, sw Rev 0x%x\n", psSGXFeatures->ui32CoreRev, psSGXFeatures->ui32CoreIdSW, @@ -2526,7 +3054,7 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, psSGXFeatures->ui32DDKVersion, psSGXFeatures->ui32DDKBuild)); - + /* done! */ return PVRSRV_OK; } @@ -2536,7 +3064,9 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, psSGXFeatures = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->sSGXFeatures; - + /* Reset the misc information to prevent + * confusion with values returned from the ukernel + */ OSMemSet(psMemInfo->pvLinAddrKM, 0, sizeof(PVRSRV_SGX_MISCINFO_INFO)); @@ -2546,16 +3076,16 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, PVRVERSION_BRANCH; psSGXFeatures->ui32DDKBuild = PVRVERSION_BUILD; - + /* Also report the kernel module build options -- used in SGXConnectionCheck() */ psSGXFeatures->ui32BuildOptions = (SGX_BUILD_OPTIONS); #if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) - + /* Report the EDM status buffer location in memory */ psSGXFeatures->sDevVAEDMStatusBuffer = psDevInfo->psKernelEDMStatusBufferMemInfo->sDevVAddr; psSGXFeatures->pvEDMStatusBuffer = psDevInfo->psKernelEDMStatusBufferMemInfo->pvLinAddrKM; #endif - + /* Copy SGX features into misc info struct, to return to client */ psMiscInfo->uData.sSGXFeatures = *psSGXFeatures; return PVRSRV_OK; } @@ -2566,17 +3096,17 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, { PVRSRV_ERROR eError; PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; - PVRSRV_SGX_MISCINFO_MEMACCESS *psSGXMemSrc; - PVRSRV_SGX_MISCINFO_MEMACCESS *psSGXMemDest; + PVRSRV_SGX_MISCINFO_MEMACCESS *psSGXMemSrc; /* user-defined mem read */ + PVRSRV_SGX_MISCINFO_MEMACCESS *psSGXMemDest; /* user-defined mem write */ { - + /* Set the mem read flag; src is user-defined */ *pui32MiscInfoFlags |= PVRSRV_USSE_MISCINFO_MEMREAD; psSGXMemSrc = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->sSGXMemAccessSrc; if(psMiscInfo->sDevVAddrSrc.uiAddr != 0) { - psSGXMemSrc->sDevVAddr = psMiscInfo->sDevVAddrSrc; + psSGXMemSrc->sDevVAddr = psMiscInfo->sDevVAddrSrc; /* src address */ } else { @@ -2586,13 +3116,13 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, if( psMiscInfo->eRequest == SGX_MISC_INFO_REQUEST_MEMCOPY) { - + /* Set the mem write flag; dest is user-defined */ *pui32MiscInfoFlags |= PVRSRV_USSE_MISCINFO_MEMWRITE; psSGXMemDest = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->sSGXMemAccessDest; if(psMiscInfo->sDevVAddrDest.uiAddr != 0) { - psSGXMemDest->sDevVAddr = psMiscInfo->sDevVAddrDest; + psSGXMemDest->sDevVAddr = psMiscInfo->sDevVAddrDest; /* dest address */ } else { @@ -2600,12 +3130,12 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, } } - + /* Get physical address of PD for memory read (may need to switch context in microkernel) */ if(psMiscInfo->hDevMemContext != IMG_NULL) { SGXGetMMUPDAddrKM( (IMG_HANDLE)psDeviceNode, hDevMemContext, &psSGXMemSrc->sPDDevPAddr); - + /* Single app will always use the same src and dest mem context */ psSGXMemDest->sPDDevPAddr = psSGXMemSrc->sPDDevPAddr; } else @@ -2613,7 +3143,7 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, return PVRSRV_ERROR_INVALID_PARAMS; } - + /* Submit the task to the ukernel */ eError = SGXGetMiscInfoUkernel(psDevInfo, psDeviceNode); if(eError != PVRSRV_OK) { @@ -2629,11 +3159,11 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, return PVRSRV_ERROR_INVALID_MISCINFO; } #endif - + /* Copy SGX features into misc info struct, to return to client */ psMiscInfo->uData.sSGXFeatures = *psSGXFeatures; return PVRSRV_OK; } -#endif +#endif /* SUPPORT_SGX_EDM_MEMORY_DEBUG */ #if defined(SUPPORT_SGX_HWPERF) case SGX_MISC_INFO_REQUEST_SET_HWPERF_STATUS: @@ -2645,7 +3175,7 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, PVRSRV_SGX_HWPERF_STATUS_MK_EXECUTION_ON; SGXMKIF_COMMAND sCommandData = {0}; - + /* Check for valid flags */ if ((psSetHWPerfStatus->ui32NewHWPerfStatus & ~ui32ValidFlags) != 0) { return PVRSRV_ERROR_INVALID_PARAMS; @@ -2655,9 +3185,9 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "SGX ukernel HWPerf status %u\n", psSetHWPerfStatus->ui32NewHWPerfStatus); - #endif + #endif /* PDUMP */ - + /* Copy the new group selector(s) to the host ctl for the ukernel */ #if defined(SGX_FEATURE_EXTENDED_PERF_COUNTERS) OSMemCopy(&psDevInfo->psSGXHostCtl->aui32PerfGroup[0], &psSetHWPerfStatus->aui32PerfGroup[0], @@ -2665,6 +3195,8 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, OSMemCopy(&psDevInfo->psSGXHostCtl->aui32PerfBit[0], &psSetHWPerfStatus->aui32PerfBit[0], sizeof(psDevInfo->psSGXHostCtl->aui32PerfBit)); + psDevInfo->psSGXHostCtl->ui32PerfCounterBitSelect = psSetHWPerfStatus->ui32PerfCounterBitSelect; + psDevInfo->psSGXHostCtl->ui32PerfSumMux = psSetHWPerfStatus->ui32PerfSumMux; #if defined(PDUMP) PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo, offsetof(SGXMKIF_HOST_CTL, aui32PerfGroup), @@ -2676,7 +3208,17 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, sizeof(psDevInfo->psSGXHostCtl->aui32PerfBit), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); - #endif + PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo, + offsetof(SGXMKIF_HOST_CTL, ui32PerfCounterBitSelect), + sizeof(psDevInfo->psSGXHostCtl->ui32PerfCounterBitSelect), + PDUMP_FLAGS_CONTINUOUS, + MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); + PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo, + offsetof(SGXMKIF_HOST_CTL, ui32PerfSumMux), + sizeof(psDevInfo->psSGXHostCtl->ui32PerfSumMux), + PDUMP_FLAGS_CONTINUOUS, + MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); + #endif /* PDUMP */ #else psDevInfo->psSGXHostCtl->ui32PerfGroup = psSetHWPerfStatus->ui32PerfGroup; #if defined(PDUMP) @@ -2685,10 +3227,10 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, sizeof(psDevInfo->psSGXHostCtl->ui32PerfGroup), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); - #endif - #endif + #endif /* PDUMP */ + #endif /* SGX_FEATURE_EXTENDED_PERF_COUNTERS */ - + /* Kick the ukernel to update the hardware state */ sCommandData.ui32Data[0] = psSetHWPerfStatus->ui32NewHWPerfStatus; eError = SGXScheduleCCBCommandKM(psDeviceNode, SGXMKIF_CMD_SETHWPERFSTATUS, @@ -2699,18 +3241,30 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_FALSE); return eError; } -#endif +#endif /* SUPPORT_SGX_HWPERF */ case SGX_MISC_INFO_DUMP_DEBUG_INFO: { PVR_LOG(("User requested SGX debug info")); - + /* Dump SGX debug data to the kernel log. */ SGXDumpDebugInfo(psDeviceNode->pvDevice, IMG_FALSE); return PVRSRV_OK; } + case SGX_MISC_INFO_DUMP_DEBUG_INFO_FORCE_REGS: + { + PVR_LOG(("User requested SGX debug info")); + + /* Dump SGX debug data to the kernel log. */ + SGXDumpDebugInfo(psDeviceNode->pvDevice, IMG_TRUE); + + return PVRSRV_OK; + } + +#if defined(DEBUG) + /* Don't allow user-mode to reboot the device in production drivers */ case SGX_MISC_INFO_PANIC: { PVR_LOG(("User requested SGX panic")); @@ -2719,10 +3273,11 @@ PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, return PVRSRV_OK; } +#endif default: { - + /* switch statement fell though, so: */ return PVRSRV_ERROR_INVALID_PARAMS; } } @@ -2777,3 +3332,6 @@ PVRSRV_ERROR SGXReadHWPerfCBKM(IMG_HANDLE hDevHandle, } +/****************************************************************************** + End of file (sgxinit.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/devices/sgx/sgxkick.c b/sgx/services4/srvkm/devices/sgx/sgxkick.c index d1220cf..5d74251 100644 --- a/sgx/services4/srvkm/devices/sgx/sgxkick.c +++ b/sgx/services4/srvkm/devices/sgx/sgxkick.c @@ -1,30 +1,46 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ - -#include <stddef.h> +/*************************************************************************/ /*! +@Title Device specific kickTA routines +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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> /* For the macro offsetof() */ #include "services_headers.h" #include "sgxinfo.h" #include "sgxinfokm.h" @@ -38,6 +54,20 @@ #include "sgxutils.h" #include "ttrace.h" +/*! +****************************************************************************** + + @Function SGXDoKickKM + + @Description + + Really kicks the TA + + @Input hDevHandle - Device handle + + @Return ui32Error - success or failure + +******************************************************************************/ IMG_EXPORT #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK_KM *psCCBKick) @@ -62,15 +92,15 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) PVR_TTRACE(PVRSRV_TRACE_GROUP_KICK, PVRSRV_TRACE_CLASS_FUNCTION_EXIT, KICK_TOKEN_DOKICK); return PVRSRV_ERROR_INVALID_PARAMS; } - - + /* override QAC warning about stricter alignment */ + /* PRQA S 3305 1 */ psTACmd = CCB_DATA_FROM_OFFSET(SGXMKIF_CMDTA_SHARED, psCCBMemInfo, psCCBKick, ui32CCBOffset); PVR_TTRACE(PVRSRV_TRACE_GROUP_KICK, PVRSRV_TRACE_CLASS_CMD_START, KICK_TOKEN_DOKICK); PVR_TTRACE_UI32(PVRSRV_TRACE_GROUP_KICK, PVRSRV_TRACE_CLASS_CCB, KICK_TOKEN_CCB_OFFSET, psCCBKick->ui32CCBOffset); - + /* TA/3D dependency */ if (psCCBKick->hTA3DSyncInfo) { psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *)psCCBKick->hTA3DSyncInfo; @@ -119,7 +149,7 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) psTACmd->ui32NumTAStatusVals = psCCBKick->ui32NumTAStatusVals; if (psCCBKick->ui32NumTAStatusVals != 0) { - + /* Copy status vals over */ for (i = 0; i < psCCBKick->ui32NumTAStatusVals; i++) { #if defined(SUPPORT_SGX_NEW_STATUS_VALS) @@ -135,7 +165,7 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) psTACmd->ui32Num3DStatusVals = psCCBKick->ui32Num3DStatusVals; if (psCCBKick->ui32Num3DStatusVals != 0) { - + /* Copy status vals over */ for (i = 0; i < psCCBKick->ui32Num3DStatusVals; i++) { #if defined(SUPPORT_SGX_NEW_STATUS_VALS) @@ -150,7 +180,7 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) #if defined(SUPPORT_SGX_GENERALISED_SYNCOBJECTS) - + /* SRC and DST sync dependencies */ psTACmd->ui32NumTASrcSyncs = psCCBKick->ui32NumTASrcSyncs; for (i=0; i<psCCBKick->ui32NumTASrcSyncs; i++) { @@ -159,9 +189,9 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) psTACmd->asTASrcSyncs[i].sWriteOpsCompleteDevVAddr = psSyncInfo->sWriteOpsCompleteDevVAddr; psTACmd->asTASrcSyncs[i].sReadOpsCompleteDevVAddr = psSyncInfo->sReadOpsCompleteDevVAddr; - + /* Get ui32ReadOpsPending snapshot and copy into the CCB - before incrementing. */ psTACmd->asTASrcSyncs[i].ui32ReadOpsPendingVal = psSyncInfo->psSyncData->ui32ReadOpsPending++; - + /* Copy ui32WriteOpsPending snapshot into the CCB. */ psTACmd->asTASrcSyncs[i].ui32WriteOpsPendingVal = psSyncInfo->psSyncData->ui32WriteOpsPending; } @@ -173,9 +203,9 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) psTACmd->asTADstSyncs[i].sWriteOpsCompleteDevVAddr = psSyncInfo->sWriteOpsCompleteDevVAddr; psTACmd->asTADstSyncs[i].sReadOpsCompleteDevVAddr = psSyncInfo->sReadOpsCompleteDevVAddr; - + /* Get ui32ReadOpsPending snapshot and copy into the CCB */ psTACmd->asTADstSyncs[i].ui32ReadOpsPendingVal = psSyncInfo->psSyncData->ui32ReadOpsPending; - + /* Copy ui32WriteOpsPending snapshot into the CCB - before incrementing */ psTACmd->asTADstSyncs[i].ui32WriteOpsPendingVal = psSyncInfo->psSyncData->ui32WriteOpsPending++; } @@ -187,13 +217,13 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) psTACmd->as3DSrcSyncs[i].sWriteOpsCompleteDevVAddr = psSyncInfo->sWriteOpsCompleteDevVAddr; psTACmd->as3DSrcSyncs[i].sReadOpsCompleteDevVAddr = psSyncInfo->sReadOpsCompleteDevVAddr; - + /* Get ui32ReadOpsPending snapshot and copy into the CCB - before incrementing. */ psTACmd->as3DSrcSyncs[i].ui32ReadOpsPendingVal = psSyncInfo->psSyncData->ui32ReadOpsPending++; - + /* Copy ui32WriteOpsPending snapshot into the CCB. */ psTACmd->as3DSrcSyncs[i].ui32WriteOpsPendingVal = psSyncInfo->psSyncData->ui32WriteOpsPending; } -#else - +#else /* SUPPORT_SGX_GENERALISED_SYNCOBJECTS */ + /* texture dependencies */ psTACmd->ui32NumSrcSyncs = psCCBKick->ui32NumSrcSyncs; for (i=0; i<psCCBKick->ui32NumSrcSyncs; i++) { @@ -205,12 +235,12 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) psTACmd->asSrcSyncs[i].sWriteOpsCompleteDevVAddr = psSyncInfo->sWriteOpsCompleteDevVAddr; psTACmd->asSrcSyncs[i].sReadOpsCompleteDevVAddr = psSyncInfo->sReadOpsCompleteDevVAddr; - + /* Get ui32ReadOpsPending snapshot and copy into the CCB - before incrementing. */ psTACmd->asSrcSyncs[i].ui32ReadOpsPendingVal = psSyncInfo->psSyncData->ui32ReadOpsPending++; - + /* Copy ui32WriteOpsPending snapshot into the CCB. */ psTACmd->asSrcSyncs[i].ui32WriteOpsPendingVal = psSyncInfo->psSyncData->ui32WriteOpsPending; } -#endif +#endif/* SUPPORT_SGX_GENERALISED_SYNCOBJECTS */ if (psCCBKick->bFirstKickOrResume && psCCBKick->ui32NumDstSyncObjects > 0) { @@ -242,15 +272,18 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) if (psSyncInfo) { + psSyncInfo->psSyncData->ui64LastWrite = ui64KickCount; PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_KICK, KICK_TOKEN_DST_SYNC, psSyncInfo, PVRSRV_SYNCOP_SAMPLE); psHWDeviceSyncList->asSyncData[i].sWriteOpsCompleteDevVAddr = psSyncInfo->sWriteOpsCompleteDevVAddr; psHWDeviceSyncList->asSyncData[i].sReadOpsCompleteDevVAddr = psSyncInfo->sReadOpsCompleteDevVAddr; + psHWDeviceSyncList->asSyncData[i].sReadOps2CompleteDevVAddr = psSyncInfo->sReadOps2CompleteDevVAddr; psHWDeviceSyncList->asSyncData[i].ui32ReadOpsPendingVal = psSyncInfo->psSyncData->ui32ReadOpsPending; psHWDeviceSyncList->asSyncData[i].ui32WriteOpsPendingVal = psSyncInfo->psSyncData->ui32WriteOpsPending++; + psHWDeviceSyncList->asSyncData[i].ui32ReadOps2PendingVal = psSyncInfo->psSyncData->ui32ReadOps2Pending; #if defined(PDUMP) if (PDumpIsCaptureFrameKM()) @@ -262,6 +295,8 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) + offsetof(PVRSRV_DEVICE_SYNC_OBJECT, ui32WriteOpsPendingVal); IMG_UINT32 ui32ROpsOffset = ui32SyncOffset + offsetof(PVRSRV_DEVICE_SYNC_OBJECT, ui32ReadOpsPendingVal); + IMG_UINT32 ui32ROps2Offset = ui32SyncOffset + + offsetof(PVRSRV_DEVICE_SYNC_OBJECT, ui32ReadOps2PendingVal); PDUMPCOMMENT("HWDeviceSyncObject for RT: %i\r\n", i); @@ -275,7 +310,9 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) if ((psSyncInfo->psSyncData->ui32LastOpDumpVal == 0) && (psSyncInfo->psSyncData->ui32LastReadOpDumpVal == 0)) { - + /* + * Init the ROpsComplete value to 0. + */ PDUMPCOMMENT("Init RT ROpsComplete\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastReadOpDumpVal, psSyncInfo->psSyncDataMemInfoKM, @@ -283,7 +320,9 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) sizeof(psSyncInfo->psSyncData->ui32ReadOpsComplete), 0, MAKEUNIQUETAG(psSyncInfo->psSyncDataMemInfoKM)); - + /* + * Init the WOpsComplete value to 0. + */ PDUMPCOMMENT("Init RT WOpsComplete\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, psSyncInfo->psSyncDataMemInfoKM, @@ -315,23 +354,37 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) sizeof(IMG_UINT32), 0, MAKEUNIQUETAG(psHWDstSyncListMemInfo)); + + /* + * Force the ROps2Complete value to 0. + */ + PDUMPCOMMENT("Modify RT %d ROps2PendingVal in HWDevSyncList\r\n", i); + PDUMPMEM(&ui32ModifiedValue, + psHWDstSyncListMemInfo, + ui32ROps2Offset, + sizeof(IMG_UINT32), + 0, + MAKEUNIQUETAG(psHWDstSyncListMemInfo)); } - #endif + #endif /* defined(PDUMP) */ } else { psHWDeviceSyncList->asSyncData[i].sWriteOpsCompleteDevVAddr.uiAddr = 0; psHWDeviceSyncList->asSyncData[i].sReadOpsCompleteDevVAddr.uiAddr = 0; + psHWDeviceSyncList->asSyncData[i].sReadOps2CompleteDevVAddr.uiAddr = 0; psHWDeviceSyncList->asSyncData[i].ui32ReadOpsPendingVal = 0; + psHWDeviceSyncList->asSyncData[i].ui32ReadOps2PendingVal = 0; psHWDeviceSyncList->asSyncData[i].ui32WriteOpsPendingVal = 0; } } } - - - + /* + NOTE: THIS MUST BE THE LAST THING WRITTEN TO THE TA COMMAND! + Set the ready for so the uKernel will process the command. + */ psTACmd->ui32CtrlFlags |= SGXMKIF_CMDTA_CTRLFLAGS_READY; #if defined(PDUMP) @@ -355,7 +408,9 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) if ((psSyncInfo->psSyncData->ui32LastOpDumpVal == 0) && (psSyncInfo->psSyncData->ui32LastReadOpDumpVal == 0)) { - + /* + * Init the ROpsComplete value to 0. + */ PDUMPCOMMENT("Init RT TA-SRC ROpsComplete\r\n", i); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastReadOpDumpVal, psSyncInfo->psSyncDataMemInfoKM, @@ -363,7 +418,9 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) sizeof(psSyncInfo->psSyncData->ui32ReadOpsComplete), 0, MAKEUNIQUETAG(psSyncInfo->psSyncDataMemInfoKM)); - + /* + * Init the WOpsComplete value to 0. + */ PDUMPCOMMENT("Init RT TA-SRC WOpsComplete\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, psSyncInfo->psSyncDataMemInfoKM, @@ -406,7 +463,9 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) if ((psSyncInfo->psSyncData->ui32LastOpDumpVal == 0) && (psSyncInfo->psSyncData->ui32LastReadOpDumpVal == 0)) { - + /* + * Init the ROpsComplete value to 0. + */ PDUMPCOMMENT("Init RT TA-DST ROpsComplete\r\n", i); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastReadOpDumpVal, psSyncInfo->psSyncDataMemInfoKM, @@ -414,7 +473,9 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) sizeof(psSyncInfo->psSyncData->ui32ReadOpsComplete), 0, MAKEUNIQUETAG(psSyncInfo->psSyncDataMemInfoKM)); - + /* + * Init the WOpsComplete value to 0. + */ PDUMPCOMMENT("Init RT TA-DST WOpsComplete\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, psSyncInfo->psSyncDataMemInfoKM, @@ -457,7 +518,9 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) if ((psSyncInfo->psSyncData->ui32LastOpDumpVal == 0) && (psSyncInfo->psSyncData->ui32LastReadOpDumpVal == 0)) { - + /* + * Init the ROpsComplete value to 0. + */ PDUMPCOMMENT("Init RT 3D-SRC ROpsComplete\r\n", i); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastReadOpDumpVal, psSyncInfo->psSyncDataMemInfoKM, @@ -465,7 +528,9 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) sizeof(psSyncInfo->psSyncData->ui32ReadOpsComplete), 0, MAKEUNIQUETAG(psSyncInfo->psSyncDataMemInfoKM)); - + /* + * Init the WOpsComplete value to 0. + */ PDUMPCOMMENT("Init RT 3D-SRC WOpsComplete\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, psSyncInfo->psSyncDataMemInfoKM, @@ -499,7 +564,7 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) 0, MAKEUNIQUETAG(psCCBMemInfo)); } -#else +#else/* SUPPORT_SGX_GENERALISED_SYNCOBJECTS */ for (i=0; i<psCCBKick->ui32NumSrcSyncs; i++) { IMG_UINT32 ui32ModifiedValue; @@ -508,7 +573,9 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) if ((psSyncInfo->psSyncData->ui32LastOpDumpVal == 0) && (psSyncInfo->psSyncData->ui32LastReadOpDumpVal == 0)) { - + /* + * Init the ROpsComplete value to 0. + */ PDUMPCOMMENT("Init RT ROpsComplete\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastReadOpDumpVal, psSyncInfo->psSyncDataMemInfoKM, @@ -516,7 +583,9 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) sizeof(psSyncInfo->psSyncData->ui32ReadOpsComplete), 0, MAKEUNIQUETAG(psSyncInfo->psSyncDataMemInfoKM)); - + /* + * Init the WOpsComplete value to 0. + */ PDUMPCOMMENT("Init RT WOpsComplete\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, psSyncInfo->psSyncDataMemInfoKM, @@ -524,6 +593,16 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) sizeof(psSyncInfo->psSyncData->ui32WriteOpsComplete), 0, MAKEUNIQUETAG(psSyncInfo->psSyncDataMemInfoKM)); + /* + * Init the ROps2Complete value to 0. + */ + PDUMPCOMMENT("Init RT WOpsComplete\r\n"); + PDUMPMEM(&psSyncInfo->psSyncData->ui32LastReadOpDumpVal, + psSyncInfo->psSyncDataMemInfoKM, + offsetof(PVRSRV_SYNC_DATA, ui32ReadOps2Complete), + sizeof(psSyncInfo->psSyncData->ui32ReadOps2Complete), + 0, + MAKEUNIQUETAG(psSyncInfo->psSyncDataMemInfoKM)); } psSyncInfo->psSyncData->ui32LastReadOpDumpVal++; @@ -581,7 +660,7 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) psSyncInfo->psSyncData->ui32LastReadOpDumpVal++; } -#endif +#endif/* SUPPORT_SGX_GENERALISED_SYNCOBJECTS */ for (i = 0; i < psCCBKick->ui32NumTAStatusVals; i++) { @@ -611,7 +690,7 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) #endif } } -#endif +#endif /* defined(PDUMP) */ PVR_TTRACE(PVRSRV_TRACE_GROUP_KICK, PVRSRV_TRACE_CLASS_CMD_END, KICK_TOKEN_DOKICK); @@ -623,7 +702,7 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) { for (i=0; i < psCCBKick->ui32NumDstSyncObjects; i++) { - + /* Client will retry, so undo the write ops pending increment done above. */ psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *)psCCBKick->pahDstSyncHandles[i]; if (psSyncInfo) @@ -655,13 +734,13 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *) psCCBKick->ah3DSrcKernelSyncInfo[i]; psSyncInfo->psSyncData->ui32ReadOpsPending--; } -#else +#else/* SUPPORT_SGX_GENERALISED_SYNCOBJECTS */ for (i=0; i<psCCBKick->ui32NumSrcSyncs; i++) { psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *) psCCBKick->ahSrcKernelSyncInfo[i]; psSyncInfo->psSyncData->ui32ReadOpsPending--; } -#endif +#endif/* SUPPORT_SGX_GENERALISED_SYNCOBJECTS */ PVR_TTRACE(PVRSRV_TRACE_GROUP_KICK, PVRSRV_TRACE_CLASS_FUNCTION_EXIT, KICK_TOKEN_DOKICK); @@ -679,7 +758,7 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) #if defined(NO_HARDWARE) - + /* TA/3D dependency */ if (psCCBKick->hTA3DSyncInfo) { psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *)psCCBKick->hTA3DSyncInfo; @@ -704,12 +783,12 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) psSyncInfo->psSyncData->ui32ReadOpsComplete = psSyncInfo->psSyncData->ui32ReadOpsPending; } - + /* Copy status vals over */ for (i = 0; i < psCCBKick->ui32NumTAStatusVals; i++) { #if defined(SUPPORT_SGX_NEW_STATUS_VALS) PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo = (PVRSRV_KERNEL_MEM_INFO*)psCCBKick->asTAStatusUpdate[i].hKernelMemInfo; - + /* derive offset into meminfo and write the status value */ *(IMG_UINT32*)((IMG_UINTPTR_T)psKernelMemInfo->pvLinAddrKM + (psTACmd->sCtlTAStatusInfo[i].sStatusDevAddr.uiAddr - psKernelMemInfo->sDevVAddr.uiAddr)) = psTACmd->sCtlTAStatusInfo[i].ui32StatusValue; @@ -720,7 +799,7 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) } #if defined(SUPPORT_SGX_GENERALISED_SYNCOBJECTS) - + /* SRC and DST dependencies */ for (i=0; i<psCCBKick->ui32NumTASrcSyncs; i++) { psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *) psCCBKick->ahTASrcKernelSyncInfo[i]; @@ -736,14 +815,14 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *) psCCBKick->ah3DSrcKernelSyncInfo[i]; psSyncInfo->psSyncData->ui32ReadOpsComplete = psSyncInfo->psSyncData->ui32ReadOpsPending; } -#else - +#else/* SUPPORT_SGX_GENERALISED_SYNCOBJECTS */ + /* texture dependencies */ for (i=0; i<psCCBKick->ui32NumSrcSyncs; i++) { psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *) psCCBKick->ahSrcKernelSyncInfo[i]; psSyncInfo->psSyncData->ui32ReadOpsComplete = psSyncInfo->psSyncData->ui32ReadOpsPending; } -#endif +#endif/* SUPPORT_SGX_GENERALISED_SYNCOBJECTS */ if (psCCBKick->bTerminateOrAbort) { @@ -761,12 +840,12 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) } } - + /* Copy status vals over */ for (i = 0; i < psCCBKick->ui32Num3DStatusVals; i++) { #if defined(SUPPORT_SGX_NEW_STATUS_VALS) PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo = (PVRSRV_KERNEL_MEM_INFO*)psCCBKick->as3DStatusUpdate[i].hKernelMemInfo; - + /* derive offset into meminfo and write the status value */ *(IMG_UINT32*)((IMG_UINTPTR_T)psKernelMemInfo->pvLinAddrKM + (psTACmd->sCtl3DStatusInfo[i].sStatusDevAddr.uiAddr - psKernelMemInfo->sDevVAddr.uiAddr)) = psTACmd->sCtl3DStatusInfo[i].ui32StatusValue; @@ -782,3 +861,6 @@ PVRSRV_ERROR SGXDoKickKM(IMG_HANDLE hDevHandle, SGX_CCB_KICK *psCCBKick) return eError; } +/****************************************************************************** + End of file (sgxkick.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/devices/sgx/sgxpower.c b/sgx/services4/srvkm/devices/sgx/sgxpower.c index 3947cdd..3e7aa6c 100644 --- a/sgx/services4/srvkm/devices/sgx/sgxpower.c +++ b/sgx/services4/srvkm/devices/sgx/sgxpower.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Device specific power routines +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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> @@ -39,9 +55,10 @@ static PVRSRV_ERROR SGXAddTimer(PVRSRV_DEVICE_NODE *psDeviceNode, SGX_TIMING_INFORMATION *psSGXTimingInfo, IMG_HANDLE *phTimer) { - - - + /* + Install timer callback for HW recovery at 50 times lower + frequency than the microkernel timer. + */ *phTimer = OSAddTimer(SGXOSTimer, psDeviceNode, 1000 * 50 / psSGXTimingInfo->ui32uKernelFreq); if(*phTimer == IMG_NULL) @@ -52,9 +69,23 @@ static PVRSRV_ERROR SGXAddTimer(PVRSRV_DEVICE_NODE *psDeviceNode, return PVRSRV_OK; } -#endif +#endif /* SUPPORT_HW_RECOVERY*/ + + +/*! +****************************************************************************** + + @Function SGXUpdateTimingInfo + + @Description + + Derives the microkernel timing info from the system-supplied values + @Input psDeviceNode : SGX Device node + @Return PVRSRV_ERROR : + +******************************************************************************/ static PVRSRV_ERROR SGXUpdateTimingInfo(PVRSRV_DEVICE_NODE *psDeviceNode) { PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; @@ -86,8 +117,9 @@ static PVRSRV_ERROR SGXUpdateTimingInfo(PVRSRV_DEVICE_NODE *psDeviceNode) ui32OlduKernelFreq = psDevInfo->ui32CoreClockSpeed / psDevInfo->ui32uKernelTimerClock; if (ui32OlduKernelFreq != psSGXTimingInfo->ui32uKernelFreq) { - - + /* + The ukernel timer frequency has changed. + */ IMG_HANDLE hNewTimer; eError = SGXAddTimer(psDeviceNode, psSGXTimingInfo, &hNewTimer); @@ -102,7 +134,7 @@ static PVRSRV_ERROR SGXUpdateTimingInfo(PVRSRV_DEVICE_NODE *psDeviceNode) } else { - + /* Failed to allocate the new timer, leave the old one. */ } } } @@ -118,13 +150,13 @@ static PVRSRV_ERROR SGXUpdateTimingInfo(PVRSRV_DEVICE_NODE *psDeviceNode) psDevInfo->psSGXHostCtl->ui32HWRecoverySampleRate = psSGXTimingInfo->ui32uKernelFreq / psSGXTimingInfo->ui32HWRecoveryFreq; } -#endif +#endif /* SUPPORT_HW_RECOVERY*/ - + /* Copy the SGX clock speed for use in the kernel */ psDevInfo->ui32CoreClockSpeed = psSGXTimingInfo->ui32CoreClockSpeed; psDevInfo->ui32uKernelTimerClock = psSGXTimingInfo->ui32CoreClockSpeed / psSGXTimingInfo->ui32uKernelFreq; - + /* FIXME: no need to duplicate - remove it from psDevInfo */ psDevInfo->psSGXHostCtl->ui32uKernelTimerClock = psDevInfo->ui32uKernelTimerClock; #if defined(PDUMP) PDUMPCOMMENT("Host Control - Microkernel clock"); @@ -132,19 +164,20 @@ static PVRSRV_ERROR SGXUpdateTimingInfo(PVRSRV_DEVICE_NODE *psDeviceNode) offsetof(SGXMKIF_HOST_CTL, ui32uKernelTimerClock), sizeof(IMG_UINT32), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); -#endif +#endif /* PDUMP */ if (psSGXTimingInfo->bEnableActivePM) { ui32ActivePowManSampleRate = psSGXTimingInfo->ui32uKernelFreq * psSGXTimingInfo->ui32ActivePowManLatencyms / 1000; - - - - - - - + /* + ui32ActivePowerCounter has the value 0 when SGX is not idle. + When SGX becomes idle, the value of ui32ActivePowerCounter is changed from 0 to ui32ActivePowManSampleRate. + The ukernel timer routine decrements the value of ui32ActivePowerCounter if it is not 0. + When the ukernel timer decrements ui32ActivePowerCounter from 1 to 0, the ukernel timer will + request power down. + Therefore the minimum value of ui32ActivePowManSampleRate is 1. + */ ui32ActivePowManSampleRate += 1; } else @@ -158,12 +191,26 @@ static PVRSRV_ERROR SGXUpdateTimingInfo(PVRSRV_DEVICE_NODE *psDeviceNode) offsetof(SGXMKIF_HOST_CTL, ui32ActivePowManSampleRate), sizeof(IMG_UINT32), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); -#endif +#endif /* PDUMP */ return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function SGXStartTimer + + @Description + + Start the microkernel timer + + @Input psDevInfo : SGX Device Info + + @Return IMG_VOID : + +******************************************************************************/ static IMG_VOID SGXStartTimer(PVRSRV_SGXDEV_INFO *psDevInfo) { #if defined(SUPPORT_HW_RECOVERY) @@ -176,10 +223,27 @@ static IMG_VOID SGXStartTimer(PVRSRV_SGXDEV_INFO *psDevInfo) } #else PVR_UNREFERENCED_PARAMETER(psDevInfo); - #endif + #endif /* SUPPORT_HW_RECOVERY */ } +/*! +****************************************************************************** + + @Function SGXPollForClockGating + + @Description + + Wait until the SGX core clocks have gated. + + @Input psDevInfo : SGX Device Info + @Input ui32Register : Offset of register to poll + @Input ui32Register : Value of register to poll for + @Input pszComment : Description of poll + + @Return IMG_VOID : + +******************************************************************************/ static IMG_VOID SGXPollForClockGating (PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32Register, IMG_UINT32 ui32RegisterValue, @@ -193,7 +257,7 @@ static IMG_VOID SGXPollForClockGating (PVRSRV_SGXDEV_INFO *psDevInfo, #if !defined(NO_HARDWARE) PVR_ASSERT(psDevInfo != IMG_NULL); - + /* PRQA S 0505 1 */ /* QAC does not like assert() */ if (PollForValueKM((IMG_UINT32 *)psDevInfo->pvRegsBaseKM + (ui32Register >> 2), 0, ui32RegisterValue, @@ -202,15 +266,32 @@ static IMG_VOID SGXPollForClockGating (PVRSRV_SGXDEV_INFO *psDevInfo, IMG_FALSE) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"SGXPollForClockGating: %s failed.", pszComment)); + SGXDumpDebugInfo(psDevInfo, IMG_FALSE); PVR_DBG_BREAK; } - #endif + #endif /* NO_HARDWARE */ PDUMPCOMMENT("%s", pszComment); PDUMPREGPOL(SGX_PDUMPREG_NAME, ui32Register, 0, ui32RegisterValue, PDUMP_POLL_OPERATOR_EQUAL); } +/*! +****************************************************************************** + + @Function SGXPrePowerState + + @Description + + does necessary preparation before power state transition + + @Input hDevHandle : SGX Device Node + @Input eNewPowerState : New power state + @Input eCurrentPowerState : Current power state + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR SGXPrePowerState (IMG_HANDLE hDevHandle, PVRSRV_DEV_POWER_STATE eNewPowerState, PVRSRV_DEV_POWER_STATE eCurrentPowerState) @@ -227,25 +308,25 @@ PVRSRV_ERROR SGXPrePowerState (IMG_HANDLE hDevHandle, IMG_UINT32 ui32CoresEnabled; #if defined(SUPPORT_HW_RECOVERY) - + /* Disable timer callback for HW recovery */ eError = OSDisableTimer(psDevInfo->hTimer); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"SGXPrePowerState: Failed to disable timer")); return eError; } - #endif + #endif /* SUPPORT_HW_RECOVERY */ if (eNewPowerState == PVRSRV_DEV_POWER_STATE_OFF) { - + /* Request the ukernel to idle SGX and save its state. */ ui32PowerCmd = PVRSRV_POWERCMD_POWEROFF; ui32CompleteStatus = PVRSRV_USSE_EDM_POWMAN_POWEROFF_COMPLETE; PDUMPCOMMENT("SGX power off request"); } else { - + /* Request the ukernel to idle SGX. */ ui32PowerCmd = PVRSRV_POWERCMD_IDLE; ui32CompleteStatus = PVRSRV_USSE_EDM_POWMAN_IDLE_COMPLETE; PDUMPCOMMENT("SGX idle request"); @@ -260,7 +341,7 @@ PVRSRV_ERROR SGXPrePowerState (IMG_HANDLE hDevHandle, return eError; } - + /* Wait for the ukernel to complete processing. */ #if !defined(NO_HARDWARE) if (PollForValueKM(&psDevInfo->psSGXHostCtl->ui32PowerStatus, ui32CompleteStatus, @@ -270,9 +351,10 @@ PVRSRV_ERROR SGXPrePowerState (IMG_HANDLE hDevHandle, IMG_FALSE) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"SGXPrePowerState: Wait for SGX ukernel power transition failed.")); + SGXDumpDebugInfo(psDevInfo, IMG_FALSE); PVR_DBG_BREAK; } - #endif + #endif /* NO_HARDWARE */ #if defined(PDUMP) PDUMPCOMMENT("TA/3D CCB Control - Wait for power event on uKernel."); @@ -283,7 +365,7 @@ PVRSRV_ERROR SGXPrePowerState (IMG_HANDLE hDevHandle, PDUMP_POLL_OPERATOR_EQUAL, 0, MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); - #endif + #endif /* PDUMP */ #if defined(SGX_FEATURE_MP) ui32CoresEnabled = ((OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_CORE) & EUR_CR_MASTER_CORE_ENABLE_MASK) >> EUR_CR_MASTER_CORE_ENABLE_SHIFT) + 1; @@ -293,7 +375,7 @@ PVRSRV_ERROR SGXPrePowerState (IMG_HANDLE hDevHandle, for (ui32Core = 0; ui32Core < ui32CoresEnabled; ui32Core++) { - + /* Wait for SGX clock gating. */ SGXPollForClockGating(psDevInfo, SGX_MP_CORE_SELECT(psDevInfo->ui32ClkGateStatusReg, ui32Core), psDevInfo->ui32ClkGateStatusMask, @@ -301,7 +383,7 @@ PVRSRV_ERROR SGXPrePowerState (IMG_HANDLE hDevHandle, } #if defined(SGX_FEATURE_MP) - + /* Wait for SGX master clock gating. */ SGXPollForClockGating(psDevInfo, psDevInfo->ui32MasterClkGateStatusReg, psDevInfo->ui32MasterClkGateStatusMask, @@ -311,11 +393,11 @@ PVRSRV_ERROR SGXPrePowerState (IMG_HANDLE hDevHandle, psDevInfo->ui32MasterClkGateStatus2Reg, psDevInfo->ui32MasterClkGateStatus2Mask, "Wait for SGX master clock gating (2)"); - #endif + #endif /* SGX_FEATURE_MP */ if (eNewPowerState == PVRSRV_DEV_POWER_STATE_OFF) { - + /* Finally, de-initialise some registers. */ eError = SGXDeinitialise(psDevInfo); if (eError != PVRSRV_OK) { @@ -329,6 +411,22 @@ PVRSRV_ERROR SGXPrePowerState (IMG_HANDLE hDevHandle, } +/*! +****************************************************************************** + + @Function SGXPostPowerState + + @Description + + does necessary preparation after power state transition + + @Input hDevHandle : SGX Device Node + @Input eNewPowerState : New power state + @Input eCurrentPowerState : Current power state + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR SGXPostPowerState (IMG_HANDLE hDevHandle, PVRSRV_DEV_POWER_STATE eNewPowerState, PVRSRV_DEV_POWER_STATE eCurrentPowerState) @@ -341,7 +439,7 @@ PVRSRV_ERROR SGXPostPowerState (IMG_HANDLE hDevHandle, PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; SGXMKIF_HOST_CTL *psSGXHostCtl = psDevInfo->psSGXHostCtl; - + /* Reset the power manager flags. */ psSGXHostCtl->ui32PowerStatus = 0; #if defined(PDUMP) PDUMPCOMMENT("Host Control - Reset power status"); @@ -349,14 +447,17 @@ PVRSRV_ERROR SGXPostPowerState (IMG_HANDLE hDevHandle, offsetof(SGXMKIF_HOST_CTL, ui32PowerStatus), sizeof(IMG_UINT32), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); - #endif + #endif /* PDUMP */ if (eCurrentPowerState == PVRSRV_DEV_POWER_STATE_OFF) { - - - + /* + Coming up from off, re-initialise SGX. + */ + /* + Re-generate the timing data required by SGX. + */ eError = SGXUpdateTimingInfo(psDeviceNode); if (eError != PVRSRV_OK) { @@ -364,8 +465,9 @@ PVRSRV_ERROR SGXPostPowerState (IMG_HANDLE hDevHandle, return eError; } - - + /* + Run the SGX init script. + */ eError = SGXInitialise(psDevInfo, IMG_FALSE); if (eError != PVRSRV_OK) { @@ -375,8 +477,9 @@ PVRSRV_ERROR SGXPostPowerState (IMG_HANDLE hDevHandle, } else { - - + /* + Coming up from idle, restart the ukernel. + */ SGXMKIF_COMMAND sCommand = {0}; sCommand.ui32Data[1] = PVRSRV_POWERCMD_RESUME; @@ -395,6 +498,22 @@ PVRSRV_ERROR SGXPostPowerState (IMG_HANDLE hDevHandle, } +/*! +****************************************************************************** + + @Function SGXPreClockSpeedChange + + @Description + + Does processing required before an SGX clock speed change. + + @Input hDevHandle : SGX Device Node + @Input bIdleDevice : Whether the microkernel needs to be idled + @Input eCurrentPowerState : Power state of the device + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR SGXPreClockSpeedChange (IMG_HANDLE hDevHandle, IMG_BOOL bIdleDevice, PVRSRV_DEV_POWER_STATE eCurrentPowerState) @@ -409,7 +528,9 @@ PVRSRV_ERROR SGXPreClockSpeedChange (IMG_HANDLE hDevHandle, { if (bIdleDevice) { - + /* + * Idle SGX. + */ PDUMPSUSPEND(); eError = SGXPrePowerState(hDevHandle, PVRSRV_DEV_POWER_STATE_IDLE, @@ -430,6 +551,22 @@ PVRSRV_ERROR SGXPreClockSpeedChange (IMG_HANDLE hDevHandle, } +/*! +****************************************************************************** + + @Function SGXPostClockSpeedChange + + @Description + + Does processing required after an SGX clock speed change. + + @Input hDevHandle : SGX Device Node + @Input bIdleDevice : Whether the microkernel had been idled previously + @Input eCurrentPowerState : Power state of the device + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR SGXPostClockSpeedChange (IMG_HANDLE hDevHandle, IMG_BOOL bIdleDevice, PVRSRV_DEV_POWER_STATE eCurrentPowerState) @@ -444,8 +581,9 @@ PVRSRV_ERROR SGXPostClockSpeedChange (IMG_HANDLE hDevHandle, { PVRSRV_ERROR eError; - - + /* + Re-generate the timing data required by SGX. + */ eError = SGXUpdateTimingInfo(psDeviceNode); if (eError != PVRSRV_OK) { @@ -455,7 +593,9 @@ PVRSRV_ERROR SGXPostClockSpeedChange (IMG_HANDLE hDevHandle, if (bIdleDevice) { - + /* + * Resume SGX. + */ eError = SGXPostPowerState(hDevHandle, PVRSRV_DEV_POWER_STATE_ON, PVRSRV_DEV_POWER_STATE_IDLE); @@ -479,3 +619,6 @@ PVRSRV_ERROR SGXPostClockSpeedChange (IMG_HANDLE hDevHandle, } +/****************************************************************************** + End of file (sgxpower.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/devices/sgx/sgxreset.c b/sgx/services4/srvkm/devices/sgx/sgxreset.c index 519783f..35b63c9 100644 --- a/sgx/services4/srvkm/devices/sgx/sgxreset.c +++ b/sgx/services4/srvkm/devices/sgx/sgxreset.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Device specific reset routines +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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 "sgxdefs.h" #include "sgxmmu.h" @@ -34,6 +50,20 @@ #include "pdump_km.h" +/*! +******************************************************************************* + + @Function SGXInitClocks + + @Description + Initialise the SGX clocks + + @Input psDevInfo - device info. structure + @Input ui32PDUMPFlags - flags to control PDUMP output + + @Return IMG_VOID + +******************************************************************************/ IMG_VOID SGXInitClocks(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32PDUMPFlags) { @@ -41,7 +71,7 @@ IMG_VOID SGXInitClocks(PVRSRV_SGXDEV_INFO *psDevInfo, #if !defined(PDUMP) PVR_UNREFERENCED_PARAMETER(ui32PDUMPFlags); -#endif +#endif /* PDUMP */ ui32RegVal = psDevInfo->ui32ClkGateCtl; OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_CLKGATECTL, ui32RegVal); @@ -55,6 +85,19 @@ IMG_VOID SGXInitClocks(PVRSRV_SGXDEV_INFO *psDevInfo, } +/*! +******************************************************************************* + + @Function SGXResetInitBIFContexts + + @Description + Initialise the BIF memory contexts + + @Input psDevInfo - SGX Device Info + + @Return IMG_VOID + +******************************************************************************/ static IMG_VOID SGXResetInitBIFContexts(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32PDUMPFlags) { @@ -62,7 +105,7 @@ static IMG_VOID SGXResetInitBIFContexts(PVRSRV_SGXDEV_INFO *psDevInfo, #if !defined(PDUMP) PVR_UNREFERENCED_PARAMETER(ui32PDUMPFlags); -#endif +#endif /* PDUMP */ ui32RegVal = 0; OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32RegVal); @@ -74,7 +117,7 @@ static IMG_VOID SGXResetInitBIFContexts(PVRSRV_SGXDEV_INFO *psDevInfo, PDUMPREGWITHFLAGS(SGX_PDUMPREG_NAME, EUR_CR_BIF_BANK_SET, ui32RegVal, ui32PDUMPFlags); OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_BANK0, ui32RegVal); PDUMPREGWITHFLAGS(SGX_PDUMPREG_NAME, EUR_CR_BIF_BANK0, ui32RegVal, ui32PDUMPFlags); -#endif +#endif /* SGX_FEATURE_MULTIPLE_MEM_CONTEXTS */ PDUMPCOMMENTWITHFLAGS(ui32PDUMPFlags, "Initialise the BIF directory list\r\n"); OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_DIR_LIST_BASE0, ui32RegVal); @@ -93,10 +136,23 @@ static IMG_VOID SGXResetInitBIFContexts(PVRSRV_SGXDEV_INFO *psDevInfo, PDUMPREGWITHFLAGS(SGX_PDUMPREG_NAME, ui32DirListReg, ui32RegVal, ui32PDUMPFlags); } } -#endif +#endif /* SGX_FEATURE_MULTIPLE_MEM_CONTEXTS */ } +/*! +******************************************************************************* + + @Function SGXResetSetupBIFContexts + + @Description + Configure the BIF for the EDM context + + @Input psDevInfo - SGX Device Info + + @Return IMG_VOID + +******************************************************************************/ static IMG_VOID SGXResetSetupBIFContexts(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32PDUMPFlags) { @@ -104,37 +160,37 @@ static IMG_VOID SGXResetSetupBIFContexts(PVRSRV_SGXDEV_INFO *psDevInfo, #if !defined(PDUMP) PVR_UNREFERENCED_PARAMETER(ui32PDUMPFlags); -#endif +#endif /* PDUMP */ #if defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) - + /* Set up EDM for bank 0 to point at kernel context */ ui32RegVal = (SGX_BIF_DIR_LIST_INDEX_EDM << EUR_CR_BIF_BANK0_INDEX_EDM_SHIFT); #if defined(SGX_FEATURE_2D_HARDWARE) && !defined(SGX_FEATURE_PTLA) - + /* Set up 2D core for bank 0 to point at kernel context */ ui32RegVal |= (SGX_BIF_DIR_LIST_INDEX_EDM << EUR_CR_BIF_BANK0_INDEX_2D_SHIFT); - #endif + #endif /* SGX_FEATURE_2D_HARDWARE */ #if defined(FIX_HW_BRN_23410) - + /* Set up TA core for bank 0 to point at kernel context to guarantee it is a valid context */ ui32RegVal |= (SGX_BIF_DIR_LIST_INDEX_EDM << EUR_CR_BIF_BANK0_INDEX_TA_SHIFT); - #endif + #endif /* FIX_HW_BRN_23410 */ OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_BANK0, ui32RegVal); PDUMPCOMMENTWITHFLAGS(ui32PDUMPFlags, "Set up EDM requestor page table in BIF\r\n"); PDUMPREGWITHFLAGS(SGX_PDUMPREG_NAME, EUR_CR_BIF_BANK0, ui32RegVal, ui32PDUMPFlags); - #endif + #endif /* defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) */ { IMG_UINT32 ui32EDMDirListReg; - + /* Set up EDM context with kernel page directory */ #if (SGX_BIF_DIR_LIST_INDEX_EDM == 0) ui32EDMDirListReg = EUR_CR_BIF_DIR_LIST_BASE0; #else - + /* Bases 0 and 1 are not necessarily contiguous */ ui32EDMDirListReg = EUR_CR_BIF_DIR_LIST_BASE1 + 4 * (SGX_BIF_DIR_LIST_INDEX_EDM - 1); - #endif + #endif /* SGX_BIF_DIR_LIST_INDEX_EDM */ ui32RegVal = psDevInfo->sKernelPDDevPAddr.uiAddr >> SGX_MMU_PDE_ADDR_ALIGNSHIFT; @@ -150,6 +206,23 @@ static IMG_VOID SGXResetSetupBIFContexts(PVRSRV_SGXDEV_INFO *psDevInfo, } +/*! +******************************************************************************* + + @Function SGXResetSleep + + @Description + + Sleep for a short time to allow reset register writes to complete. + Required because no status registers are available to poll on. + + @Input psDevInfo - SGX Device Info + @Input ui32PDUMPFlags - flags to control PDUMP output + @Input bPDump - Pdump the sleep + + @Return Nothing + +******************************************************************************/ static IMG_VOID SGXResetSleep(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32PDUMPFlags, IMG_BOOL bPDump) @@ -161,14 +234,14 @@ static IMG_VOID SGXResetSleep(PVRSRV_SGXDEV_INFO *psDevInfo, ui32ReadRegister = EUR_CR_MASTER_SOFT_RESET; #else ui32ReadRegister = EUR_CR_SOFT_RESET; - #endif + #endif /* SGX_FEATURE_MP */ #endif #if !defined(PDUMP) PVR_UNREFERENCED_PARAMETER(ui32PDUMPFlags); -#endif +#endif /* PDUMP */ - + /* Sleep for 100 SGX clocks */ SGXWaitClocks(psDevInfo, 100); if (bPDump) { @@ -180,14 +253,32 @@ static IMG_VOID SGXResetSleep(PVRSRV_SGXDEV_INFO *psDevInfo, } #if defined(EMULATOR) - - + /* + Read a register to make sure we wait long enough on the emulator... + */ OSReadHWReg(psDevInfo->pvRegsBaseKM, ui32ReadRegister); #endif } #if !defined(SGX_FEATURE_MP) +/*! +******************************************************************************* + + @Function SGXResetSoftReset + + @Description + + Write to the SGX soft reset register. + + @Input psDevInfo - SGX Device Info + @Input bResetBIF - Include the BIF in the soft reset + @Input ui32PDUMPFlags - flags to control PDUMP output + @Input bPDump - Pdump the sleep + + @Return Nothing + +******************************************************************************/ static IMG_VOID SGXResetSoftReset(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_BOOL bResetBIF, IMG_UINT32 ui32PDUMPFlags, @@ -196,13 +287,14 @@ static IMG_VOID SGXResetSoftReset(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32SoftResetRegVal; ui32SoftResetRegVal = - + /* add common reset bits: */ EUR_CR_SOFT_RESET_DPM_RESET_MASK | EUR_CR_SOFT_RESET_TA_RESET_MASK | EUR_CR_SOFT_RESET_USE_RESET_MASK | EUR_CR_SOFT_RESET_ISP_RESET_MASK | EUR_CR_SOFT_RESET_TSP_RESET_MASK; +/* add conditional reset bits: */ #ifdef EUR_CR_SOFT_RESET_TWOD_RESET_MASK ui32SoftResetRegVal |= EUR_CR_SOFT_RESET_TWOD_RESET_MASK; #endif @@ -254,7 +346,7 @@ static IMG_VOID SGXResetSoftReset(PVRSRV_SGXDEV_INFO *psDevInfo, #if !defined(PDUMP) PVR_UNREFERENCED_PARAMETER(ui32PDUMPFlags); -#endif +#endif /* PDUMP */ if (bResetBIF) { @@ -269,13 +361,28 @@ static IMG_VOID SGXResetSoftReset(PVRSRV_SGXDEV_INFO *psDevInfo, } +/*! +******************************************************************************* + + @Function SGXResetInvalDC + + @Description + + Invalidate the BIF Directory Cache and wait for the operation to complete. + + @Input psDevInfo - SGX Device Info + @Input ui32PDUMPFlags - flags to control PDUMP output + + @Return Nothing + +******************************************************************************/ static IMG_VOID SGXResetInvalDC(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32PDUMPFlags, IMG_BOOL bPDump) { IMG_UINT32 ui32RegVal; - + /* Invalidate BIF Directory cache. */ #if defined(EUR_CR_BIF_CTRL_INVAL) ui32RegVal = EUR_CR_BIF_CTRL_INVAL_ALL_MASK; OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL_INVAL, ui32RegVal); @@ -302,9 +409,10 @@ static IMG_VOID SGXResetInvalDC(PVRSRV_SGXDEV_INFO *psDevInfo, #if !defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) { - - - + /* + Wait for the DC invalidate to complete - indicated by + outstanding reads reaching zero. + */ if (PollForValueKM((IMG_UINT32 *)((IMG_UINT8*)psDevInfo->pvRegsBaseKM + EUR_CR_BIF_MEM_REQ_STAT), 0, EUR_CR_BIF_MEM_REQ_STAT_READS_MASK, @@ -321,11 +429,28 @@ static IMG_VOID SGXResetInvalDC(PVRSRV_SGXDEV_INFO *psDevInfo, PDUMPREGPOLWITHFLAGS(SGX_PDUMPREG_NAME, EUR_CR_BIF_MEM_REQ_STAT, 0, EUR_CR_BIF_MEM_REQ_STAT_READS_MASK, ui32PDUMPFlags, PDUMP_POLL_OPERATOR_EQUAL); } } -#endif +#endif /* SGX_FEATURE_MULTIPLE_MEM_CONTEXTS */ } -#endif +#endif /* SGX_FEATURE_MP */ + + +/*! +******************************************************************************* + @Function SGXReset + @Description + + Reset chip + + @Input psDevInfo - device info. structure + @Input bHardwareRecovery - true if recovering powered hardware, + false if powering up + @Input ui32PDUMPFlags - flags to control PDUMP output + + @Return IMG_VOID + +******************************************************************************/ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_BOOL bHardwareRecovery, IMG_UINT32 ui32PDUMPFlags) @@ -340,12 +465,12 @@ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, #if !defined(PDUMP) PVR_UNREFERENCED_PARAMETER(ui32PDUMPFlags); -#endif +#endif /* PDUMP */ PDUMPCOMMENTWITHFLAGS(ui32PDUMPFlags, "Start of SGX reset sequence\r\n"); #if defined(FIX_HW_BRN_23944) - + /* Pause the BIF. */ ui32RegVal = EUR_CR_BIF_CTRL_PAUSE_MASK; OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32RegVal); PDUMPREGWITHFLAGS(SGX_PDUMPREG_NAME, EUR_CR_BIF_CTRL, ui32RegVal, ui32PDUMPFlags); @@ -355,7 +480,7 @@ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, ui32RegVal = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_INT_STAT); if (ui32RegVal & ui32BifFaultMask) { - + /* Page fault needs to be cleared before resetting the BIF. */ ui32RegVal = EUR_CR_BIF_CTRL_PAUSE_MASK | EUR_CR_BIF_CTRL_CLEAR_FAULT_MASK; OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32RegVal); PDUMPREGWITHFLAGS(SGX_PDUMPREG_NAME, EUR_CR_BIF_CTRL, ui32RegVal, ui32PDUMPFlags); @@ -368,17 +493,18 @@ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_TRUE); } -#endif +#endif /* defined(FIX_HW_BRN_23944) */ - + /* Reset all including BIF */ SGXResetSoftReset(psDevInfo, IMG_TRUE, ui32PDUMPFlags, IMG_TRUE); SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_TRUE); - - + /* + Initialise the BIF state. + */ #if defined(SGX_FEATURE_36BIT_MMU) - + /* enable 36bit addressing mode if the MMU supports it*/ OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_36BIT_ADDRESSING, EUR_CR_BIF_36BIT_ADDRESSING_ENABLE_MASK); PDUMPREGWITHFLAGS(SGX_PDUMPREG_NAME, EUR_CR_BIF_36BIT_ADDRESSING, EUR_CR_BIF_36BIT_ADDRESSING_ENABLE_MASK, ui32PDUMPFlags); #endif @@ -386,57 +512,60 @@ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, SGXResetInitBIFContexts(psDevInfo, ui32PDUMPFlags); #if defined(EUR_CR_BIF_MEM_ARB_CONFIG) - - + /* + Initialise the memory arbiter to its default state + */ ui32RegVal = (12UL << EUR_CR_BIF_MEM_ARB_CONFIG_PAGE_SIZE_SHIFT) | (7UL << EUR_CR_BIF_MEM_ARB_CONFIG_BEST_CNT_SHIFT) | (12UL << EUR_CR_BIF_MEM_ARB_CONFIG_TTE_THRESH_SHIFT); OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_MEM_ARB_CONFIG, ui32RegVal); PDUMPREGWITHFLAGS(SGX_PDUMPREG_NAME, EUR_CR_BIF_MEM_ARB_CONFIG, ui32RegVal, ui32PDUMPFlags); -#endif +#endif /* EUR_CR_BIF_MEM_ARB_CONFIG */ #if defined(SGX_FEATURE_SYSTEM_CACHE) #if defined(SGX_BYPASS_SYSTEM_CACHE) - + /* set the SLC to bypass all accesses */ ui32RegVal = MNE_CR_CTRL_BYPASS_ALL_MASK; #else #if defined(FIX_HW_BRN_26620) ui32RegVal = 0; #else - + /* set the SLC to bypass cache-coherent accesses */ ui32RegVal = MNE_CR_CTRL_BYP_CC_MASK; #endif #if defined(FIX_HW_BRN_34028) - + /* Bypass the MNE for the USEC requester */ ui32RegVal |= (8 << MNE_CR_CTRL_BYPASS_SHIFT); #endif - #endif + #endif /* SGX_BYPASS_SYSTEM_CACHE */ OSWriteHWReg(psDevInfo->pvRegsBaseKM, MNE_CR_CTRL, ui32RegVal); PDUMPREG(SGX_PDUMPREG_NAME, MNE_CR_CTRL, ui32RegVal); -#endif +#endif /* SGX_FEATURE_SYSTEM_CACHE */ if (bHardwareRecovery) { - - - - - - - + /* + Set all requestors to the dummy PD which forces all memory + accesses to page fault. + This enables us to flush out BIF requests from parts of SGX + which do not have their own soft reset. + Note: sBIFResetPDDevPAddr.uiAddr is a relative address (2GB max) + MSB is the bus master flag; 1 == enabled + */ ui32RegVal = (IMG_UINT32)psDevInfo->sBIFResetPDDevPAddr.uiAddr; OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_DIR_LIST_BASE0, ui32RegVal); SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_FALSE); - + /* Bring BIF out of reset. */ SGXResetSoftReset(psDevInfo, IMG_FALSE, ui32PDUMPFlags, IMG_TRUE); SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_FALSE); SGXResetInvalDC(psDevInfo, ui32PDUMPFlags, IMG_FALSE); - - + /* + Check for a page fault from parts of SGX which do not have a reset. + */ for (;;) { IMG_UINT32 ui32BifIntStat = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_INT_STAT); @@ -448,18 +577,19 @@ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, break; } - - - + /* + There is a page fault, so reset the BIF again, map in the dummy page, + bring the BIF up and invalidate the Directory Cache. + */ sBifFault.uiAddr = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_FAULT); PVR_DPF((PVR_DBG_WARNING, "SGXReset: Page fault 0x%x/0x%x", ui32BifIntStat, sBifFault.uiAddr)); ui32PDIndex = sBifFault.uiAddr >> (SGX_MMU_PAGE_SHIFT + SGX_MMU_PT_SHIFT); ui32PTIndex = (sBifFault.uiAddr & SGX_MMU_PT_MASK) >> SGX_MMU_PAGE_SHIFT; - + /* Put the BIF into reset. */ SGXResetSoftReset(psDevInfo, IMG_TRUE, ui32PDUMPFlags, IMG_FALSE); - + /* Map in the dummy page. */ psDevInfo->pui32BIFResetPD[ui32PDIndex] = (psDevInfo->sBIFResetPTDevPAddr.uiAddr >>SGX_MMU_PDE_ADDR_ALIGNSHIFT) | SGX_MMU_PDE_PAGE_SIZE_4K @@ -468,7 +598,7 @@ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, >>SGX_MMU_PTE_ADDR_ALIGNSHIFT) | SGX_MMU_PTE_VALID; - + /* Clear outstanding events. */ ui32RegVal = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_STATUS); OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_HOST_CLEAR, ui32RegVal); ui32RegVal = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_STATUS2); @@ -476,50 +606,51 @@ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_FALSE); - + /* Bring the BIF out of reset. */ SGXResetSoftReset(psDevInfo, IMG_FALSE, ui32PDUMPFlags, IMG_FALSE); SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_FALSE); - + /* Invalidate Directory Cache. */ SGXResetInvalDC(psDevInfo, ui32PDUMPFlags, IMG_FALSE); - + /* Unmap the dummy page and try again. */ psDevInfo->pui32BIFResetPD[ui32PDIndex] = 0; psDevInfo->pui32BIFResetPT[ui32PTIndex] = 0; } } else { - + /* Bring BIF out of reset. */ SGXResetSoftReset(psDevInfo, IMG_FALSE, ui32PDUMPFlags, IMG_TRUE); SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_FALSE); } - - + /* + Initialise the BIF memory contexts before bringing the rest of SGX out of reset. + */ SGXResetSetupBIFContexts(psDevInfo, ui32PDUMPFlags); #if defined(SGX_FEATURE_2D_HARDWARE) && !defined(SGX_FEATURE_PTLA) - + /* check that the heap base has the right alignment (1Mb) */ #if ((SGX_2D_HEAP_BASE & ~EUR_CR_BIF_TWOD_REQ_BASE_ADDR_MASK) != 0) #error "SGXReset: SGX_2D_HEAP_BASE doesn't match EUR_CR_BIF_TWOD_REQ_BASE_ADDR_MASK alignment" #endif - + /* Set up 2D requestor base */ OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_TWOD_REQ_BASE, SGX_2D_HEAP_BASE); PDUMPREGWITHFLAGS(SGX_PDUMPREG_NAME, EUR_CR_BIF_TWOD_REQ_BASE, SGX_2D_HEAP_BASE, ui32PDUMPFlags); #endif - + /* Invalidate BIF Directory cache. */ SGXResetInvalDC(psDevInfo, ui32PDUMPFlags, IMG_TRUE); PVR_DPF((PVR_DBG_MESSAGE,"Soft Reset of SGX")); - + /* Take chip out of reset */ ui32RegVal = 0; OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_SOFT_RESET, ui32RegVal); PDUMPREGWITHFLAGS(SGX_PDUMPREG_NAME, EUR_CR_SOFT_RESET, ui32RegVal, ui32PDUMPFlags); - + /* wait a bit */ SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_TRUE); PDUMPCOMMENTWITHFLAGS(ui32PDUMPFlags, "End of SGX reset sequence\r\n"); @@ -534,17 +665,21 @@ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, #if !defined(PDUMP) PVR_UNREFERENCED_PARAMETER(ui32PDUMPFlags); -#endif +#endif /* PDUMP */ PDUMPCOMMENTWITHFLAGS(ui32PDUMPFlags, "Start of SGX MP reset sequence\r\n"); - + /* Put hydra into soft reset */ ui32RegVal = EUR_CR_MASTER_SOFT_RESET_BIF_RESET_MASK | EUR_CR_MASTER_SOFT_RESET_IPF_RESET_MASK | EUR_CR_MASTER_SOFT_RESET_DPM_RESET_MASK | - EUR_CR_MASTER_SOFT_RESET_MCI_RESET_MASK | EUR_CR_MASTER_SOFT_RESET_VDM_RESET_MASK; + if (bHardwareRecovery) + { + ui32RegVal |= EUR_CR_MASTER_SOFT_RESET_MCI_RESET_MASK; + } + #if defined(SGX_FEATURE_PTLA) ui32RegVal |= EUR_CR_MASTER_SOFT_RESET_PTLA_RESET_MASK; #endif @@ -552,7 +687,7 @@ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, ui32RegVal |= EUR_CR_MASTER_SOFT_RESET_SLC_RESET_MASK; #endif - + /* Hard reset the slave cores */ ui32RegVal |= EUR_CR_MASTER_SOFT_RESET_CORE_RESET_MASK(0) | EUR_CR_MASTER_SOFT_RESET_CORE_RESET_MASK(1) | EUR_CR_MASTER_SOFT_RESET_CORE_RESET_MASK(2) | @@ -580,6 +715,9 @@ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, #if defined(PVR_SLC_8KB_ADDRESS_MODE) (4 << EUR_CR_MASTER_SLC_CTRL_ADDR_DECODE_MODE_SHIFT) | #endif + #if defined(FIX_HW_BRN_33809) + (2 << EUR_CR_MASTER_SLC_CTRL_ADDR_DECODE_MODE_SHIFT) | + #endif (0xC << EUR_CR_MASTER_SLC_CTRL_ARB_PAGE_SIZE_SHIFT); OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_SLC_CTRL, ui32RegVal); PDUMPCOMMENTWITHFLAGS(ui32PDUMPFlags, "Initialise the hydra SLC control\r\n"); @@ -596,15 +734,15 @@ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, EUR_CR_MASTER_SLC_CTRL_BYPASS_REQ_USE3_MASK | EUR_CR_MASTER_SLC_CTRL_BYPASS_REQ_TA_MASK; #endif - #endif + #endif /* SGX_BYPASS_SYSTEM_CACHE */ OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_SLC_CTRL_BYPASS, ui32RegVal); PDUMPCOMMENTWITHFLAGS(ui32PDUMPFlags, "Initialise the hydra SLC bypass control\r\n"); PDUMPREG(SGX_PDUMPREG_NAME, EUR_CR_MASTER_SLC_CTRL_BYPASS, ui32RegVal); -#endif +#endif /* SGX_FEATURE_SYSTEM_CACHE */ SGXResetSleep(psDevInfo, ui32PDUMPFlags, IMG_TRUE); - + /* Remove the resets */ ui32RegVal = 0; OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_SOFT_RESET, ui32RegVal); PDUMPCOMMENTWITHFLAGS(ui32PDUMPFlags, "Remove the resets from all of SGX\r\n"); @@ -621,32 +759,32 @@ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, #if defined(FIX_HW_BRN_31278) || defined(FIX_HW_BRN_31620) || defined(FIX_HW_BRN_31671) || defined(FIX_HW_BRN_32085) #if defined(FIX_HW_BRN_31278) || defined(FIX_HW_BRN_32085) - + /* disable prefetch */ ui32RegVal = (1<<EUR_CR_MASTER_BIF_MMU_CTRL_ADDR_HASH_MODE_SHIFT); #else ui32RegVal = (1<<EUR_CR_MASTER_BIF_MMU_CTRL_ADDR_HASH_MODE_SHIFT) | EUR_CR_MASTER_BIF_MMU_CTRL_PREFETCHING_ON_MASK; #endif #if !defined(FIX_HW_BRN_31620) && !defined(FIX_HW_BRN_31671) - + /* enable the DC TLB */ ui32RegVal |= EUR_CR_MASTER_BIF_MMU_CTRL_ENABLE_DC_TLB_MASK; #endif - + /* Master bank */ OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_BIF_MMU_CTRL, ui32RegVal); PDUMPREGWITHFLAGS(SGX_PDUMPREG_NAME, EUR_CR_MASTER_BIF_MMU_CTRL, ui32RegVal, ui32PDUMPFlags); #if defined(FIX_HW_BRN_31278) || defined(FIX_HW_BRN_32085) - + /* disable prefetch */ ui32RegVal = (1<<EUR_CR_BIF_MMU_CTRL_ADDR_HASH_MODE_SHIFT); #else ui32RegVal = (1<<EUR_CR_BIF_MMU_CTRL_ADDR_HASH_MODE_SHIFT) | EUR_CR_BIF_MMU_CTRL_PREFETCHING_ON_MASK; #endif #if !defined(FIX_HW_BRN_31620) && !defined(FIX_HW_BRN_31671) - + /* enable the DC TLB */ ui32RegVal |= EUR_CR_BIF_MMU_CTRL_ENABLE_DC_TLB_MASK; #endif - + /* Per-core */ { IMG_UINT32 ui32Core; @@ -663,6 +801,9 @@ IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO *psDevInfo, PDUMPCOMMENTWITHFLAGS(ui32PDUMPFlags, "End of SGX MP reset sequence\r\n"); } -#endif +#endif /* SGX_FEATURE_MP */ +/****************************************************************************** + End of file (sgxreset.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/devices/sgx/sgxtransfer.c b/sgx/services4/srvkm/devices/sgx/sgxtransfer.c index bde6fc6..e85015d 100644 --- a/sgx/services4/srvkm/devices/sgx/sgxtransfer.c +++ b/sgx/services4/srvkm/devices/sgx/sgxtransfer.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Device specific transfer queue routines +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #if defined(TRANSFER_QUEUE) @@ -68,7 +84,11 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF #if defined(PDUMP) IMG_BOOL bPersistentProcess = IMG_FALSE; - + /* + * For persistent processes, the HW kicks should not go into the + * extended init phase; only keep memory transactions from the + * window system which are necessary to run the client app. + */ { PVRSRV_PER_PROCESS_DATA* psPerProc = PVRSRVFindPerProcessData(); if(psPerProc != IMG_NULL) @@ -76,7 +96,7 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF bPersistentProcess = psPerProc->bPDumpPersistent; } } -#endif +#endif /* PDUMP */ #if defined(FIX_HW_BRN_31620) hDevMemContext = psKick->hDevMemContext; #endif @@ -89,8 +109,8 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF TRANSFER_TOKEN_SUBMIT); return PVRSRV_ERROR_INVALID_PARAMS; } - - + /* override QAC warning about stricter alignment */ + /* PRQA S 3305 1 */ psSharedTransferCmd = CCB_DATA_FROM_OFFSET(SGXMKIF_TRANSFERCMD_SHARED, psCCBMemInfo, psKick, ui32SharedCmdCCBOffset); PVR_TTRACE(PVRSRV_TRACE_GROUP_TRANSFER, PVRSRV_TRACE_CLASS_CMD_START, TRANSFER_TOKEN_SUBMIT); @@ -135,7 +155,9 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF psSharedTransferCmd->s3DSyncReadOpsCompleteDevVAddr.uiAddr = 0; } - + /* filter out multiple occurrences of the same sync object from srcs or dests + * note : the same sync can still be used to synchronize both src and dst. + */ for (loop = 0; loop < MIN(SGX_MAX_TRANSFER_SYNC_OPS, psKick->ui32NumSrcSync); loop++) { IMG_UINT32 i; @@ -158,10 +180,6 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF } if (uiSrcSyncEnable & (1 << loop)) { - if (psMySyncInfo->hSmartCache) - { - PVRMMapPrepareCpuToGpu(psMySyncInfo->hSmartCache); - } ui32RealSrcSyncNum++; } } @@ -187,11 +205,6 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF } if (uiDstSyncEnable & (1 << loop)) { - if (psMySyncInfo->hSmartCache) - { - /* TODO this should happen after GPU is done? */ - PVRMMapPrepareGpuToCpu(psMySyncInfo->hSmartCache); - } ui32RealDstSyncNum++; } } @@ -229,20 +242,29 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF { psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *)psKick->ahDstSyncInfo[loop]; + psSyncInfo->psSyncData->ui64LastWrite = ui64KickCount; + PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_TRANSFER, TRANSFER_TOKEN_DST_SYNC, psSyncInfo, PVRSRV_SYNCOP_SAMPLE); psSharedTransferCmd->asDstSyncs[i].ui32WriteOpsPendingVal = psSyncInfo->psSyncData->ui32WriteOpsPending; psSharedTransferCmd->asDstSyncs[i].ui32ReadOpsPendingVal = psSyncInfo->psSyncData->ui32ReadOpsPending; + psSharedTransferCmd->asDstSyncs[i].ui32ReadOps2PendingVal = psSyncInfo->psSyncData->ui32ReadOps2Pending; psSharedTransferCmd->asDstSyncs[i].sWriteOpsCompleteDevVAddr = psSyncInfo->sWriteOpsCompleteDevVAddr; psSharedTransferCmd->asDstSyncs[i].sReadOpsCompleteDevVAddr = psSyncInfo->sReadOpsCompleteDevVAddr; + psSharedTransferCmd->asDstSyncs[i].sReadOps2CompleteDevVAddr = psSyncInfo->sReadOps2CompleteDevVAddr; i++; } } PVR_ASSERT(i == ui32RealDstSyncNum); - + /* + * We allow source and destination sync objects to be the + * same, which is why the read/write pending updates are delayed + * until the transfer command has been updated with the current + * values from the objects. + */ for (loop = 0; loop < psKick->ui32NumSrcSync; loop++) { if (uiSrcSyncEnable & (1 << loop)) @@ -284,7 +306,7 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF { psSyncInfo = psKick->ahSrcSyncInfo[loop]; - PDUMPCOMMENT("Hack src surface write op in transfer cmd\r\n"); + PDUMPCOMMENT("Tweak src surface write op in transfer cmd\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, psCCBMemInfo, psKick->ui32CCBDumpWOff + (IMG_UINT32)(offsetof(SGXMKIF_TRANSFERCMD_SHARED, asSrcSyncs) + i * sizeof(PVRSRV_DEVICE_SYNC_OBJECT) + offsetof(PVRSRV_DEVICE_SYNC_OBJECT, ui32WriteOpsPendingVal)), @@ -292,7 +314,7 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF psKick->ui32PDumpFlags, MAKEUNIQUETAG(psCCBMemInfo)); - PDUMPCOMMENT("Hack src surface read op in transfer cmd\r\n"); + PDUMPCOMMENT("Tweak src surface read op in transfer cmd\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastReadOpDumpVal, psCCBMemInfo, psKick->ui32CCBDumpWOff + (IMG_UINT32)(offsetof(SGXMKIF_TRANSFERCMD_SHARED, asSrcSyncs) + i * sizeof(PVRSRV_DEVICE_SYNC_OBJECT) + offsetof(PVRSRV_DEVICE_SYNC_OBJECT, ui32ReadOpsPendingVal)), @@ -308,9 +330,10 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF { if (uiDstSyncEnable & (1 << loop)) { + IMG_UINT32 ui32PDumpReadOp2 = 0; psSyncInfo = psKick->ahDstSyncInfo[loop]; - PDUMPCOMMENT("Hack dest surface write op in transfer cmd\r\n"); + PDUMPCOMMENT("Tweak dest surface write op in transfer cmd\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, psCCBMemInfo, psKick->ui32CCBDumpWOff + (IMG_UINT32)(offsetof(SGXMKIF_TRANSFERCMD_SHARED, asDstSyncs) + i * sizeof(PVRSRV_DEVICE_SYNC_OBJECT) + offsetof(PVRSRV_DEVICE_SYNC_OBJECT, ui32WriteOpsPendingVal)), @@ -318,18 +341,31 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF psKick->ui32PDumpFlags, MAKEUNIQUETAG(psCCBMemInfo)); - PDUMPCOMMENT("Hack dest surface read op in transfer cmd\r\n"); + PDUMPCOMMENT("Tweak dest surface read op in transfer cmd\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastReadOpDumpVal, psCCBMemInfo, psKick->ui32CCBDumpWOff + (IMG_UINT32)(offsetof(SGXMKIF_TRANSFERCMD_SHARED, asDstSyncs) + i * sizeof(PVRSRV_DEVICE_SYNC_OBJECT) + offsetof(PVRSRV_DEVICE_SYNC_OBJECT, ui32ReadOpsPendingVal)), sizeof(psSyncInfo->psSyncData->ui32LastReadOpDumpVal), psKick->ui32PDumpFlags, MAKEUNIQUETAG(psCCBMemInfo)); + + PDUMPCOMMENT("Tweak dest surface read op2 in transfer cmd\r\n"); + PDUMPMEM(&ui32PDumpReadOp2, + psCCBMemInfo, + psKick->ui32CCBDumpWOff + (IMG_UINT32)(offsetof(SGXMKIF_TRANSFERCMD_SHARED, asDstSyncs) + i * sizeof(PVRSRV_DEVICE_SYNC_OBJECT) + offsetof(PVRSRV_DEVICE_SYNC_OBJECT, ui32ReadOps2PendingVal)), + sizeof(ui32PDumpReadOp2), + psKick->ui32PDumpFlags, + MAKEUNIQUETAG(psCCBMemInfo)); i++; } } - + /* + * We allow the first source and destination sync objects to be the + * same, which is why the read/write pending updates are delayed + * until the transfer command has been updated with the current + * values from the objects. + */ for (loop = 0; loop < (psKick->ui32NumSrcSync); loop++) { if (uiSrcSyncEnable & (1 << loop)) @@ -390,7 +426,7 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF if (eError == PVRSRV_ERROR_RETRY) { - + /* Client will retry, so undo the sync ops pending increment(s) done above. */ if ((psKick->ui32Flags & SGXMKIF_TQFLAGS_KEEPPENDING) == 0UL) { for (loop = 0; loop < psKick->ui32NumSrcSync; loop++) @@ -425,14 +461,14 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF } } - + /* Command needed to be synchronised with the TA? */ if (psKick->hTASyncInfo != IMG_NULL) { psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *)psKick->hTASyncInfo; psSyncInfo->psSyncData->ui32WriteOpsPending--; } - + /* Command needed to be synchronised with the 3D? */ if (psKick->h3DSyncInfo != IMG_NULL) { psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *)psKick->h3DSyncInfo; @@ -452,7 +488,7 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmitTransferKM(IMG_HANDLE hDevHandle, PVRSRV_TRANSF #if defined(NO_HARDWARE) if ((psKick->ui32Flags & SGXMKIF_TQFLAGS_NOSYNCUPDATE) == 0) { - + /* Update sync objects pretending that we have done the job*/ for (loop = 0; loop < psKick->ui32NumSrcSync; loop++) { if (uiSrcSyncEnable & (1 << loop)) @@ -508,7 +544,11 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK IMG_HANDLE hDevMemContext = IMG_NULL; #if defined(PDUMP) IMG_BOOL bPersistentProcess = IMG_FALSE; - + /* + * For persistent processes, the HW kicks should not go into the + * extended init phase; only keep memory transactions from the + * window system which are necessary to run the client app. + */ { PVRSRV_PER_PROCESS_DATA* psPerProc = PVRSRVFindPerProcessData(); if(psPerProc != IMG_NULL) @@ -516,7 +556,7 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK bPersistentProcess = psPerProc->bPDumpPersistent; } } -#endif +#endif /* PDUMP */ #if defined(FIX_HW_BRN_31620) hDevMemContext = psKick->hDevMemContext; #endif @@ -526,13 +566,13 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK PVR_DPF((PVR_DBG_ERROR, "SGXSubmit2DKM: Invalid CCB offset")); return PVRSRV_ERROR_INVALID_PARAMS; } - - + /* override QAC warning about stricter alignment */ + /* PRQA S 3305 1 */ ps2DCmd = CCB_DATA_FROM_OFFSET(SGXMKIF_2DCMD_SHARED, psCCBMemInfo, psKick, ui32SharedCmdCCBOffset); OSMemSet(ps2DCmd, 0, sizeof(*ps2DCmd)); - + /* Command needs to be synchronised with the TA? */ if (psKick->hTASyncInfo != IMG_NULL) { psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *)psKick->hTASyncInfo; @@ -544,7 +584,7 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK ps2DCmd->sTASyncData.sReadOpsCompleteDevVAddr = psSyncInfo->sReadOpsCompleteDevVAddr; } - + /* Command needs to be synchronised with the 3D? */ if (psKick->h3DSyncInfo != IMG_NULL) { psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *)psKick->h3DSyncInfo; @@ -556,7 +596,12 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK ps2DCmd->s3DSyncData.sReadOpsCompleteDevVAddr = psSyncInfo->sReadOpsCompleteDevVAddr; } - + /* + * We allow the first source and destination sync objects to be the + * same, which is why the read/write pending updates are delayed + * until the transfer command has been updated with the current + * values from the objects. + */ ps2DCmd->ui32NumSrcSync = psKick->ui32NumSrcSync; for (i = 0; i < psKick->ui32NumSrcSync; i++) { @@ -575,12 +620,14 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK ps2DCmd->sDstSyncData.ui32WriteOpsPendingVal = psSyncInfo->psSyncData->ui32WriteOpsPending; ps2DCmd->sDstSyncData.ui32ReadOpsPendingVal = psSyncInfo->psSyncData->ui32ReadOpsPending; + ps2DCmd->sDstSyncData.ui32ReadOps2PendingVal = psSyncInfo->psSyncData->ui32ReadOps2Pending; ps2DCmd->sDstSyncData.sWriteOpsCompleteDevVAddr = psSyncInfo->sWriteOpsCompleteDevVAddr; ps2DCmd->sDstSyncData.sReadOpsCompleteDevVAddr = psSyncInfo->sReadOpsCompleteDevVAddr; + ps2DCmd->sDstSyncData.sReadOps2CompleteDevVAddr = psSyncInfo->sReadOps2CompleteDevVAddr; } - + /* Read/Write ops pending updates, delayed from above */ for (i = 0; i < psKick->ui32NumSrcSync; i++) { psSyncInfo = psKick->ahSrcSyncInfo[i]; @@ -598,7 +645,7 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK || ((psKick->ui32PDumpFlags & PDUMP_FLAGS_CONTINUOUS) != 0)) && (bPersistentProcess == IMG_FALSE) ) { - + /* Pdump the command from the per context CCB */ PDUMPCOMMENT("Shared part of 2D command\r\n"); PDUMPMEM(ps2DCmd, psCCBMemInfo, @@ -611,7 +658,7 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK { psSyncInfo = psKick->ahSrcSyncInfo[i]; - PDUMPCOMMENT("Hack src surface write op in 2D cmd\r\n"); + PDUMPCOMMENT("Tweak src surface write op in 2D cmd\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, psCCBMemInfo, psKick->ui32CCBDumpWOff + (IMG_UINT32)offsetof(SGXMKIF_2DCMD_SHARED, sSrcSyncData[i].ui32WriteOpsPendingVal), @@ -619,7 +666,7 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK psKick->ui32PDumpFlags, MAKEUNIQUETAG(psCCBMemInfo)); - PDUMPCOMMENT("Hack src surface read op in 2D cmd\r\n"); + PDUMPCOMMENT("Tweak src surface read op in 2D cmd\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastReadOpDumpVal, psCCBMemInfo, psKick->ui32CCBDumpWOff + (IMG_UINT32)offsetof(SGXMKIF_2DCMD_SHARED, sSrcSyncData[i].ui32ReadOpsPendingVal), @@ -630,9 +677,10 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK if (psKick->hDstSyncInfo != IMG_NULL) { + IMG_UINT32 ui32PDumpReadOp2 = 0; psSyncInfo = psKick->hDstSyncInfo; - PDUMPCOMMENT("Hack dest surface write op in 2D cmd\r\n"); + PDUMPCOMMENT("Tweak dest surface write op in 2D cmd\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastOpDumpVal, psCCBMemInfo, psKick->ui32CCBDumpWOff + (IMG_UINT32)offsetof(SGXMKIF_2DCMD_SHARED, sDstSyncData.ui32WriteOpsPendingVal), @@ -640,16 +688,23 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK psKick->ui32PDumpFlags, MAKEUNIQUETAG(psCCBMemInfo)); - PDUMPCOMMENT("Hack dest surface read op in 2D cmd\r\n"); + PDUMPCOMMENT("Tweak dest surface read op in 2D cmd\r\n"); PDUMPMEM(&psSyncInfo->psSyncData->ui32LastReadOpDumpVal, psCCBMemInfo, psKick->ui32CCBDumpWOff + (IMG_UINT32)offsetof(SGXMKIF_2DCMD_SHARED, sDstSyncData.ui32ReadOpsPendingVal), sizeof(psSyncInfo->psSyncData->ui32LastReadOpDumpVal), psKick->ui32PDumpFlags, MAKEUNIQUETAG(psCCBMemInfo)); + PDUMPCOMMENT("Tweak dest surface read op2 in 2D cmd\r\n"); + PDUMPMEM(&ui32PDumpReadOp2, + psCCBMemInfo, + psKick->ui32CCBDumpWOff + (IMG_UINT32)offsetof(SGXMKIF_2DCMD_SHARED, sDstSyncData.ui32ReadOps2PendingVal), + sizeof(ui32PDumpReadOp2), + psKick->ui32PDumpFlags, + MAKEUNIQUETAG(psCCBMemInfo)); } - + /* Read/Write ops pending updates, delayed from above */ for (i = 0; i < psKick->ui32NumSrcSync; i++) { psSyncInfo = psKick->ahSrcSyncInfo[i]; @@ -670,8 +725,9 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK if (eError == PVRSRV_ERROR_RETRY) { - - + /* Client will retry, so undo the write ops pending increment + done above. + */ #if defined(PDUMP) if (PDumpIsCaptureFrameKM()) { @@ -701,7 +757,7 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK psSyncInfo->psSyncData->ui32WriteOpsPending--; } - + /* Command needed to be synchronised with the TA? */ if (psKick->hTASyncInfo != IMG_NULL) { psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *)psKick->hTASyncInfo; @@ -709,7 +765,7 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK psSyncInfo->psSyncData->ui32WriteOpsPending--; } - + /* Command needed to be synchronised with the 3D? */ if (psKick->h3DSyncInfo != IMG_NULL) { psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *)psKick->h3DSyncInfo; @@ -722,7 +778,7 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK #if defined(NO_HARDWARE) - + /* Update sync objects pretending that we have done the job*/ for(i = 0; i < psKick->ui32NumSrcSync; i++) { psSyncInfo = (PVRSRV_KERNEL_SYNC_INFO *)psKick->ahSrcSyncInfo[i]; @@ -753,5 +809,5 @@ IMG_EXPORT PVRSRV_ERROR SGXSubmit2DKM(IMG_HANDLE hDevHandle, PVRSRV_2D_SGX_KICK return eError; } -#endif -#endif +#endif /* SGX_FEATURE_2D_HARDWARE */ +#endif /* TRANSFER_QUEUE */ diff --git a/sgx/services4/srvkm/devices/sgx/sgxutils.c b/sgx/services4/srvkm/devices/sgx/sgxutils.c index 1fbca00..b64f545 100644 --- a/sgx/services4/srvkm/devices/sgx/sgxutils.c +++ b/sgx/services4/srvkm/devices/sgx/sgxutils.c @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Device specific utility routines +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Device specific functions +@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> @@ -43,12 +60,14 @@ #include "ttrace.h" #ifdef __linux__ -#include <linux/kernel.h> -#include <linux/string.h> +#include <linux/kernel.h> // sprintf +#include <linux/string.h> // strncpy, strlen #else #include <stdio.h> #endif +IMG_UINT64 ui64KickCount; + #if defined(SYS_CUSTOM_POWERDOWN) PVRSRV_ERROR SysPowerDownMISR(PVRSRV_DEVICE_NODE * psDeviceNode, IMG_UINT32 ui32CallerID); @@ -56,20 +75,38 @@ PVRSRV_ERROR SysPowerDownMISR(PVRSRV_DEVICE_NODE * psDeviceNode, IMG_UINT32 ui32 +/*! +****************************************************************************** + + @Function SGXPostActivePowerEvent + + @Description + + post power event functionality (e.g. restart) + + @Input psDeviceNode : SGX Device Node + @Input ui32CallerID - KERNEL_ID or ISR_ID + + @Return IMG_VOID : + +******************************************************************************/ static IMG_VOID SGXPostActivePowerEvent(PVRSRV_DEVICE_NODE * psDeviceNode, IMG_UINT32 ui32CallerID) { PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; SGXMKIF_HOST_CTL *psSGXHostCtl = psDevInfo->psSGXHostCtl; - + /* Update the counter for stats. */ psSGXHostCtl->ui32NumActivePowerEvents++; if ((psSGXHostCtl->ui32PowerStatus & PVRSRV_USSE_EDM_POWMAN_POWEROFF_RESTART_IMMEDIATE) != 0) { + PVR_DPF((PVR_DBG_MESSAGE, "SGXPostActivePowerEvent: SGX requests immediate restart")); - - + /* + Events were queued during the active power + request, so SGX will need to be restarted. + */ if (ui32CallerID == ISR_ID) { psDeviceNode->bReProcessDeviceCommandComplete = IMG_TRUE; @@ -82,6 +119,22 @@ static IMG_VOID SGXPostActivePowerEvent(PVRSRV_DEVICE_NODE * psDeviceNode, } +/*! +****************************************************************************** + + @Function SGXTestActivePowerEvent + + @Description + + Checks whether the microkernel has generated an active power event. If so, + perform the power transition. + + @Input psDeviceNode : SGX Device Node + @Input ui32CallerID - KERNEL_ID or ISR_ID + + @Return IMG_VOID : + +******************************************************************************/ IMG_VOID SGXTestActivePowerEvent (PVRSRV_DEVICE_NODE *psDeviceNode, IMG_UINT32 ui32CallerID) { @@ -89,38 +142,76 @@ IMG_VOID SGXTestActivePowerEvent (PVRSRV_DEVICE_NODE *psDeviceNode, PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; SGXMKIF_HOST_CTL *psSGXHostCtl = psDevInfo->psSGXHostCtl; - if (((psSGXHostCtl->ui32InterruptFlags & PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER) != 0) && - ((psSGXHostCtl->ui32InterruptClearFlags & PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER) == 0)) +#if defined(SYS_SUPPORTS_SGX_IDLE_CALLBACK) + if (!psDevInfo->bSGXIdle && + ((psSGXHostCtl->ui32InterruptFlags & PVRSRV_USSE_EDM_INTERRUPT_IDLE) != 0)) { - + psDevInfo->bSGXIdle = IMG_TRUE; + SysSGXIdleTransition(psDevInfo->bSGXIdle); + } + else if (psDevInfo->bSGXIdle && + ((psSGXHostCtl->ui32InterruptFlags & PVRSRV_USSE_EDM_INTERRUPT_IDLE) == 0)) + { + psDevInfo->bSGXIdle = IMG_FALSE; + SysSGXIdleTransition(psDevInfo->bSGXIdle); + } +#endif /* SYS_SUPPORTS_SGX_IDLE_CALLBACK */ + + /* + * Quickly check (without lock) if there is an APM event we should handle. + * This check fails most of the time so we don't want to incur lock overhead. + * Check the flags in the reverse order that microkernel clears them to prevent + * us from seeing an inconsistent state. + */ + if (((psSGXHostCtl->ui32InterruptClearFlags & PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER) == 0) && + ((psSGXHostCtl->ui32InterruptFlags & PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER) != 0)) + { + eError = PVRSRVPowerLock(ui32CallerID, IMG_FALSE); + if (eError == PVRSRV_ERROR_RETRY) + { + return; + } + else if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"SGXTestActivePowerEvent failed to acquire lock - " + "ui32CallerID:%d eError:%u", ui32CallerID, eError)); + return; + } + + /* + * Check again (with lock) if APM event has been cleared or handled. A race + * condition may allow multiple threads to pass the quick check. + */ + if (((psSGXHostCtl->ui32InterruptClearFlags & PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER) != 0) || + ((psSGXHostCtl->ui32InterruptFlags & PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER) == 0)) + { + PVRSRVPowerUnlock(ui32CallerID); + return; + } + + /* Microkernel is idle and is requesting to be powered down. */ psSGXHostCtl->ui32InterruptClearFlags |= PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER; - + /* Suspend pdumping. */ PDUMPSUSPEND(); #if defined(SYS_CUSTOM_POWERDOWN) - - - + /* + Some power down code cannot be executed inside an MISR on + some platforms that use mutexes inside the power code. + */ eError = SysPowerDownMISR(psDeviceNode, ui32CallerID); #else eError = PVRSRVSetDevicePowerStateKM(psDeviceNode->sDevId.ui32DeviceIndex, - PVRSRV_DEV_POWER_STATE_OFF, - ui32CallerID, IMG_FALSE); + PVRSRV_DEV_POWER_STATE_OFF); if (eError == PVRSRV_OK) { SGXPostActivePowerEvent(psDeviceNode, ui32CallerID); } #endif - if (eError == PVRSRV_ERROR_RETRY) - { - - - psSGXHostCtl->ui32InterruptClearFlags &= ~PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER; - eError = PVRSRV_OK; - } + PVRSRVPowerUnlock(ui32CallerID); - + /* Resume pdumping */ PDUMPRESUME(); } @@ -131,6 +222,15 @@ IMG_VOID SGXTestActivePowerEvent (PVRSRV_DEVICE_NODE *psDeviceNode, } +/****************************************************************************** + FUNCTION : SGXAcquireKernelCCBSlot + + PURPOSE : Attempts to obtain a slot in the Kernel CCB + + PARAMETERS : psCCB - the CCB + + RETURNS : Address of space if available, IMG_NULL otherwise +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(SGXAcquireKernelCCBSlot) #endif @@ -146,10 +246,27 @@ static INLINE SGXMKIF_COMMAND * SGXAcquireKernelCCBSlot(PVRSRV_SGX_CCB_INFO *psC OSSleepms(1); } END_LOOP_UNTIL_TIMEOUT(); - + /* Time out on waiting for CCB space */ return IMG_NULL; } +/*! +****************************************************************************** + + @Function SGXScheduleCCBCommand + + @Description - Submits a CCB command and kicks the ukernel (without + power management) + + @Input psDevInfo - pointer to device info + @Input eCmdType - see SGXMKIF_CMD_* + @Input psCommandData - kernel CCB command + @Input ui32CallerID - KERNEL_ID or ISR_ID + @Input ui32PDumpFlags + + @Return ui32Error - success or failure + +******************************************************************************/ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, SGXMKIF_CMD_TYPE eCmdType, SGXMKIF_COMMAND *psCommandData, @@ -162,6 +279,7 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, PVRSRV_ERROR eError = PVRSRV_OK; SGXMKIF_COMMAND *psSGXCommand; PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + SGXMKIF_HOST_CTL *psSGXHostCtl = psDevInfo->psSGXHostCtl; #if defined(FIX_HW_BRN_31620) IMG_UINT32 ui32CacheMasks[4]; IMG_UINT32 i; @@ -185,7 +303,7 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, psMMUContext = psDevInfo->hKernelMMUContext; psDeviceNode->pfnMMUGetCacheFlushRange(psMMUContext, &ui32CacheMasks[0]); - + /* Put the apps memory context in the bottom half */ if (hDevMemContext) { BM_CONTEXT *psBMContext = (BM_CONTEXT *) hDevMemContext; @@ -194,7 +312,7 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, psDeviceNode->pfnMMUGetCacheFlushRange(psMMUContext, &ui32CacheMasks[2]); } - + /* If we have an outstanding flush request then set the cachecontrol bit */ if (ui32CacheMasks[0] || ui32CacheMasks[1] || ui32CacheMasks[2] || ui32CacheMasks[3]) { psDevInfo->ui32CacheControl |= SGXMKIF_CC_INVAL_BIF_PD; @@ -202,10 +320,11 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, #endif #if defined(FIX_HW_BRN_28889) - - - - + /* + If the data cache and bif cache need invalidating there has been a cleanup + request. Therefore, we need to send the invalidate seperately and wait + for it to complete. + */ if ( (eCmdType != SGXMKIF_CMD_PROCESS_QUEUES) && ((psDevInfo->ui32CacheControl & SGXMKIF_CC_INVAL_DATA) != 0) && ((psDevInfo->ui32CacheControl & (SGXMKIF_CC_INVAL_BIF_PT | SGXMKIF_CC_INVAL_BIF_PD)) != 0)) @@ -228,7 +347,7 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, goto Exit; } - + /* Wait for the invalidate to happen */ #if !defined(NO_HARDWARE) if(PollForValueKM(&psSGXHostCtl->ui32InvalStatus, PVRSRV_USSE_EDM_BIF_INVAL_COMPLETE, @@ -243,7 +362,7 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, #endif #if defined(PDUMP) - + /* Pdump the poll as well. */ PDUMPCOMMENTWITHFLAGS(0, "Host Control - Poll for BIF cache invalidate request to complete"); PDUMPMEMPOL(psSGXHostCtlMemInfo, offsetof(SGXMKIF_HOST_CTL, ui32InvalStatus), @@ -252,7 +371,7 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, PDUMP_POLL_OPERATOR_EQUAL, 0, MAKEUNIQUETAG(psSGXHostCtlMemInfo)); - #endif + #endif /* PDUMP */ psSGXHostCtl->ui32InvalStatus &= ~(PVRSRV_USSE_EDM_BIF_INVAL_COMPLETE); PDUMPMEM(IMG_NULL, psSGXHostCtlMemInfo, offsetof(SGXMKIF_HOST_CTL, ui32CleanupStatus), sizeof(IMG_UINT32), 0, MAKEUNIQUETAG(psSGXHostCtlMemInfo)); @@ -267,7 +386,7 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, SGXMKIF_COMMAND sPDECacheCommand = {0}; IMG_DEV_PHYADDR sDevPAddr; - + /* Put the kernel info in the top 1/2 of the data */ psMMUContext = psDevInfo->hKernelMMUContext; psDeviceNode->pfnMMUGetPDPhysAddr(psMMUContext, &sDevPAddr); @@ -275,7 +394,7 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, sPDECacheCommand.ui32Data[1] = ui32CacheMasks[0]; sPDECacheCommand.ui32Data[2] = ui32CacheMasks[1]; - + /* Put the apps memory context in the bottom half */ if (hDevMemContext) { BM_CONTEXT *psBMContext = (BM_CONTEXT *) hDevMemContext; @@ -283,13 +402,13 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, psMMUContext = psBMContext->psMMUContext; psDeviceNode->pfnMMUGetPDPhysAddr(psMMUContext, &sDevPAddr); - + /* Or in 1 to the lsb to show we have a valid context */ sPDECacheCommand.ui32Data[3] = sDevPAddr.uiAddr | 1; sPDECacheCommand.ui32Data[4] = ui32CacheMasks[2]; sPDECacheCommand.ui32Data[5] = ui32CacheMasks[3]; } - + /* Only do a kick if there is any update */ if (sPDECacheCommand.ui32Data[1] | sPDECacheCommand.ui32Data[2] | sPDECacheCommand.ui32Data[4] | sPDECacheCommand.ui32Data[5]) { @@ -308,7 +427,11 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, } #endif #if defined(PDUMP) - + /* + * For persistent processes, the HW kicks should not go into the + * extended init phase; only keep memory transactions from the + * window system which are necessary to run the client app. + */ { PVRSRV_PER_PROCESS_DATA* psPerProc = PVRSRVFindPerProcessData(); if(psPerProc != IMG_NULL) @@ -316,12 +439,12 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, bPersistentProcess = psPerProc->bPDumpPersistent; } } -#endif +#endif /* PDUMP */ psKernelCCB = psDevInfo->psKernelCCBInfo; psSGXCommand = SGXAcquireKernelCCBSlot(psKernelCCB); - + /* Wait for CCB space timed out */ if(!psSGXCommand) { PVR_DPF((PVR_DBG_ERROR, "SGXScheduleCCBCommand: Wait for CCB space timed out")) ; @@ -329,18 +452,18 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, goto Exit; } - + /* embed cache control word */ psCommandData->ui32CacheControl = psDevInfo->ui32CacheControl; #if defined(PDUMP) - + /* Accumulate any cache invalidates that may have happened */ psDevInfo->sPDContext.ui32CacheControl |= psDevInfo->ui32CacheControl; #endif - + /* and clear it */ psDevInfo->ui32CacheControl = 0; - + /* Copy command data over */ *psSGXCommand = *psCommandData; if (eCmdType >= SGXMKIF_CMD_MAX) @@ -350,11 +473,13 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, goto Exit; } - if ((eCmdType == SGXMKIF_CMD_TA) && bLastInScene) + if (eCmdType == SGXMKIF_CMD_2D || + eCmdType == SGXMKIF_CMD_TRANSFER || + ((eCmdType == SGXMKIF_CMD_TA) && bLastInScene)) { SYS_DATA *psSysData; - + /* CPU cache clean control */ SysAcquireData(&psSysData); if(psSysData->ePendingCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_FLUSH) @@ -366,18 +491,18 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, OSCleanCPUCacheKM(); } - + /* Clear the pending op */ psSysData->ePendingCacheOpType = PVRSRV_MISC_INFO_CPUCACHEOP_NONE; } PVR_ASSERT(eCmdType < SGXMKIF_CMD_MAX); - psSGXCommand->ui32ServiceAddress = psDevInfo->aui32HostKickAddr[eCmdType]; + psSGXCommand->ui32ServiceAddress = psDevInfo->aui32HostKickAddr[eCmdType]; /* PRQA S 3689 */ /* misuse of enums for bounds checking */ #if defined(PDUMP) if ((ui32CallerID != ISR_ID) && (bPDumpIsSuspended == IMG_FALSE) && (bPersistentProcess == IMG_FALSE) ) { - + /* Poll for space in the CCB. */ PDUMPCOMMENTWITHFLAGS(ui32PDumpFlags, "Poll for space in the Kernel CCB\r\n"); PDUMPMEMPOL(psKernelCCB->psCCBCtlMemInfo, offsetof(PVRSRV_SGX_CCB_CTL, ui32ReadOffset), @@ -397,7 +522,7 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, ui32PDumpFlags, MAKEUNIQUETAG(psKernelCCB->psCCBMemInfo)); - + /* Overwrite cache control with pdump shadow */ PDUMPMEM(&psDevInfo->sPDContext.ui32CacheControl, psKernelCCB->psCCBMemInfo, psKernelCCB->ui32CCBDumpWOff * sizeof(SGXMKIF_COMMAND) + @@ -409,14 +534,14 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, if (PDumpIsCaptureFrameKM() || ((ui32PDumpFlags & PDUMP_FLAGS_CONTINUOUS) != 0)) { - + /* Clear cache invalidate shadow */ psDevInfo->sPDContext.ui32CacheControl = 0; } } #endif #if defined(FIX_HW_BRN_26620) && defined(SGX_FEATURE_SYSTEM_CACHE) && !defined(SGX_BYPASS_SYSTEM_CACHE) - + /* Make sure the previous command has been read before send the next one */ eError = PollForValueKM (psKernelCCB->pui32ReadOffset, *psKernelCCB->pui32WriteOffset, 0xFF, @@ -431,8 +556,9 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, } #endif - - + /* + Increment the write offset + */ *psKernelCCB->pui32WriteOffset = (*psKernelCCB->pui32WriteOffset + 1) & 255; #if defined(PDUMP) @@ -482,9 +608,16 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, *psDevInfo->pui32KernelCCBEventKicker = (*psDevInfo->pui32KernelCCBEventKicker + 1) & 0xFF; + /* + * New command submission is considered a proper handling of any pending APM + * event, so mark it as handled to prevent other host threads from taking + * action. + */ + psSGXHostCtl->ui32InterruptClearFlags |= PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER; + OSWriteMemoryBarrier(); - + /* Order is importent for post processor! */ PVR_TTRACE_UI32(PVRSRV_TRACE_GROUP_MKSYNC, PVRSRV_TRACE_CLASS_NONE, MKSYNC_TOKEN_KERNEL_CCB_OFFSET, *psKernelCCB->pui32WriteOffset); PVR_TTRACE_UI32(PVRSRV_TRACE_GROUP_MKSYNC, PVRSRV_TRACE_CLASS_NONE, @@ -506,15 +639,32 @@ PVRSRV_ERROR SGXScheduleCCBCommand(PVRSRV_DEVICE_NODE *psDeviceNode, OSMemoryBarrier(); #if defined(NO_HARDWARE) - + /* Increment read offset */ *psKernelCCB->pui32ReadOffset = (*psKernelCCB->pui32ReadOffset + 1) & 255; #endif + ui64KickCount++; Exit: return eError; } +/*! +****************************************************************************** + + @Function SGXScheduleCCBCommandKM + + @Description - Submits a CCB command and kicks the ukernel + + @Input psDeviceNode - pointer to SGX device node + @Input eCmdType - see SGXMKIF_CMD_* + @Input psCommandData - kernel CCB command + @Input ui32CallerID - KERNEL_ID or ISR_ID + @Input ui32PDumpFlags + + @Return ui32Error - success or failure + +******************************************************************************/ PVRSRV_ERROR SGXScheduleCCBCommandKM(PVRSRV_DEVICE_NODE *psDeviceNode, SGXMKIF_CMD_TYPE eCmdType, SGXMKIF_COMMAND *psCommandData, @@ -523,16 +673,47 @@ PVRSRV_ERROR SGXScheduleCCBCommandKM(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_HANDLE hDevMemContext, IMG_BOOL bLastInScene) { - PVRSRV_ERROR eError; + PVRSRV_ERROR eError; - + eError = PVRSRVPowerLock(ui32CallerID, IMG_FALSE); + if (eError == PVRSRV_ERROR_RETRY) + { + if (ui32CallerID == ISR_ID) + { + SYS_DATA *psSysData; + + /* + ISR failed to acquire lock so it must be held by a kernel thread. + Bring up and kick SGX if necessary when the lock is available. + */ + psDeviceNode->bReProcessDeviceCommandComplete = IMG_TRUE; + eError = PVRSRV_OK; + + SysAcquireData(&psSysData); + OSScheduleMISR(psSysData); + } + else + { + /* + Return to srvclient for retry. + */ + } + + return eError; + } + else if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"SGXScheduleCCBCommandKM failed to acquire lock - " + "ui32CallerID:%d eError:%u", ui32CallerID, eError)); + return eError; + } + + /* Note that a power-up has been dumped in the init phase. */ PDUMPSUSPEND(); - + /* Ensure that SGX is powered up before kicking the ukernel. */ eError = PVRSRVSetDevicePowerStateKM(psDeviceNode->sDevId.ui32DeviceIndex, - PVRSRV_DEV_POWER_STATE_ON, - ui32CallerID, - IMG_TRUE); + PVRSRV_DEV_POWER_STATE_ON); PDUMPRESUME(); @@ -542,33 +723,8 @@ PVRSRV_ERROR SGXScheduleCCBCommandKM(PVRSRV_DEVICE_NODE *psDeviceNode, } else { - if (eError == PVRSRV_ERROR_RETRY) - { - if (ui32CallerID == ISR_ID) - { - SYS_DATA *psSysData; - - - - - psDeviceNode->bReProcessDeviceCommandComplete = IMG_TRUE; - eError = PVRSRV_OK; - - SysAcquireData(&psSysData); - OSScheduleMISR(psSysData); - } - else - { - - - } - } - else - { - PVR_DPF((PVR_DBG_ERROR,"SGXScheduleCCBCommandKM failed to acquire lock - " - "ui32CallerID:%d eError:%u", ui32CallerID, eError)); - } - + PVR_DPF((PVR_DBG_ERROR,"SGXScheduleCCBCommandKM failed to acquire lock - " + "ui32CallerID:%d eError:%u", ui32CallerID, eError)); return eError; } @@ -579,6 +735,16 @@ PVRSRV_ERROR SGXScheduleCCBCommandKM(PVRSRV_DEVICE_NODE *psDeviceNode, } +/*! +****************************************************************************** + + @Function SGXScheduleProcessQueuesKM + + @Description - Software command complete handler + + @Input psDeviceNode - SGX device node + +******************************************************************************/ PVRSRV_ERROR SGXScheduleProcessQueuesKM(PVRSRV_DEVICE_NODE *psDeviceNode) { PVRSRV_ERROR eError; @@ -590,7 +756,7 @@ PVRSRV_ERROR SGXScheduleProcessQueuesKM(PVRSRV_DEVICE_NODE *psDeviceNode) ui32PowerStatus = psHostCtl->ui32PowerStatus; if ((ui32PowerStatus & PVRSRV_USSE_EDM_POWMAN_NO_WORK) != 0) { - + /* The ukernel has no work to do so don't waste power. */ return PVRSRV_OK; } @@ -605,11 +771,41 @@ PVRSRV_ERROR SGXScheduleProcessQueuesKM(PVRSRV_DEVICE_NODE *psDeviceNode) } +/*! +****************************************************************************** + + @Function SGXIsDevicePowered + + @Description + + Whether the device is powered, for the purposes of lockup detection. + + @Input psDeviceNode - pointer to device node + + @Return IMG_BOOL : Whether device is powered + +******************************************************************************/ IMG_BOOL SGXIsDevicePowered(PVRSRV_DEVICE_NODE *psDeviceNode) { return PVRSRVIsDevicePowered(psDeviceNode->sDevId.ui32DeviceIndex); } +/*! +******************************************************************************* + + @Function SGXGetInternalDevInfoKM + + @Description + Gets device information that is not intended to be passed + on beyond the srvclient libs. + + @Input hDevCookie + + @Output psSGXInternalDevInfo + + @Return PVRSRV_ERROR : + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR SGXGetInternalDevInfoKM(IMG_HANDLE hDevCookie, #if defined (SUPPORT_SID_INTERFACE) @@ -623,7 +819,7 @@ PVRSRV_ERROR SGXGetInternalDevInfoKM(IMG_HANDLE hDevCookie, psSGXInternalDevInfo->ui32Flags = psDevInfo->ui32Flags; psSGXInternalDevInfo->bForcePTOff = (IMG_BOOL)psDevInfo->bForcePTOff; - + /* This should be patched up by OS bridge code */ psSGXInternalDevInfo->hHostCtlKernelMemInfoHandle = (IMG_HANDLE)psDevInfo->psKernelSGXHostCtlMemInfo; @@ -631,6 +827,19 @@ PVRSRV_ERROR SGXGetInternalDevInfoKM(IMG_HANDLE hDevCookie, } +/***************************************************************************** + FUNCTION : SGXCleanupRequest + + PURPOSE : Wait for the microkernel to clean up its references to either a + render context or render target. + + PARAMETERS : psDeviceNode - SGX device node + psHWDataDevVAddr - Device Address of the resource + ui32CleanupType - PVRSRV_CLEANUPCMD_* + bForceCleanup - Skips sync polling + + RETURNS : error status +*****************************************************************************/ PVRSRV_ERROR SGXCleanupRequest(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_DEV_VIRTADDR *psHWDataDevVAddr, IMG_UINT32 ui32CleanupType, @@ -654,11 +863,12 @@ PVRSRV_ERROR SGXCleanupRequest(PVRSRV_DEVICE_NODE *psDeviceNode, if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"SGXCleanupRequest: Failed to submit clean-up command")); + SGXDumpDebugInfo(psDevInfo, IMG_FALSE); PVR_DBG_BREAK; return eError; } - + /* Wait for the uKernel process the cleanup request */ #if !defined(NO_HARDWARE) if(PollForValueKM(&psHostCtl->ui32CleanupStatus, PVRSRV_USSE_EDM_CLEANUPCMD_COMPLETE, @@ -669,38 +879,59 @@ PVRSRV_ERROR SGXCleanupRequest(PVRSRV_DEVICE_NODE *psDeviceNode, { PVR_DPF((PVR_DBG_ERROR,"SGXCleanupRequest: Wait for uKernel to clean up (%u) failed", ui32CleanupType)); eError = PVRSRV_ERROR_TIMEOUT; + SGXDumpDebugInfo(psDevInfo, IMG_FALSE); PVR_DBG_BREAK; } #endif #if defined(PDUMP) - + /* + Pdump the poll as well. + Note: + We don't expect the cleanup to report busy as the client should have + ensured the the resource has been finished with before requesting + it's cleanup. This isn't true of the abnormal termination case but + we don't expect to PDump that. Unless/until PDump has flow control + there isn't anything else we can do. + */ PDUMPCOMMENTWITHFLAGS(0, "Host Control - Poll for clean-up request to complete"); PDUMPMEMPOL(psHostCtlMemInfo, offsetof(SGXMKIF_HOST_CTL, ui32CleanupStatus), - PVRSRV_USSE_EDM_CLEANUPCMD_COMPLETE, - PVRSRV_USSE_EDM_CLEANUPCMD_COMPLETE, + PVRSRV_USSE_EDM_CLEANUPCMD_COMPLETE | PVRSRV_USSE_EDM_CLEANUPCMD_DONE, + PVRSRV_USSE_EDM_CLEANUPCMD_COMPLETE | PVRSRV_USSE_EDM_CLEANUPCMD_DONE, PDUMP_POLL_OPERATOR_EQUAL, 0, MAKEUNIQUETAG(psHostCtlMemInfo)); - #endif + #endif /* PDUMP */ if (eError != PVRSRV_OK) { return eError; } } + + if (psHostCtl->ui32CleanupStatus & PVRSRV_USSE_EDM_CLEANUPCMD_BUSY) + { + /* Only one flag should be set */ + PVR_ASSERT((psHostCtl->ui32CleanupStatus & PVRSRV_USSE_EDM_CLEANUPCMD_DONE) == 0); + eError = PVRSRV_ERROR_RETRY; + psHostCtl->ui32CleanupStatus &= ~(PVRSRV_USSE_EDM_CLEANUPCMD_COMPLETE | PVRSRV_USSE_EDM_CLEANUPCMD_BUSY); + } + else + { + eError = PVRSRV_OK; + psHostCtl->ui32CleanupStatus &= ~(PVRSRV_USSE_EDM_CLEANUPCMD_COMPLETE | PVRSRV_USSE_EDM_CLEANUPCMD_DONE); + } - psHostCtl->ui32CleanupStatus &= ~(PVRSRV_USSE_EDM_CLEANUPCMD_COMPLETE); PDUMPMEM(IMG_NULL, psHostCtlMemInfo, offsetof(SGXMKIF_HOST_CTL, ui32CleanupStatus), sizeof(IMG_UINT32), 0, MAKEUNIQUETAG(psHostCtlMemInfo)); - + /* Request the cache invalidate */ #if defined(SGX_FEATURE_SYSTEM_CACHE) psDevInfo->ui32CacheControl |= (SGXMKIF_CC_INVAL_BIF_SL | SGXMKIF_CC_INVAL_DATA); #else psDevInfo->ui32CacheControl |= SGXMKIF_CC_INVAL_DATA; #endif - return PVRSRV_OK; + return eError; } @@ -710,6 +941,8 @@ typedef struct _SGX_HW_RENDER_CONTEXT_CLEANUP_ PVRSRV_KERNEL_MEM_INFO *psHWRenderContextMemInfo; IMG_HANDLE hBlockAlloc; PRESMAN_ITEM psResItem; + IMG_BOOL bCleanupTimerRunning; + IMG_PVOID pvTimeData; } SGX_HW_RENDER_CONTEXT_CLEANUP; @@ -727,16 +960,44 @@ static PVRSRV_ERROR SGXCleanupHWRenderContextCallback(IMG_PVOID pvParam, PVRSRV_CLEANUPCMD_RC, bForceCleanup); - - PVRSRVFreeDeviceMemKM(psCleanup->psDeviceNode, - psCleanup->psHWRenderContextMemInfo); + if (eError == PVRSRV_ERROR_RETRY) + { + if (!psCleanup->bCleanupTimerRunning) + { + OSTimeCreateWithUSOffset(&psCleanup->pvTimeData, MAX_CLEANUP_TIME_US); + psCleanup->bCleanupTimerRunning = IMG_TRUE; + } + else + { + if (OSTimeHasTimePassed(psCleanup->pvTimeData)) + { + eError = PVRSRV_ERROR_TIMEOUT_POLLING_FOR_VALUE; + psCleanup->bCleanupTimerRunning = IMG_FALSE; + OSTimeDestroy(psCleanup->pvTimeData); + } + } + } + else + { + if (psCleanup->bCleanupTimerRunning) + { + OSTimeDestroy(psCleanup->pvTimeData); + } + } - - OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, - sizeof(SGX_HW_RENDER_CONTEXT_CLEANUP), - psCleanup, - psCleanup->hBlockAlloc); + if (eError != PVRSRV_ERROR_RETRY) + { + /* Free the Device Mem allocated */ + PVRSRVFreeDeviceMemKM(psCleanup->psDeviceNode, + psCleanup->psHWRenderContextMemInfo); + /* Finally, free the cleanup structure itself */ + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(SGX_HW_RENDER_CONTEXT_CLEANUP), + psCleanup, + psCleanup->hBlockAlloc); + /*not nulling pointer, copy on stack*/ + } return eError; } @@ -747,6 +1008,8 @@ typedef struct _SGX_HW_TRANSFER_CONTEXT_CLEANUP_ PVRSRV_KERNEL_MEM_INFO *psHWTransferContextMemInfo; IMG_HANDLE hBlockAlloc; PRESMAN_ITEM psResItem; + IMG_BOOL bCleanupTimerRunning; + IMG_PVOID pvTimeData; } SGX_HW_TRANSFER_CONTEXT_CLEANUP; @@ -764,16 +1027,44 @@ static PVRSRV_ERROR SGXCleanupHWTransferContextCallback(IMG_PVOID pvParam, PVRSRV_CLEANUPCMD_TC, bForceCleanup); - - PVRSRVFreeDeviceMemKM(psCleanup->psDeviceNode, - psCleanup->psHWTransferContextMemInfo); + if (eError == PVRSRV_ERROR_RETRY) + { + if (!psCleanup->bCleanupTimerRunning) + { + OSTimeCreateWithUSOffset(&psCleanup->pvTimeData, MAX_CLEANUP_TIME_US); + psCleanup->bCleanupTimerRunning = IMG_TRUE; + } + else + { + if (OSTimeHasTimePassed(psCleanup->pvTimeData)) + { + eError = PVRSRV_ERROR_TIMEOUT_POLLING_FOR_VALUE; + psCleanup->bCleanupTimerRunning = IMG_FALSE; + OSTimeDestroy(psCleanup->pvTimeData); + } + } + } + else + { + if (psCleanup->bCleanupTimerRunning) + { + OSTimeDestroy(psCleanup->pvTimeData); + } + } - - OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, - sizeof(SGX_HW_TRANSFER_CONTEXT_CLEANUP), - psCleanup, - psCleanup->hBlockAlloc); + if (eError != PVRSRV_ERROR_RETRY) + { + /* Free the Device Mem allocated */ + PVRSRVFreeDeviceMemKM(psCleanup->psDeviceNode, + psCleanup->psHWTransferContextMemInfo); + /* Finally, free the cleanup structure itself */ + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(SGX_HW_TRANSFER_CONTEXT_CLEANUP), + psCleanup, + psCleanup->hBlockAlloc); + /*not nulling pointer, copy on stack*/ + } return eError; } @@ -824,6 +1115,9 @@ IMG_HANDLE SGXRegisterHWRenderContextKM(IMG_HANDLE hDeviceNode, | PVRSRV_MEM_CACHE_CONSISTENT, ui32HWRenderContextSize, 32, + IMG_NULL, + 0, + 0,0,0,IMG_NULL, /* No sparse mapping data */ &psCleanup->psHWRenderContextMemInfo, "HW Render Context"); @@ -844,10 +1138,10 @@ IMG_HANDLE SGXRegisterHWRenderContextKM(IMG_HANDLE hDeviceNode, goto exit2; } - + /* Pass the DevVAddr of the new context back up through the bridge */ psHWRenderContextDevVAddr->uiAddr = psCleanup->psHWRenderContextMemInfo->sDevVAddr.uiAddr; - + /* Retrieve the PDDevPAddr */ eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevMemContextInt, hDevMemContext, @@ -862,11 +1156,12 @@ IMG_HANDLE SGXRegisterHWRenderContextKM(IMG_HANDLE hDeviceNode, psMMUContext = BM_GetMMUContextFromMemContext(hDevMemContextInt); sPDDevPAddr = psDeviceNode->pfnMMUGetPDDevPAddr(psMMUContext); - - - - - + /* + patch-in the Page-Directory Device-Physical address. Note that this is + copied-in one byte at a time, as we have no guarantee that the usermode- + provided ui32OffsetToPDDevPAddr is a validly-aligned address for the + current CPU architecture. + */ pSrc = (IMG_UINT8 *)&sPDDevPAddr; pDst = (IMG_UINT8 *)psCleanup->psHWRenderContextMemInfo->pvLinAddrKM; pDst += ui32OffsetToPDDevPAddr; @@ -877,7 +1172,7 @@ IMG_HANDLE SGXRegisterHWRenderContextKM(IMG_HANDLE hDeviceNode, } #if defined(PDUMP) - + /* PDUMP the HW context */ PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "HW Render context struct"); PDUMPMEM( @@ -888,7 +1183,7 @@ IMG_HANDLE SGXRegisterHWRenderContextKM(IMG_HANDLE hDeviceNode, PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psCleanup->psHWRenderContextMemInfo)); - + /* PDUMP the PDDevPAddr */ PDUMPCOMMENT("Page directory address in HW render context"); PDUMPPDDEVPADDR( psCleanup->psHWRenderContextMemInfo, @@ -900,6 +1195,7 @@ IMG_HANDLE SGXRegisterHWRenderContextKM(IMG_HANDLE hDeviceNode, psCleanup->hBlockAlloc = hBlockAlloc; psCleanup->psDeviceNode = psDeviceNode; + psCleanup->bCleanupTimerRunning = IMG_FALSE; psResItem = ResManRegisterRes(psPerProc->hResManContext, RESMAN_TYPE_HW_RENDER_CONTEXT, @@ -917,6 +1213,7 @@ IMG_HANDLE SGXRegisterHWRenderContextKM(IMG_HANDLE hDeviceNode, return (IMG_HANDLE)psCleanup; +/* Error exit paths */ exit2: PVRSRVFreeDeviceMemKM(hDeviceNode, psCleanup->psHWRenderContextMemInfo); @@ -925,7 +1222,7 @@ exit1: sizeof(SGX_HW_RENDER_CONTEXT_CLEANUP), psCleanup, psCleanup->hBlockAlloc); - + /*not nulling pointer, out of scope*/ exit0: return IMG_NULL; } @@ -998,6 +1295,9 @@ IMG_HANDLE SGXRegisterHWTransferContextKM(IMG_HANDLE hDeviceNode, | PVRSRV_MEM_CACHE_CONSISTENT, ui32HWTransferContextSize, 32, + IMG_NULL, + 0, + 0,0,0,IMG_NULL, /* No sparse mapping data */ &psCleanup->psHWTransferContextMemInfo, "HW Render Context"); @@ -1018,10 +1318,10 @@ IMG_HANDLE SGXRegisterHWTransferContextKM(IMG_HANDLE hDeviceNode, goto exit2; } - + /* Pass the DevVAddr of the new context back up through the bridge */ psHWTransferContextDevVAddr->uiAddr = psCleanup->psHWTransferContextMemInfo->sDevVAddr.uiAddr; - + /* Retrieve the PDDevPAddr */ eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevMemContextInt, hDevMemContext, @@ -1036,11 +1336,12 @@ IMG_HANDLE SGXRegisterHWTransferContextKM(IMG_HANDLE hDeviceNode, psMMUContext = BM_GetMMUContextFromMemContext(hDevMemContextInt); sPDDevPAddr = psDeviceNode->pfnMMUGetPDDevPAddr(psMMUContext); - - - - - + /* + patch-in the Page-Directory Device-Physical address. Note that this is + copied-in one byte at a time, as we have no guarantee that the usermode- + provided ui32OffsetToPDDevPAddr is a validly-aligned address for the + current CPU architecture. + */ pSrc = (IMG_UINT8 *)&sPDDevPAddr; pDst = (IMG_UINT8 *)psCleanup->psHWTransferContextMemInfo->pvLinAddrKM; pDst += ui32OffsetToPDDevPAddr; @@ -1051,7 +1352,7 @@ IMG_HANDLE SGXRegisterHWTransferContextKM(IMG_HANDLE hDeviceNode, } #if defined(PDUMP) - + /* PDUMP the HW Transfer Context */ PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "HW Transfer context struct"); PDUMPMEM( @@ -1062,7 +1363,7 @@ IMG_HANDLE SGXRegisterHWTransferContextKM(IMG_HANDLE hDeviceNode, PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psCleanup->psHWTransferContextMemInfo)); - + /* PDUMP the PDDevPAddr */ PDUMPCOMMENT("Page directory address in HW transfer context"); PDUMPPDDEVPADDR( @@ -1075,6 +1376,7 @@ IMG_HANDLE SGXRegisterHWTransferContextKM(IMG_HANDLE hDeviceNode, psCleanup->hBlockAlloc = hBlockAlloc; psCleanup->psDeviceNode = psDeviceNode; + psCleanup->bCleanupTimerRunning = IMG_FALSE; psResItem = ResManRegisterRes(psPerProc->hResManContext, RESMAN_TYPE_HW_TRANSFER_CONTEXT, @@ -1092,6 +1394,7 @@ IMG_HANDLE SGXRegisterHWTransferContextKM(IMG_HANDLE hDeviceNode, return (IMG_HANDLE)psCleanup; +/* Error exit paths */ exit2: PVRSRVFreeDeviceMemKM(hDeviceNode, psCleanup->psHWTransferContextMemInfo); @@ -1100,7 +1403,7 @@ exit1: sizeof(SGX_HW_TRANSFER_CONTEXT_CLEANUP), psCleanup, psCleanup->hBlockAlloc); - + /*not nulling pointer, out of scope*/ exit0: return IMG_NULL; @@ -1154,9 +1457,10 @@ PVRSRV_ERROR SGXSetTransferContextPriorityKM( return PVRSRV_ERROR_INVALID_PARAMS; } - - - + /* + cannot be sure that offset (passed from user-land) is safe to deref + as a word-ptr on current CPU arch: copy one byte at a time. + */ pDst = (IMG_UINT8 *)psCleanup->psHWTransferContextMemInfo->pvLinAddrKM; pDst += ui32OffsetOfPriorityField; pSrc = (IMG_UINT8 *)&ui32Priority; @@ -1195,9 +1499,10 @@ PVRSRV_ERROR SGXSetRenderContextPriorityKM( return PVRSRV_ERROR_INVALID_PARAMS; } - - - + /* + cannot be sure that offset (passed from user-land) is safe to deref + as a word-ptr on current CPU arch: copy one byte at a time. + */ pDst = (IMG_UINT8 *)psCleanup->psHWRenderContextMemInfo->pvLinAddrKM; pDst += ui32OffsetOfPriorityField; @@ -1218,6 +1523,8 @@ typedef struct _SGX_HW_2D_CONTEXT_CLEANUP_ PVRSRV_KERNEL_MEM_INFO *psHW2DContextMemInfo; IMG_HANDLE hBlockAlloc; PRESMAN_ITEM psResItem; + IMG_BOOL bCleanupTimerRunning; + IMG_PVOID pvTimeData; } SGX_HW_2D_CONTEXT_CLEANUP; static PVRSRV_ERROR SGXCleanupHW2DContextCallback(IMG_PVOID pvParam, @@ -1229,23 +1536,50 @@ static PVRSRV_ERROR SGXCleanupHW2DContextCallback(IMG_PVOID pvParam, PVR_UNREFERENCED_PARAMETER(ui32Param); - + /* First, ensure the context is no longer being utilised */ eError = SGXCleanupRequest(psCleanup->psDeviceNode, &psCleanup->psHW2DContextMemInfo->sDevVAddr, PVRSRV_CLEANUPCMD_2DC, bForceCleanup); - - PVRSRVFreeDeviceMemKM(psCleanup->psDeviceNode, - psCleanup->psHW2DContextMemInfo); - - - OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, - sizeof(SGX_HW_2D_CONTEXT_CLEANUP), - psCleanup, - psCleanup->hBlockAlloc); - + if (eError == PVRSRV_ERROR_RETRY) + { + if (!psCleanup->bCleanupTimerRunning) + { + OSTimeCreateWithUSOffset(&psCleanup->pvTimeData, MAX_CLEANUP_TIME_US); + psCleanup->bCleanupTimerRunning = IMG_TRUE; + } + else + { + if (OSTimeHasTimePassed(psCleanup->pvTimeData)) + { + eError = PVRSRV_ERROR_TIMEOUT_POLLING_FOR_VALUE; + psCleanup->bCleanupTimerRunning = IMG_FALSE; + OSTimeDestroy(psCleanup->pvTimeData); + } + } + } + else + { + if (psCleanup->bCleanupTimerRunning) + { + OSTimeDestroy(psCleanup->pvTimeData); + } + } + if (eError != PVRSRV_ERROR_RETRY) + { + /* Free the Device Mem allocated */ + PVRSRVFreeDeviceMemKM(psCleanup->psDeviceNode, + psCleanup->psHW2DContextMemInfo); + + /* Finally, free the cleanup structure itself */ + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(SGX_HW_2D_CONTEXT_CLEANUP), + psCleanup, + psCleanup->hBlockAlloc); + /*not nulling pointer, copy on stack*/ + } return eError; } @@ -1294,6 +1628,9 @@ IMG_HANDLE SGXRegisterHW2DContextKM(IMG_HANDLE hDeviceNode, | PVRSRV_MEM_CACHE_CONSISTENT, ui32HW2DContextSize, 32, + IMG_NULL, + 0, + 0,0,0,IMG_NULL, /* No sparse mapping data */ &psCleanup->psHW2DContextMemInfo, "HW 2D Context"); @@ -1313,10 +1650,10 @@ IMG_HANDLE SGXRegisterHW2DContextKM(IMG_HANDLE hDeviceNode, goto exit2; } - + /* Pass the DevVAddr of the new context back up through the bridge */ psHW2DContextDevVAddr->uiAddr = psCleanup->psHW2DContextMemInfo->sDevVAddr.uiAddr; - + /* Retrieve the PDDevPAddr */ eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &hDevMemContextInt, hDevMemContext, @@ -1331,11 +1668,12 @@ IMG_HANDLE SGXRegisterHW2DContextKM(IMG_HANDLE hDeviceNode, psMMUContext = BM_GetMMUContextFromMemContext(hDevMemContextInt); sPDDevPAddr = psDeviceNode->pfnMMUGetPDDevPAddr(psMMUContext); - - - - - + /* + patch-in the Page-Directory Device-Physical address. Note that this is + copied-in one byte at a time, as we have no guarantee that the usermode- + provided ui32OffsetToPDDevPAddr is a validly-aligned address for the + current CPU architecture. + */ pSrc = (IMG_UINT8 *)&sPDDevPAddr; pDst = (IMG_UINT8 *)psCleanup->psHW2DContextMemInfo->pvLinAddrKM; pDst += ui32OffsetToPDDevPAddr; @@ -1346,7 +1684,7 @@ IMG_HANDLE SGXRegisterHW2DContextKM(IMG_HANDLE hDeviceNode, } #if defined(PDUMP) - + /* PDUMP the HW 2D Context */ PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "HW 2D context struct"); PDUMPMEM( @@ -1357,7 +1695,7 @@ IMG_HANDLE SGXRegisterHW2DContextKM(IMG_HANDLE hDeviceNode, PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psCleanup->psHW2DContextMemInfo)); - + /* PDUMP the PDDevPAddr */ PDUMPCOMMENT("Page directory address in HW 2D transfer context"); PDUMPPDDEVPADDR( psCleanup->psHW2DContextMemInfo, @@ -1369,6 +1707,7 @@ IMG_HANDLE SGXRegisterHW2DContextKM(IMG_HANDLE hDeviceNode, psCleanup->hBlockAlloc = hBlockAlloc; psCleanup->psDeviceNode = psDeviceNode; + psCleanup->bCleanupTimerRunning = IMG_FALSE; psResItem = ResManRegisterRes(psPerProc->hResManContext, RESMAN_TYPE_HW_2D_CONTEXT, @@ -1386,6 +1725,7 @@ IMG_HANDLE SGXRegisterHW2DContextKM(IMG_HANDLE hDeviceNode, return (IMG_HANDLE)psCleanup; +/* Error exit paths */ exit2: PVRSRVFreeDeviceMemKM(hDeviceNode, psCleanup->psHW2DContextMemInfo); @@ -1394,7 +1734,7 @@ exit1: sizeof(SGX_HW_2D_CONTEXT_CLEANUP), psCleanup, psCleanup->hBlockAlloc); - + /*not nulling pointer, out of scope*/ exit0: return IMG_NULL; } @@ -1418,8 +1758,16 @@ PVRSRV_ERROR SGXUnregisterHW2DContextKM(IMG_HANDLE hHW2DContext, IMG_BOOL bForce return eError; } -#endif +#endif /* #if defined(SGX_FEATURE_2D_HARDWARE)*/ +/*!**************************************************************************** + @Function SGX2DQuerySyncOpsCompleteKM + + @Input psSyncInfo : Sync object to be queried + + @Return IMG_TRUE - ops complete, IMG_FALSE - ops pending + +******************************************************************************/ #ifdef INLINE_IS_PRAGMA #pragma inline(SGX2DQuerySyncOpsComplete) #endif @@ -1436,6 +1784,16 @@ IMG_BOOL SGX2DQuerySyncOpsComplete(PVRSRV_KERNEL_SYNC_INFO *psSyncInfo, ); } +/*!**************************************************************************** + @Function SGX2DQueryBlitsCompleteKM + + @Input psDevInfo : SGX device info structure + + @Input psSyncInfo : Sync object to be queried + + @Return PVRSRV_ERROR + +******************************************************************************/ IMG_EXPORT PVRSRV_ERROR SGX2DQueryBlitsCompleteKM(PVRSRV_SGXDEV_INFO *psDevInfo, PVRSRV_KERNEL_SYNC_INFO *psSyncInfo, @@ -1452,20 +1810,20 @@ PVRSRV_ERROR SGX2DQueryBlitsCompleteKM(PVRSRV_SGXDEV_INFO *psDevInfo, if(SGX2DQuerySyncOpsComplete(psSyncInfo, ui32ReadOpsPending, ui32WriteOpsPending)) { - + /* Instant success */ PVR_DPF((PVR_DBG_CALLTRACE, "SGX2DQueryBlitsCompleteKM: No wait. Blits complete.")); return PVRSRV_OK; } - + /* Not complete yet */ if (!bWaitForComplete) { - + /* Just report not complete */ PVR_DPF((PVR_DBG_CALLTRACE, "SGX2DQueryBlitsCompleteKM: No wait. Ops pending.")); return PVRSRV_ERROR_CMD_NOT_PROCESSED; } - + /* Start polling */ PVR_DPF((PVR_DBG_MESSAGE, "SGX2DQueryBlitsCompleteKM: Ops pending. Start polling.")); LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) @@ -1474,7 +1832,7 @@ PVRSRV_ERROR SGX2DQueryBlitsCompleteKM(PVRSRV_SGXDEV_INFO *psDevInfo, if(SGX2DQuerySyncOpsComplete(psSyncInfo, ui32ReadOpsPending, ui32WriteOpsPending)) { - + /* Success */ PVR_DPF((PVR_DBG_CALLTRACE, "SGX2DQueryBlitsCompleteKM: Wait over. Blits complete.")); return PVRSRV_OK; } @@ -1482,7 +1840,7 @@ PVRSRV_ERROR SGX2DQueryBlitsCompleteKM(PVRSRV_SGXDEV_INFO *psDevInfo, OSSleepms(1); } END_LOOP_UNTIL_TIMEOUT(); - + /* Timed out */ PVR_DPF((PVR_DBG_ERROR,"SGX2DQueryBlitsCompleteKM: Timed out. Ops pending.")); #if defined(DEBUG) @@ -1533,54 +1891,21 @@ IMG_UINT32 SGXConvertTimeStamp(PVRSRV_SGXDEV_INFO *psDevInfo, ui32Clocksx16 = (IMG_UINT32)(ui64Clocks / 16); return ui32Clocksx16; -#endif +#endif /* EUR_CR_TIMER */ } IMG_VOID SGXWaitClocks(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32SGXClocks) { - - + /* + Round up to the next microsecond. + */ OSWaitus(1 + (ui32SGXClocks * 1000000 / psDevInfo->ui32CoreClockSpeed)); } -IMG_EXPORT -PVRSRV_ERROR PVRSRVGetSGXRevDataKM(PVRSRV_DEVICE_NODE* psDeviceNode, IMG_UINT32 *pui32SGXCoreRev, - IMG_UINT32 *pui32SGXCoreID) -{ - PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; - SGX_MISC_INFO sMiscInfo; - PVRSRV_ERROR eError; - - sMiscInfo.eRequest = SGX_MISC_INFO_REQUEST_SGXREV; - eError = SGXGetMiscInfoKM(psDevInfo, &sMiscInfo, psDeviceNode, NULL); - - *pui32SGXCoreRev = sMiscInfo.uData.sSGXFeatures.ui32CoreRev; - *pui32SGXCoreID = sMiscInfo.uData.sSGXFeatures.ui32CoreID; - return eError; -} - - -PVRSRV_ERROR SGXContextSuspend(PVRSRV_DEVICE_NODE *psDeviceNode, - IMG_DEV_VIRTADDR *psHWContextDevVAddr, - IMG_BOOL bResume) -{ - PVRSRV_ERROR eError; - SGXMKIF_COMMAND sCommand = {0}; - - sCommand.ui32Data[0] = psHWContextDevVAddr->uiAddr; - sCommand.ui32Data[1] = bResume ? PVRSRV_CTXSUSPCMD_RESUME : PVRSRV_CTXSUSPCMD_SUSPEND; - - eError = SGXScheduleCCBCommandKM(psDeviceNode, SGXMKIF_CMD_CONTEXTSUSPEND, &sCommand, KERNEL_ID, 0, IMG_NULL, IMG_FALSE); - if (eError != PVRSRV_OK) - { - PVR_DPF((PVR_DBG_ERROR,"SGXContextSuspend: Failed to submit context suspend command")); - return eError; - } - - return eError; -} - +/****************************************************************************** + End of file (sgxutils.c) +******************************************************************************/ diff --git a/sgx/services4/srvkm/devices/sgx/sgxutils.h b/sgx/services4/srvkm/devices/sgx/sgxutils.h index ae6dbc7..d21ad02 100644 --- a/sgx/services4/srvkm/devices/sgx/sgxutils.h +++ b/sgx/services4/srvkm/devices/sgx/sgxutils.h @@ -1,33 +1,50 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Device specific utility routines declarations +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Inline functions/structures specific to SGX +@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 "perproc.h" #include "sgxinfokm.h" - +/* PRQA S 3410 7 */ /* macros require the absence of some brackets */ #define CCB_OFFSET_IS_VALID(type, psCCBMemInfo, psCCBKick, offset) \ ((sizeof(type) <= (psCCBMemInfo)->uAllocSize) && \ ((psCCBKick)->offset <= (psCCBMemInfo)->uAllocSize - sizeof(type))) @@ -36,6 +53,8 @@ ((type *)(((IMG_CHAR *)(psCCBMemInfo)->pvLinAddrKM) + \ (psCCBKick)->offset)) +extern IMG_UINT64 ui64KickCount; + IMG_IMPORT IMG_VOID SGXTestActivePowerEvent(PVRSRV_DEVICE_NODE *psDeviceNode, @@ -123,6 +142,21 @@ IMG_UINT32 SGXConvertTimeStamp(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32TimeWraps, IMG_UINT32 ui32Time); +/*! +******************************************************************************* + + @Function SGXWaitClocks + + @Description + + Wait for a specified number of SGX clock cycles to elapse. + + @Input psDevInfo - SGX Device Info + @Input ui32SGXClocks - number of clock cycles to wait + + @Return IMG_VOID + +******************************************************************************/ IMG_VOID SGXWaitClocks(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32SGXClocks); @@ -135,7 +169,28 @@ IMG_IMPORT PVRSRV_ERROR PVRSRVGetSGXRevDataKM(PVRSRV_DEVICE_NODE* psDeviceNode, IMG_UINT32 *pui32SGXCoreRev, IMG_UINT32 *pui32SGXCoreID); +/*! +****************************************************************************** + + @Function SGXContextSuspend + + @Description - Interface to the SGX microkernel to instruct it to suspend or + resume processing on a given context. This will interrupt current + processing of this context if a task is already running and is + interruptable. + + @Input psDeviceNode SGX device node + @Input psHWContextDevVAddr SGX virtual address of the context to be suspended + or resumed. Can be of type SGXMKIF_HWRENDERCONTEXT, + SGXMKIF_HWTRANSFERCONTEXT or SGXMKIF_HW2DCONTEXT + @Input bResume IMG_TRUE to put a context into suspend state, + IMG_FALSE to resume a previously suspended context + +******************************************************************************/ PVRSRV_ERROR SGXContextSuspend(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_DEV_VIRTADDR *psHWContextDevVAddr, IMG_BOOL bResume); +/****************************************************************************** + End of file (sgxutils.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/env/linux/Kbuild.mk b/sgx/services4/srvkm/env/linux/Kbuild.mk index 95df225..b101a5f 100755..100644 --- a/sgx/services4/srvkm/env/linux/Kbuild.mk +++ b/sgx/services4/srvkm/env/linux/Kbuild.mk @@ -1,26 +1,43 @@ -# -# Copyright (C) Imagination Technologies Ltd. All rights reserved. +########################################################################### ### +#@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +#@License Dual MIT/GPLv2 # -# 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. +# The contents of this file are subject to the MIT license as set out below. # -# 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. +# 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: # -# 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 above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. # -# The full GNU General Public License is included in this distribution in -# the file called "COPYING". -# -# Contact Information: -# Imagination Technologies Ltd. <gpl-support@imgtec.com> -# Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK +# 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. +# +### ########################################################################### $(PVRSRV_MODNAME)-y += \ services4/srvkm/env/linux/osfunc.o \ @@ -40,22 +57,36 @@ $(PVRSRV_MODNAME)-y += \ services4/srvkm/common/deviceclass.o \ services4/srvkm/common/handle.o \ services4/srvkm/common/hash.o \ + services4/srvkm/common/lists.o \ + services4/srvkm/common/mem.o \ + services4/srvkm/common/mem_debug.o \ services4/srvkm/common/metrics.o \ + services4/srvkm/common/osfunc_common.o \ + services4/srvkm/common/pdump_common.o \ + services4/srvkm/common/perproc.o \ + services4/srvkm/common/power.o \ services4/srvkm/common/pvrsrv.o \ services4/srvkm/common/queue.o \ services4/srvkm/common/ra.o \ + services4/srvkm/common/refcount.o \ services4/srvkm/common/resman.o \ - services4/srvkm/common/power.o \ - services4/srvkm/common/mem.o \ - services4/srvkm/common/pdump_common.o \ services4/srvkm/bridged/bridged_support.o \ services4/srvkm/bridged/bridged_pvr_bridge.o \ - services4/srvkm/common/perproc.o \ services4/system/$(PVR_SYSTEM)/sysconfig.o \ - services4/system/$(PVR_SYSTEM)/sysutils.o \ - services4/srvkm/common/lists.o \ - services4/srvkm/common/mem_debug.o \ - services4/srvkm/common/osfunc_common.o + services4/system/$(PVR_SYSTEM)/sysutils.o + +$(PVRSRV_MODNAME)-$(CONFIG_ION_OMAP) += \ + services4/srvkm/env/linux/ion.o + +ifeq ($(SUPPORT_ION),1) +$(PVRSRV_MODNAME)-y += \ + services4/srvkm/env/linux/ion.o +endif + +ifeq ($(TTRACE),1) +$(PVRSRV_MODNAME)-y += \ + services4/srvkm/common/ttrace.o +endif ifneq ($(W),1) CFLAGS_osfunc.o := -Werror @@ -89,6 +120,7 @@ CFLAGS_perproc.o := -Werror CFLAGS_lists.o := -Werror CFLAGS_mem_debug.o := -Werror CFLAGS_osfunc_common.o := -Werror +CFLAGS_refcount.o := -Werror endif # SUPPORT_SGX==1 only diff --git a/sgx/services4/srvkm/env/linux/Linux.mk b/sgx/services4/srvkm/env/linux/Linux.mk index 0ea43aa..b5e9de4 100755..100644 --- a/sgx/services4/srvkm/env/linux/Linux.mk +++ b/sgx/services4/srvkm/env/linux/Linux.mk @@ -1,27 +1,43 @@ -# -# Copyright (C) Imagination Technologies Ltd. All rights reserved. +########################################################################### ### +#@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +#@License Dual MIT/GPLv2 # -# 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. +# The contents of this file are subject to the MIT license as set out below. # -# 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. +# 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: # -# 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 above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. # -# The full GNU General Public License is included in this distribution in -# the file called "COPYING". -# -# Contact Information: -# Imagination Technologies Ltd. <gpl-support@imgtec.com> -# Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK +# 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. +# +### ########################################################################### modules := srvkm diff --git a/sgx/services4/srvkm/env/linux/env_data.h b/sgx/services4/srvkm/env/linux/env_data.h index 7716529..4a2b9b1 100644 --- a/sgx/services4/srvkm/env/linux/env_data.h +++ b/sgx/services4/srvkm/env/linux/env_data.h @@ -1,29 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Environmental Data header file +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Linux-specific part of system data. +@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. + +*/ /**************************************************************************/ #ifndef _ENV_DATA_ #define _ENV_DATA_ @@ -34,6 +50,11 @@ #include <linux/workqueue.h> #endif +/* + * Env data specific to linux - convenient place to put this + */ + +/* Fairly arbitrary sizes - hopefully enough for all bridge calls */ #define PVRSRV_MAX_BRIDGE_IN_SIZE 0x1000 #define PVRSRV_MAX_BRIDGE_OUT_SIZE 0x1000 @@ -61,6 +82,13 @@ typedef struct _ENV_DATA_TAG #else struct tasklet_struct sMISRTasklet; #endif +#if defined (SUPPORT_ION) + IMG_HANDLE hIonHeaps; + IMG_HANDLE hIonDev; +#endif } ENV_DATA; -#endif +#endif /* _ENV_DATA_ */ +/***************************************************************************** + End of file (env_data.h) +*****************************************************************************/ diff --git a/sgx/services4/srvkm/env/linux/env_perproc.h b/sgx/services4/srvkm/env/linux/env_perproc.h index 58e2c38..f434226 100644 --- a/sgx/services4/srvkm/env/linux/env_perproc.h +++ b/sgx/services4/srvkm/env/linux/env_perproc.h @@ -1,29 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title OS specific per process data interface +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Linux per process data +@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. + +*/ /**************************************************************************/ #ifndef __ENV_PERPROC_H__ #define __ENV_PERPROC_H__ @@ -33,6 +49,7 @@ #include "services.h" #include "handle.h" +#define ION_CLIENT_NAME_SIZE 50 typedef struct _PVRSRV_ENV_PER_PROCESS_DATA_ { IMG_HANDLE hBlockAlloc; @@ -47,6 +64,10 @@ typedef struct _PVRSRV_ENV_PER_PROCESS_DATA_ struct drm_device *dev; #endif /* SUPPORT_DRI_DRM_EXTERNAL */ #endif +#if defined (SUPPORT_ION) + struct ion_client *psIONClient; + IMG_CHAR azIonClientName[ION_CLIENT_NAME_SIZE]; +#endif } PVRSRV_ENV_PER_PROCESS_DATA; IMG_VOID RemovePerProcessProcDir(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc); @@ -59,5 +80,8 @@ PVRSRV_ERROR LinuxMMapPerProcessHandleOptions(PVRSRV_HANDLE_BASE *psHandleBase); IMG_HANDLE LinuxTerminatingProcessPrivateData(IMG_VOID); -#endif +#endif /* __ENV_PERPROC_H__ */ +/****************************************************************************** + End of file (env_perproc.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/env/linux/event.c b/sgx/services4/srvkm/env/linux/event.c index 7e160c3..1946e61 100644 --- a/sgx/services4/srvkm/env/linux/event.c +++ b/sgx/services4/srvkm/env/linux/event.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Event Object +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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 <linux/version.h> @@ -85,6 +101,20 @@ typedef struct PVRSRV_LINUX_EVENT_OBJECT_TAG PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList; } PVRSRV_LINUX_EVENT_OBJECT; +/*! +****************************************************************************** + + @Function LinuxEventObjectListCreate + + @Description + + Linux wait object list creation + + @Output hOSEventKM : Pointer to the event object list handle + + @Return PVRSRV_ERROR : Error code + +******************************************************************************/ PVRSRV_ERROR LinuxEventObjectListCreate(IMG_HANDLE *phEventObjectList) { PVRSRV_LINUX_EVENT_OBJECT_LIST *psEventObjectList; @@ -106,6 +136,20 @@ PVRSRV_ERROR LinuxEventObjectListCreate(IMG_HANDLE *phEventObjectList) return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function LinuxEventObjectListDestroy + + @Description + + Linux wait object list destruction + + @Input hOSEventKM : Event object list handle + + @Return PVRSRV_ERROR : Error code + +******************************************************************************/ PVRSRV_ERROR LinuxEventObjectListDestroy(IMG_HANDLE hEventObjectList) { @@ -126,13 +170,29 @@ PVRSRV_ERROR LinuxEventObjectListDestroy(IMG_HANDLE hEventObjectList) } OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT_LIST), psEventObjectList, IMG_NULL); - + /*not nulling pointer, copy on stack*/ } return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function LinuxEventObjectDelete + + @Description + + Linux wait object removal + + @Input hOSEventObjectList : Event object list handle + @Input hOSEventObject : Event object handle + @Input bResManCallback : Called from the resman + + @Return PVRSRV_ERROR : Error code + +******************************************************************************/ PVRSRV_ERROR LinuxEventObjectDelete(IMG_HANDLE hOSEventObjectList, IMG_HANDLE hOSEventObject) { if(hOSEventObjectList) @@ -155,6 +215,20 @@ PVRSRV_ERROR LinuxEventObjectDelete(IMG_HANDLE hOSEventObjectList, IMG_HANDLE hO } +/*! +****************************************************************************** + + @Function LinuxEventObjectDeleteCallback + + @Description + + Linux wait object removal + + @Input hOSEventObject : Event object handle + + @Return PVRSRV_ERROR : Error code + +******************************************************************************/ static PVRSRV_ERROR LinuxEventObjectDeleteCallback(IMG_PVOID pvParam, IMG_UINT32 ui32Param, IMG_BOOL bForceCleanup) { PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = pvParam; @@ -173,10 +247,25 @@ static PVRSRV_ERROR LinuxEventObjectDeleteCallback(IMG_PVOID pvParam, IMG_UINT32 #endif OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT), psLinuxEventObject, IMG_NULL); - + /*not nulling pointer, copy on stack*/ return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function LinuxEventObjectAdd + + @Description + + Linux wait object addition + + @Input hOSEventObjectList : Event object list handle + @Output phOSEventObject : Pointer to the event object handle + + @Return PVRSRV_ERROR : Error code + +******************************************************************************/ PVRSRV_ERROR LinuxEventObjectAdd(IMG_HANDLE hOSEventObjectList, IMG_HANDLE *phOSEventObject) { PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject; @@ -192,7 +281,7 @@ PVRSRV_ERROR LinuxEventObjectAdd(IMG_HANDLE hOSEventObjectList, IMG_HANDLE *phOS return PVRSRV_ERROR_OUT_OF_MEMORY; } - + /* allocate completion variable */ if(OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_LINUX_EVENT_OBJECT), (IMG_VOID **)&psLinuxEventObject, IMG_NULL, "Linux Event Object") != PVRSRV_OK) @@ -228,6 +317,20 @@ PVRSRV_ERROR LinuxEventObjectAdd(IMG_HANDLE hOSEventObjectList, IMG_HANDLE *phOS return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function LinuxEventObjectSignal + + @Description + + Linux wait object signaling function + + @Input hOSEventObjectList : Event object list handle + + @Return PVRSRV_ERROR : Error code + +******************************************************************************/ PVRSRV_ERROR LinuxEventObjectSignal(IMG_HANDLE hOSEventObjectList) { PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject; @@ -236,7 +339,10 @@ PVRSRV_ERROR LinuxEventObjectSignal(IMG_HANDLE hOSEventObjectList) psList = &psLinuxEventObjectList->sList; - + /* + * We don't take the write lock in interrupt context, so we don't + * need to use read_lock_irqsave. + */ read_lock(&psLinuxEventObjectList->sLock); list_for_each(psListEntry, psList) { @@ -252,6 +358,22 @@ PVRSRV_ERROR LinuxEventObjectSignal(IMG_HANDLE hOSEventObjectList) } +/*! +****************************************************************************** + + @Function LinuxEventObjectWait + + @Description + + Linux wait object routine + + @Input hOSEventObject : Event object handle + + @Input ui32MSTimeout : Time out value in msec + + @Return PVRSRV_ERROR : Error code + +******************************************************************************/ PVRSRV_ERROR LinuxEventObjectWait(IMG_HANDLE hOSEventObject, IMG_UINT32 ui32MSTimeout) { IMG_UINT32 ui32TimeStamp; diff --git a/sgx/services4/srvkm/env/linux/event.h b/sgx/services4/srvkm/env/linux/event.h index 3035283..88adb27 100644 --- a/sgx/services4/srvkm/env/linux/event.h +++ b/sgx/services4/srvkm/env/linux/event.h @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Event Object +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ + PVRSRV_ERROR LinuxEventObjectListCreate(IMG_HANDLE *phEventObjectList); PVRSRV_ERROR LinuxEventObjectListDestroy(IMG_HANDLE hEventObjectList); diff --git a/sgx/services4/srvkm/env/linux/linkage.h b/sgx/services4/srvkm/env/linux/linkage.h index e64012c..94aae0b 100644 --- a/sgx/services4/srvkm/env/linux/linkage.h +++ b/sgx/services4/srvkm/env/linux/linkage.h @@ -1,29 +1,47 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Linux specific Services code internal interfaces +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Interfaces between various parts of the Linux specific + Services code, that don't have any other obvious + header file to go into. +@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. + +*/ /**************************************************************************/ #ifndef __LINKAGE_H__ #define __LINKAGE_H__ @@ -45,8 +63,11 @@ IMG_INT PVRProcSetPowerLevel(struct file *file, const IMG_CHAR *buffer, IMG_UINT void ProcSeqShowPowerLevel(struct seq_file *sfile,void* el); -#endif +#endif /* PVR_MANUAL_POWER_CONTROL */ -#endif +#endif /* DEBUG */ -#endif +#endif /* __LINKAGE_H__ */ +/***************************************************************************** + End of file (linkage.h) +*****************************************************************************/ diff --git a/sgx/services4/srvkm/env/linux/lock.h b/sgx/services4/srvkm/env/linux/lock.h index a0854c3..d6d5b50 100644 --- a/sgx/services4/srvkm/env/linux/lock.h +++ b/sgx/services4/srvkm/env/linux/lock.h @@ -1,32 +1,57 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Main driver lock +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description The main driver lock, held in most places in + the driver. +@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. + +*/ /**************************************************************************/ #ifndef __LOCK_H__ #define __LOCK_H__ +/* + * Main driver lock, used to ensure driver code is single threaded. + * There are some places where this lock must not be taken, such as + * in the mmap related deriver entry points. + */ extern PVRSRV_LINUX_MUTEX gPVRSRVLock; -#endif +#endif /* __LOCK_H__ */ +/***************************************************************************** + End of file (lock.h) +*****************************************************************************/ diff --git a/sgx/services4/srvkm/env/linux/mm.c b/sgx/services4/srvkm/env/linux/mm.c index 3edbc49..dc2b471 100644 --- a/sgx/services4/srvkm/env/linux/mm.c +++ b/sgx/services4/srvkm/env/linux/mm.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Misc memory management utility functions for Linux +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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 <linux/version.h> @@ -32,6 +48,14 @@ #endif #endif +#if !defined(PVR_LINUX_MEM_AREA_POOL_MAX_PAGES) +#define PVR_LINUX_MEM_AREA_POOL_MAX_PAGES 0 +#endif + +#include <linux/kernel.h> +#include <asm/atomic.h> +#include <linux/list.h> +#include <linux/mutex.h> #include <linux/mm.h> #include <linux/vmalloc.h> #include <asm/io.h> @@ -42,6 +66,12 @@ #include <linux/highmem.h> #include <linux/sched.h> +#if defined(PVR_LINUX_MEM_AREA_POOL_ALLOW_SHRINK) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) +#include <linux/shrinker.h> +#endif +#endif + #include "img_defs.h" #include "services.h" #include "servicesint.h" @@ -60,6 +90,13 @@ #include "lists.h" #endif +/* + * The page pool entry count is an atomic int so that the shrinker function + * can return it even when we can't take the lock that protects the page pool + * list. + */ +static atomic_t g_sPagePoolEntryCount = ATOMIC_INIT(0); + #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) typedef enum { DEBUG_MEM_ALLOC_TYPE_KMALLOC, @@ -68,13 +105,17 @@ typedef enum { DEBUG_MEM_ALLOC_TYPE_IOREMAP, DEBUG_MEM_ALLOC_TYPE_IO, DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE, + DEBUG_MEM_ALLOC_TYPE_ION, +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) + DEBUG_MEM_ALLOC_TYPE_VMAP, +#endif DEBUG_MEM_ALLOC_TYPE_COUNT -}DEBUG_MEM_ALLOC_TYPE; +} DEBUG_MEM_ALLOC_TYPE; typedef struct _DEBUG_MEM_ALLOC_REC { DEBUG_MEM_ALLOC_TYPE eAllocType; - IMG_VOID *pvKey; + IMG_VOID *pvKey; /* Some unique value (private to the eAllocType) */ IMG_VOID *pvCpuVAddr; IMG_UINT32 ulCpuPAddr; IMG_VOID *pvPrivateData; @@ -85,7 +126,7 @@ typedef struct _DEBUG_MEM_ALLOC_REC struct _DEBUG_MEM_ALLOC_REC *psNext; struct _DEBUG_MEM_ALLOC_REC **ppsThis; -}DEBUG_MEM_ALLOC_REC; +} DEBUG_MEM_ALLOC_REC; static IMPLEMENT_LIST_ANY_VA_2(DEBUG_MEM_ALLOC_REC, IMG_BOOL, IMG_FALSE) static IMPLEMENT_LIST_ANY_VA(DEBUG_MEM_ALLOC_REC) @@ -99,9 +140,17 @@ static DEBUG_MEM_ALLOC_REC *g_MemoryRecords; static IMG_UINT32 g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_COUNT]; static IMG_UINT32 g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_COUNT]; -static IMG_UINT32 g_SysRAMWaterMark; -static IMG_UINT32 g_SysRAMHighWaterMark; +/* vmalloc + kmalloc + alloc_pages + kmem_cache */ +static IMG_UINT32 g_SysRAMWaterMark; /* Doesn't include page pool */ +static IMG_UINT32 g_SysRAMHighWaterMark; /* *DOES* include page pool */ +static inline IMG_UINT32 +SysRAMTrueWaterMark(void) +{ + return g_SysRAMWaterMark + PAGES_TO_BYTES(atomic_read(&g_sPagePoolEntryCount)); +} + +/* ioremap + io */ static IMG_UINT32 g_IOMemWaterMark; static IMG_UINT32 g_IOMemHighWaterMark; @@ -119,7 +168,7 @@ static IMG_VOID DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE eAllocType, IMG_V static IMG_CHAR *DebugMemAllocRecordTypeToString(DEBUG_MEM_ALLOC_TYPE eAllocType); -static struct proc_dir_entry *g_SeqFileMemoryRecords =0; +static struct proc_dir_entry *g_SeqFileMemoryRecords; static void* ProcSeqNextMemoryRecords(struct seq_file *sfile,void* el,loff_t off); static void ProcSeqShowMemoryRecords(struct seq_file *sfile,void* el); static void* ProcSeqOff2ElementMemoryRecords(struct seq_file * sfile, loff_t off); @@ -153,7 +202,7 @@ static IMG_UINT32 g_LinuxMemAreaWaterMark; static IMG_UINT32 g_LinuxMemAreaHighWaterMark; -static struct proc_dir_entry *g_SeqFileMemArea=0; +static struct proc_dir_entry *g_SeqFileMemArea; static void* ProcSeqNextMemArea(struct seq_file *sfile,void* el,loff_t off); static void ProcSeqShowMemArea(struct seq_file *sfile,void* el); @@ -169,8 +218,19 @@ static PVRSRV_LINUX_MUTEX g_sDebugMutex; static void ProcSeqStartstopDebugMutex(struct seq_file *sfile,IMG_BOOL start); #endif -static LinuxKMemCache *psLinuxMemAreaCache; +typedef struct +{ + /* Linkage for page pool LRU list */ + struct list_head sPagePoolItem; + + struct page *psPage; +} LinuxPagePoolEntry; + +static LinuxKMemCache *g_PsLinuxMemAreaCache; +static LinuxKMemCache *g_PsLinuxPagePoolCache; +static LIST_HEAD(g_sPagePoolList); +static int g_iPagePoolMaxEntries; #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) static IMG_VOID ReservePages(IMG_VOID *pvAddress, IMG_UINT32 ui32Length); @@ -185,165 +245,26 @@ static DEBUG_LINUX_MEM_AREA_REC *DebugLinuxMemAreaRecordFind(LinuxMemArea *psLin static IMG_VOID DebugLinuxMemAreaRecordRemove(LinuxMemArea *psLinuxMemArea); #endif -PVRSRV_ERROR -LinuxMMInit(IMG_VOID) -{ -#if defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) - LinuxInitMutex(&g_sDebugMutex); -#endif - -#if defined(DEBUG_LINUX_MEM_AREAS) - { - g_SeqFileMemArea = CreateProcReadEntrySeq( - "mem_areas", - NULL, - ProcSeqNextMemArea, - ProcSeqShowMemArea, - ProcSeqOff2ElementMemArea, - ProcSeqStartstopDebugMutex - ); - if(!g_SeqFileMemArea) - { - return PVRSRV_ERROR_OUT_OF_MEMORY; - } - } -#endif - - -#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) - { - g_SeqFileMemoryRecords =CreateProcReadEntrySeq( - "meminfo", - NULL, - ProcSeqNextMemoryRecords, - ProcSeqShowMemoryRecords, - ProcSeqOff2ElementMemoryRecords, - ProcSeqStartstopDebugMutex - ); - if(!g_SeqFileMemoryRecords) - { - return PVRSRV_ERROR_OUT_OF_MEMORY; - } - } -#endif - - psLinuxMemAreaCache = KMemCacheCreateWrapper("img-mm", sizeof(LinuxMemArea), 0, 0); - if(!psLinuxMemAreaCache) - { - PVR_DPF((PVR_DBG_ERROR,"%s: failed to allocate kmem_cache", __FUNCTION__)); - return PVRSRV_ERROR_OUT_OF_MEMORY; - } - - return PVRSRV_OK; -} - -#if defined(DEBUG_LINUX_MEM_AREAS) -static IMG_VOID LinuxMMCleanup_MemAreas_ForEachCb(DEBUG_LINUX_MEM_AREA_REC *psCurrentRecord) -{ - LinuxMemArea *psLinuxMemArea; - - psLinuxMemArea = psCurrentRecord->psLinuxMemArea; - PVR_DPF((PVR_DBG_ERROR, "%s: BUG!: Cleaning up Linux memory area (%p), type=%s, size=%d bytes", - __FUNCTION__, - psCurrentRecord->psLinuxMemArea, - LinuxMemAreaTypeToString(psCurrentRecord->psLinuxMemArea->eAreaType), - psCurrentRecord->psLinuxMemArea->ui32ByteSize)); - - LinuxMemAreaDeepFree(psLinuxMemArea); -} -#endif - -#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) -static IMG_VOID LinuxMMCleanup_MemRecords_ForEachVa(DEBUG_MEM_ALLOC_REC *psCurrentRecord) +static inline IMG_BOOL +AreaIsUncached(IMG_UINT32 ui32AreaFlags) { - - PVR_DPF((PVR_DBG_ERROR, "%s: BUG!: Cleaning up memory: " - "type=%s " - "CpuVAddr=%p " - "CpuPAddr=0x%08x, " - "allocated @ file=%s,line=%d", - __FUNCTION__, - DebugMemAllocRecordTypeToString(psCurrentRecord->eAllocType), - psCurrentRecord->pvCpuVAddr, - psCurrentRecord->ulCpuPAddr, - psCurrentRecord->pszFileName, - psCurrentRecord->ui32Line)); - switch(psCurrentRecord->eAllocType) - { - case DEBUG_MEM_ALLOC_TYPE_KMALLOC: - KFreeWrapper(psCurrentRecord->pvCpuVAddr); - break; - case DEBUG_MEM_ALLOC_TYPE_IOREMAP: - IOUnmapWrapper(psCurrentRecord->pvCpuVAddr); - break; - case DEBUG_MEM_ALLOC_TYPE_IO: - - DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_IO, psCurrentRecord->pvKey, __FILE__, __LINE__); - break; - case DEBUG_MEM_ALLOC_TYPE_VMALLOC: - VFreeWrapper(psCurrentRecord->pvCpuVAddr); - break; - case DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES: - - DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, psCurrentRecord->pvKey, __FILE__, __LINE__); - break; - case DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE: - KMemCacheFreeWrapper(psCurrentRecord->pvPrivateData, psCurrentRecord->pvCpuVAddr); - break; - default: - PVR_ASSERT(0); - } + return (ui32AreaFlags & (PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_UNCACHED)) != 0; } -#endif - -IMG_VOID -LinuxMMCleanup(IMG_VOID) +static inline IMG_BOOL +CanFreeToPool(LinuxMemArea *psLinuxMemArea) { - -#if defined(DEBUG_LINUX_MEM_AREAS) - { - if(g_LinuxMemAreaCount) - { - PVR_DPF((PVR_DBG_ERROR, "%s: BUG!: There are %d LinuxMemArea allocation unfreed (%d bytes)", - __FUNCTION__, g_LinuxMemAreaCount, g_LinuxMemAreaWaterMark)); - } - - List_DEBUG_LINUX_MEM_AREA_REC_ForEach(g_LinuxMemAreaRecords, - LinuxMMCleanup_MemAreas_ForEachCb); - - RemoveProcEntrySeq( g_SeqFileMemArea ); - } -#endif - - -#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) - { - - - List_DEBUG_MEM_ALLOC_REC_ForEach(g_MemoryRecords, - LinuxMMCleanup_MemRecords_ForEachVa); - - RemoveProcEntrySeq( g_SeqFileMemoryRecords ); - } -#endif - - if(psLinuxMemAreaCache) - { - KMemCacheDestroyWrapper(psLinuxMemAreaCache); - psLinuxMemAreaCache=NULL; - } + return AreaIsUncached(psLinuxMemArea->ui32AreaFlags) && !psLinuxMemArea->bNeedsCacheInvalidate; } - IMG_VOID * _KMallocWrapper(IMG_UINT32 ui32ByteSize, gfp_t uFlags, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line) { IMG_VOID *pvRet; pvRet = kmalloc(ui32ByteSize, uFlags); #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) - if(pvRet) + if (pvRet) { DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_KMALLOC, pvRet, @@ -353,7 +274,7 @@ _KMallocWrapper(IMG_UINT32 ui32ByteSize, gfp_t uFlags, IMG_CHAR *pszFileName, IM ui32ByteSize, pszFileName, ui32Line - ); + ); } #else PVR_UNREFERENCED_PARAMETER(pszFileName); @@ -406,27 +327,31 @@ DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE eAllocType, List_DEBUG_MEM_ALLOC_REC_Insert(&g_MemoryRecords, psRecord); g_WaterMarkData[eAllocType] += ui32Bytes; - if(g_WaterMarkData[eAllocType] > g_HighWaterMarkData[eAllocType]) + if (g_WaterMarkData[eAllocType] > g_HighWaterMarkData[eAllocType]) { g_HighWaterMarkData[eAllocType] = g_WaterMarkData[eAllocType]; } - if(eAllocType == DEBUG_MEM_ALLOC_TYPE_KMALLOC + if (eAllocType == DEBUG_MEM_ALLOC_TYPE_KMALLOC || eAllocType == DEBUG_MEM_ALLOC_TYPE_VMALLOC || eAllocType == DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES || eAllocType == DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE) { + IMG_UINT32 ui32SysRAMTrueWaterMark; + g_SysRAMWaterMark += ui32Bytes; - if(g_SysRAMWaterMark > g_SysRAMHighWaterMark) + ui32SysRAMTrueWaterMark = SysRAMTrueWaterMark(); + + if (ui32SysRAMTrueWaterMark > g_SysRAMHighWaterMark) { - g_SysRAMHighWaterMark = g_SysRAMWaterMark; + g_SysRAMHighWaterMark = ui32SysRAMTrueWaterMark; } } - else if(eAllocType == DEBUG_MEM_ALLOC_TYPE_IOREMAP + else if (eAllocType == DEBUG_MEM_ALLOC_TYPE_IOREMAP || eAllocType == DEBUG_MEM_ALLOC_TYPE_IO) { g_IOMemWaterMark += ui32Bytes; - if(g_IOMemWaterMark > g_IOMemHighWaterMark) + if (g_IOMemWaterMark > g_IOMemHighWaterMark) { g_IOMemHighWaterMark = g_IOMemWaterMark; } @@ -444,20 +369,20 @@ static IMG_BOOL DebugMemAllocRecordRemove_AnyVaCb(DEBUG_MEM_ALLOC_REC *psCurrent eAllocType = va_arg(va, DEBUG_MEM_ALLOC_TYPE); pvKey = va_arg(va, IMG_VOID*); - if(psCurrentRecord->eAllocType == eAllocType + if (psCurrentRecord->eAllocType == eAllocType && psCurrentRecord->pvKey == pvKey) { eAllocType = psCurrentRecord->eAllocType; g_WaterMarkData[eAllocType] -= psCurrentRecord->ui32Bytes; - if(eAllocType == DEBUG_MEM_ALLOC_TYPE_KMALLOC + if (eAllocType == DEBUG_MEM_ALLOC_TYPE_KMALLOC || eAllocType == DEBUG_MEM_ALLOC_TYPE_VMALLOC || eAllocType == DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES || eAllocType == DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE) { g_SysRAMWaterMark -= psCurrentRecord->ui32Bytes; } - else if(eAllocType == DEBUG_MEM_ALLOC_TYPE_IOREMAP + else if (eAllocType == DEBUG_MEM_ALLOC_TYPE_IOREMAP || eAllocType == DEBUG_MEM_ALLOC_TYPE_IO) { g_IOMemWaterMark -= psCurrentRecord->ui32Bytes; @@ -478,10 +403,12 @@ static IMG_BOOL DebugMemAllocRecordRemove_AnyVaCb(DEBUG_MEM_ALLOC_REC *psCurrent static IMG_VOID DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE eAllocType, IMG_VOID *pvKey, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line) { +/* DEBUG_MEM_ALLOC_REC **ppsCurrentRecord;*/ + LinuxLockMutex(&g_sDebugMutex); - - if(!List_DEBUG_MEM_ALLOC_REC_IMG_BOOL_Any_va(g_MemoryRecords, + /* Locate the corresponding allocation entry */ + if (!List_DEBUG_MEM_ALLOC_REC_IMG_BOOL_Any_va(g_MemoryRecords, DebugMemAllocRecordRemove_AnyVaCb, eAllocType, pvKey)) @@ -504,27 +431,24 @@ DebugMemAllocRecordTypeToString(DEBUG_MEM_ALLOC_TYPE eAllocType) "ALLOC_PAGES", "IOREMAP", "IO", - "KMEM_CACHE_ALLOC" + "KMEM_CACHE_ALLOC", +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) + "VMAP" +#endif }; return apszDebugMemoryRecordTypes[eAllocType]; } #endif - -IMG_VOID * -_VMallocWrapper(IMG_UINT32 ui32Bytes, - IMG_UINT32 ui32AllocFlags, - IMG_CHAR *pszFileName, - IMG_UINT32 ui32Line) +static IMG_BOOL +AllocFlagsToPGProt(pgprot_t *pPGProtFlags, IMG_UINT32 ui32AllocFlags) { pgprot_t PGProtFlags; - IMG_VOID *pvRet; - - switch(ui32AllocFlags & PVRSRV_HAP_CACHETYPE_MASK) + + switch (ui32AllocFlags & PVRSRV_HAP_CACHETYPE_MASK) { case PVRSRV_HAP_CACHED: - case PVRSRV_HAP_SMART: PGProtFlags = PAGE_KERNEL; break; case PVRSRV_HAP_WRITECOMBINE: @@ -535,17 +459,36 @@ _VMallocWrapper(IMG_UINT32 ui32Bytes, break; default: PVR_DPF((PVR_DBG_ERROR, - "VMAllocWrapper: unknown mapping flags=0x%08x", - ui32AllocFlags)); + "%s: Unknown mapping flags=0x%08x", + __FUNCTION__, ui32AllocFlags)); dump_stack(); + return IMG_FALSE; + } + + *pPGProtFlags = PGProtFlags; + + return IMG_TRUE; +} + +IMG_VOID * +_VMallocWrapper(IMG_UINT32 ui32Bytes, + IMG_UINT32 ui32AllocFlags, + IMG_CHAR *pszFileName, + IMG_UINT32 ui32Line) +{ + pgprot_t PGProtFlags; + IMG_VOID *pvRet; + + if (!AllocFlagsToPGProt(&PGProtFlags, ui32AllocFlags)) + { return NULL; } - + /* Allocate virtually contiguous pages */ pvRet = __vmalloc(ui32Bytes, GFP_KERNEL | __GFP_HIGHMEM, PGProtFlags); #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) - if(pvRet) + if (pvRet) { DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_VMALLOC, pvRet, @@ -555,7 +498,7 @@ _VMallocWrapper(IMG_UINT32 ui32Bytes, PAGE_ALIGN(ui32Bytes), pszFileName, ui32Line - ); + ); } #else PVR_UNREFERENCED_PARAMETER(pszFileName); @@ -579,31 +522,481 @@ _VFreeWrapper(IMG_VOID *pvCpuVAddr, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line) } +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) +static IMG_VOID * +_VMapWrapper(struct page **ppsPageList, IMG_UINT32 ui32NumPages, IMG_UINT32 ui32AllocFlags, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line) +{ + pgprot_t PGProtFlags; + IMG_VOID *pvRet; + + if (!AllocFlagsToPGProt(&PGProtFlags, ui32AllocFlags)) + { + return NULL; + } + + pvRet = vmap(ppsPageList, ui32NumPages, GFP_KERNEL | __GFP_HIGHMEM, PGProtFlags); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + if (pvRet) + { + DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_VMAP, + pvRet, + pvRet, + 0, + NULL, + PAGES_TO_BYTES(ui32NumPages), + pszFileName, + ui32Line + ); + } +#else + PVR_UNREFERENCED_PARAMETER(pszFileName); + PVR_UNREFERENCED_PARAMETER(ui32Line); +#endif + + return pvRet; +} + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +#define VMapWrapper(ppsPageList, ui32Bytes, ui32AllocFlags) _VMapWrapper(ppsPageList, ui32Bytes, ui32AllocFlags, __FILE__, __LINE__) +#else +#define VMapWrapper(ppsPageList, ui32Bytes, ui32AllocFlags) _VMapWrapper(ppsPageList, ui32Bytes, ui32AllocFlags, NULL, 0) +#endif + + +static IMG_VOID +_VUnmapWrapper(IMG_VOID *pvCpuVAddr, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line) +{ +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_VMAP, pvCpuVAddr, pszFileName, ui32Line); +#else + PVR_UNREFERENCED_PARAMETER(pszFileName); + PVR_UNREFERENCED_PARAMETER(ui32Line); +#endif + vunmap(pvCpuVAddr); +} + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +#define VUnmapWrapper(pvCpuVAddr) _VUnmapWrapper(pvCpuVAddr, __FILE__, __LINE__) +#else +#define VUnmapWrapper(pvCpuVAddr) _VUnmapWrapper(pvCpuVAddr, NULL, 0) +#endif + +#endif /* defined(PVR_LINUX_MEM_AREA_USE_VMAP) */ + + +IMG_VOID +_KMemCacheFreeWrapper(LinuxKMemCache *psCache, IMG_VOID *pvObject, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line) +{ +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE, pvObject, pszFileName, ui32Line); +#else + PVR_UNREFERENCED_PARAMETER(pszFileName); + PVR_UNREFERENCED_PARAMETER(ui32Line); +#endif + + kmem_cache_free(psCache, pvObject); +} + + +const IMG_CHAR * +KMemCacheNameWrapper(LinuxKMemCache *psCache) +{ + PVR_UNREFERENCED_PARAMETER(psCache); + + /* In this case kmem_cache_t is an incomplete typedef, + * so we can't even de-reference to get the name member. It is also a GPL export symbol */ + return ""; +} + + +static LinuxPagePoolEntry * +LinuxPagePoolEntryAlloc(IMG_VOID) +{ + return KMemCacheAllocWrapper(g_PsLinuxPagePoolCache, GFP_KERNEL); +} + +static IMG_VOID +LinuxPagePoolEntryFree(LinuxPagePoolEntry *psPagePoolEntry) +{ + KMemCacheFreeWrapper(g_PsLinuxPagePoolCache, psPagePoolEntry); +} + + +static struct page * +AllocPageFromLinux(void) +{ + struct page *psPage; + + psPage = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, 0); + if (!psPage) + { + return NULL; + + } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) + /* Reserve those pages to allow them to be re-mapped to user space */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) + SetPageReserved(psPage); +#else + mem_map_reserve(psPage); +#endif +#endif + return psPage; +} + + +static IMG_VOID +FreePageToLinux(struct page *psPage) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) + ClearPageReserved(psPage); +#else + mem_map_reserve(psPage); +#endif +#endif + __free_pages(psPage, 0); +} + + +#if (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0) +static DEFINE_MUTEX(g_sPagePoolMutex); + +static inline void +PagePoolLock(void) +{ + mutex_lock(&g_sPagePoolMutex); +} + +static inline void +PagePoolUnlock(void) +{ + mutex_unlock(&g_sPagePoolMutex); +} + +static inline int +PagePoolTrylock(void) +{ + return mutex_trylock(&g_sPagePoolMutex); +} + +#else /* (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0) */ +static inline void +PagePoolLock(void) +{ +} + +static inline void +PagePoolUnlock(void) +{ +} + +static inline int +PagePoolTrylock(void) +{ + return 1; +} +#endif /* (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0) */ + + +static inline void +AddEntryToPool(LinuxPagePoolEntry *psPagePoolEntry) +{ + list_add_tail(&psPagePoolEntry->sPagePoolItem, &g_sPagePoolList); + atomic_inc(&g_sPagePoolEntryCount); +} + +static inline void +RemoveEntryFromPool(LinuxPagePoolEntry *psPagePoolEntry) +{ + list_del(&psPagePoolEntry->sPagePoolItem); + atomic_dec(&g_sPagePoolEntryCount); +} + +static inline LinuxPagePoolEntry * +RemoveFirstEntryFromPool(void) +{ + LinuxPagePoolEntry *psPagePoolEntry; + + if (list_empty(&g_sPagePoolList)) + { + PVR_ASSERT(atomic_read(&g_sPagePoolEntryCount) == 0); + + return NULL; + } + + PVR_ASSERT(atomic_read(&g_sPagePoolEntryCount) > 0); + + psPagePoolEntry = list_first_entry(&g_sPagePoolList, LinuxPagePoolEntry, sPagePoolItem); + + RemoveEntryFromPool(psPagePoolEntry); + + return psPagePoolEntry; +} + +static struct page * +AllocPage(IMG_UINT32 ui32AreaFlags, IMG_BOOL *pbFromPagePool) +{ + struct page *psPage = NULL; + + /* + * Only uncached allocations can come from the page pool. + * The page pool is currently used to reduce the cost of + * invalidating the CPU cache when uncached memory is allocated. + */ + if (AreaIsUncached(ui32AreaFlags) && atomic_read(&g_sPagePoolEntryCount) != 0) + { + LinuxPagePoolEntry *psPagePoolEntry; + + PagePoolLock(); + psPagePoolEntry = RemoveFirstEntryFromPool(); + PagePoolUnlock(); + + /* List may have changed since we checked the counter */ + if (psPagePoolEntry) + { + psPage = psPagePoolEntry->psPage; + LinuxPagePoolEntryFree(psPagePoolEntry); + *pbFromPagePool = IMG_TRUE; + } + } + + if (!psPage) + { + psPage = AllocPageFromLinux(); + if (psPage) + { + *pbFromPagePool = IMG_FALSE; + } + } + + return psPage; + +} + +static IMG_VOID +FreePage(IMG_BOOL bToPagePool, struct page *psPage) +{ + /* Only uncached allocations can be freed to the page pool */ + if (bToPagePool && atomic_read(&g_sPagePoolEntryCount) < g_iPagePoolMaxEntries) + { + LinuxPagePoolEntry *psPagePoolEntry = LinuxPagePoolEntryAlloc(); + if (psPagePoolEntry) + { + psPagePoolEntry->psPage = psPage; + + PagePoolLock(); + AddEntryToPool(psPagePoolEntry); + PagePoolUnlock(); + + return; + } + } + + FreePageToLinux(psPage); +} + +static IMG_VOID +FreePagePool(IMG_VOID) +{ + LinuxPagePoolEntry *psPagePoolEntry, *psTempPoolEntry; + + PagePoolLock(); + +#if (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0) + PVR_TRACE(("%s: Freeing %d pages from pool", __FUNCTION__, atomic_read(&g_sPagePoolEntryCount))); +#else + PVR_ASSERT(atomic_read(&g_sPagePoolEntryCount) == 0); + PVR_ASSERT(list_empty(&g_sPagePoolList)); +#endif + + list_for_each_entry_safe(psPagePoolEntry, psTempPoolEntry, &g_sPagePoolList, sPagePoolItem) + { + RemoveEntryFromPool(psPagePoolEntry); + + FreePageToLinux(psPagePoolEntry->psPage); + LinuxPagePoolEntryFree(psPagePoolEntry); + } + + PVR_ASSERT(atomic_read(&g_sPagePoolEntryCount) == 0); + + PagePoolUnlock(); +} + +#if defined(PVR_LINUX_MEM_AREA_POOL_ALLOW_SHRINK) +#if defined(PVRSRV_NEED_PVR_ASSERT) +static struct shrinker g_sShrinker; +#endif + +static int +ShrinkPagePool(struct shrinker *psShrinker, struct shrink_control *psShrinkControl) +{ + unsigned long uNumToScan = psShrinkControl->nr_to_scan; + + PVR_ASSERT(psShrinker == &g_sShrinker); + (void)psShrinker; + + if (uNumToScan != 0) + { + LinuxPagePoolEntry *psPagePoolEntry, *psTempPoolEntry; + + PVR_TRACE(("%s: Number to scan: %ld", __FUNCTION__, uNumToScan)); + PVR_TRACE(("%s: Pages in pool before scan: %d", __FUNCTION__, atomic_read(&g_sPagePoolEntryCount))); + + if (!PagePoolTrylock()) + { + PVR_TRACE(("%s: Couldn't get page pool lock", __FUNCTION__)); + return -1; + } + + list_for_each_entry_safe(psPagePoolEntry, psTempPoolEntry, &g_sPagePoolList, sPagePoolItem) + { + RemoveEntryFromPool(psPagePoolEntry); + + FreePageToLinux(psPagePoolEntry->psPage); + LinuxPagePoolEntryFree(psPagePoolEntry); + + if (--uNumToScan == 0) + { + break; + } + } + + if (list_empty(&g_sPagePoolList)) + { + PVR_ASSERT(atomic_read(&g_sPagePoolEntryCount) == 0); + } + + PagePoolUnlock(); + + PVR_TRACE(("%s: Pages in pool after scan: %d", __FUNCTION__, atomic_read(&g_sPagePoolEntryCount))); + } + + return atomic_read(&g_sPagePoolEntryCount); +} +#endif + +static IMG_BOOL +AllocPages(IMG_UINT32 ui32AreaFlags, struct page ***pppsPageList, IMG_HANDLE *phBlockPageList, IMG_UINT32 ui32NumPages, IMG_BOOL *pbFromPagePool) +{ + struct page **ppsPageList; + IMG_HANDLE hBlockPageList; + IMG_INT32 i; /* Must be signed; see "for" loop conditions */ + PVRSRV_ERROR eError; + IMG_BOOL bFromPagePool = IMG_FALSE; + + eError = OSAllocMem(0, sizeof(*ppsPageList) * ui32NumPages, (IMG_VOID **)&ppsPageList, &hBlockPageList, + "Array of pages"); + if (eError != PVRSRV_OK) + { + goto failed_page_list_alloc; + } + + *pbFromPagePool = IMG_TRUE; + for(i = 0; i < (IMG_INT32)ui32NumPages; i++) + { + ppsPageList[i] = AllocPage(ui32AreaFlags, &bFromPagePool); + if (!ppsPageList[i]) + { + goto failed_alloc_pages; + } + *pbFromPagePool &= bFromPagePool; + } + + *pppsPageList = ppsPageList; + *phBlockPageList = hBlockPageList; + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, + ppsPageList, + 0, + 0, + NULL, + PAGES_TO_BYTES(ui32NumPages), + "unknown", + 0 + ); +#endif + + return IMG_TRUE; + +failed_alloc_pages: + for(i--; i >= 0; i--) + { + FreePage(*pbFromPagePool, ppsPageList[i]); + } + (IMG_VOID) OSFreeMem(0, sizeof(*ppsPageList) * ui32NumPages, ppsPageList, hBlockPageList); + +failed_page_list_alloc: + return IMG_FALSE; +} + + +static IMG_VOID +FreePages(IMG_BOOL bToPagePool, struct page **ppsPageList, IMG_HANDLE hBlockPageList, IMG_UINT32 ui32NumPages) +{ + IMG_INT32 i; + + for(i = 0; i < (IMG_INT32)ui32NumPages; i++) + { + FreePage(bToPagePool, ppsPageList[i]); + } + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, ppsPageList, __FILE__, __LINE__); +#endif + + (IMG_VOID) OSFreeMem(0, sizeof(*ppsPageList) * ui32NumPages, ppsPageList, hBlockPageList); +} + + LinuxMemArea * NewVMallocLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags) { - LinuxMemArea *psLinuxMemArea; + LinuxMemArea *psLinuxMemArea = NULL; IMG_VOID *pvCpuVAddr; +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) + IMG_UINT32 ui32NumPages = 0; + struct page **ppsPageList = NULL; + IMG_HANDLE hBlockPageList; +#endif + IMG_BOOL bFromPagePool = IMG_FALSE; psLinuxMemArea = LinuxMemAreaStructAlloc(); - if(!psLinuxMemArea) + if (!psLinuxMemArea) { goto failed; } +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) + ui32NumPages = RANGE_TO_PAGES(ui32Bytes); + + if (!AllocPages(ui32AreaFlags, &ppsPageList, &hBlockPageList, ui32NumPages, &bFromPagePool)) + { + goto failed; + } + + pvCpuVAddr = VMapWrapper(ppsPageList, ui32NumPages, ui32AreaFlags); +#else /* defined(PVR_LINUX_MEM_AREA_USE_VMAP) */ pvCpuVAddr = VMallocWrapper(ui32Bytes, ui32AreaFlags); - if(!pvCpuVAddr) + if (!pvCpuVAddr) { goto failed; } - +/* PG_reserved was deprecated in linux-2.6.15 */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) - + /* Reserve those pages to allow them to be re-mapped to user space */ ReservePages(pvCpuVAddr, ui32Bytes); #endif +#endif /* defined(PVR_LINUX_MEM_AREA_USE_VMAP) */ psLinuxMemArea->eAreaType = LINUX_MEM_AREA_VMALLOC; psLinuxMemArea->uData.sVmalloc.pvVmallocAddress = pvCpuVAddr; +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) + psLinuxMemArea->uData.sVmalloc.ppsPageList = ppsPageList; + psLinuxMemArea->uData.sVmalloc.hBlockPageList = hBlockPageList; +#endif psLinuxMemArea->ui32ByteSize = ui32Bytes; psLinuxMemArea->ui32AreaFlags = ui32AreaFlags; INIT_LIST_HEAD(&psLinuxMemArea->sMMapOffsetStructList); @@ -612,16 +1005,41 @@ NewVMallocLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags) DebugLinuxMemAreaRecordAdd(psLinuxMemArea, ui32AreaFlags); #endif - - if(ui32AreaFlags & (PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_UNCACHED)) - OSInvalidateCPUCacheRangeKM(psLinuxMemArea, pvCpuVAddr, ui32Bytes); + /* This works around a problem where Linux will not invalidate + * the cache for physical memory it frees that is direct mapped. + * + * As a result, cache entries remain that may be subsequently flushed + * to these physical pages after they have been allocated for another + * purpose. For a subsequent cached use of this memory, that is not a + * problem, but if we are allocating uncached or write-combined memory, + * and bypassing the cache, it can cause subsequent uncached writes to + * the memory to be replaced with junk from the cache. + * + * If the pages are from our page cache, no cache invalidate is needed. + * + * This just handles the __vmalloc() case (when we have a kernel virtual + * address range). The alloc_pages() path is handled in mmap.c. + */ + if (AreaIsUncached(ui32AreaFlags) && !bFromPagePool) + { + OSInvalidateCPUCacheRangeKM(psLinuxMemArea, 0, pvCpuVAddr, ui32Bytes); + } return psLinuxMemArea; failed: PVR_DPF((PVR_DBG_ERROR, "%s: failed!", __FUNCTION__)); - if(psLinuxMemArea) +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) + if (ppsPageList) + { + FreePages(bFromPagePool, ppsPageList, hBlockPageList, ui32NumPages); + } +#endif + if (psLinuxMemArea) + { LinuxMemAreaStructFree(psLinuxMemArea); + } + return NULL; } @@ -629,6 +1047,12 @@ failed: IMG_VOID FreeVMallocLinuxMemArea(LinuxMemArea *psLinuxMemArea) { +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) + IMG_UINT32 ui32NumPages; + struct page **ppsPageList; + IMG_HANDLE hBlockPageList; +#endif + PVR_ASSERT(psLinuxMemArea); PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_VMALLOC); PVR_ASSERT(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress); @@ -637,20 +1061,34 @@ FreeVMallocLinuxMemArea(LinuxMemArea *psLinuxMemArea) DebugLinuxMemAreaRecordRemove(psLinuxMemArea); #endif + PVR_DPF((PVR_DBG_MESSAGE,"%s: pvCpuVAddr: %p", + __FUNCTION__, psLinuxMemArea->uData.sVmalloc.pvVmallocAddress)); + +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) + VUnmapWrapper(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress); + + ui32NumPages = RANGE_TO_PAGES(psLinuxMemArea->ui32ByteSize); + ppsPageList = psLinuxMemArea->uData.sVmalloc.ppsPageList; + hBlockPageList = psLinuxMemArea->uData.sVmalloc.hBlockPageList; + + FreePages(CanFreeToPool(psLinuxMemArea), ppsPageList, hBlockPageList, ui32NumPages); +#else +/* PG_reserved was deprecated in linux-2.6.15 */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) - UnreservePages(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress, + UnreservePages(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress, psLinuxMemArea->ui32ByteSize); #endif - PVR_DPF((PVR_DBG_MESSAGE,"%s: pvCpuVAddr: %p", - __FUNCTION__, psLinuxMemArea->uData.sVmalloc.pvVmallocAddress)); VFreeWrapper(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress); +#endif /* defined(PVR_LINUX_MEM_AREA_USE_VMAP) */ LinuxMemAreaStructFree(psLinuxMemArea); } #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) +/* Reserve pages of memory in order that they're not automatically + deallocated after the last user reference dies. */ static IMG_VOID ReservePages(IMG_VOID *pvAddress, IMG_UINT32 ui32Length) { @@ -668,6 +1106,7 @@ ReservePages(IMG_VOID *pvAddress, IMG_UINT32 ui32Length) } +/* Un-reserve pages of memory in order that they can be freed. */ static IMG_VOID UnreservePages(IMG_VOID *pvAddress, IMG_UINT32 ui32Length) { @@ -683,7 +1122,7 @@ UnreservePages(IMG_VOID *pvAddress, IMG_UINT32 ui32Length) #endif } } -#endif +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) */ IMG_VOID * @@ -695,10 +1134,9 @@ _IORemapWrapper(IMG_CPU_PHYADDR BasePAddr, { IMG_VOID *pvIORemapCookie; - switch(ui32MappingFlags & PVRSRV_HAP_CACHETYPE_MASK) + switch (ui32MappingFlags & PVRSRV_HAP_CACHETYPE_MASK) { case PVRSRV_HAP_CACHED: - case PVRSRV_HAP_SMART: pvIORemapCookie = (IMG_VOID *)IOREMAP(BasePAddr.uiAddr, ui32Bytes); break; case PVRSRV_HAP_WRITECOMBINE: @@ -713,7 +1151,7 @@ _IORemapWrapper(IMG_CPU_PHYADDR BasePAddr, } #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) - if(pvIORemapCookie) + if (pvIORemapCookie) { DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_IOREMAP, pvIORemapCookie, @@ -723,7 +1161,7 @@ _IORemapWrapper(IMG_CPU_PHYADDR BasePAddr, ui32Bytes, pszFileName, ui32Line - ); + ); } #else PVR_UNREFERENCED_PARAMETER(pszFileName); @@ -756,13 +1194,13 @@ NewIORemapLinuxMemArea(IMG_CPU_PHYADDR BasePAddr, IMG_VOID *pvIORemapCookie; psLinuxMemArea = LinuxMemAreaStructAlloc(); - if(!psLinuxMemArea) + if (!psLinuxMemArea) { return NULL; } pvIORemapCookie = IORemapWrapper(BasePAddr, ui32Bytes, ui32AreaFlags); - if(!pvIORemapCookie) + if (!pvIORemapCookie) { LinuxMemAreaStructFree(psLinuxMemArea); return NULL; @@ -799,6 +1237,16 @@ FreeIORemapLinuxMemArea(LinuxMemArea *psLinuxMemArea) #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) +/* + * Avoid using remap_pfn_range on RAM, if possible. On x86 systems, with + * PAT enabled, remap_pfn_range checks the page attributes requested by + * remap_pfn_range against those of the direct kernel mapping for those + * pages (if any). This is rather annoying if the pages have been obtained + * with alloc_pages, where we just ask for raw pages; we don't care about + * the direct mapping. This latter issue arises when device memory is + * exported from one process to another. Services implements this + * using memory wrapping, which ends up creating an external KV memory area. + */ static IMG_BOOL TreatExternalPagesAsContiguous(IMG_SYS_PHYADDR *psSysPhysAddr, IMG_UINT32 ui32Bytes, IMG_BOOL bPhysContig) { @@ -806,7 +1254,10 @@ TreatExternalPagesAsContiguous(IMG_SYS_PHYADDR *psSysPhysAddr, IMG_UINT32 ui32By IMG_UINT32 ui32AddrChk; IMG_UINT32 ui32NumPages = RANGE_TO_PAGES(ui32Bytes); - + /* + * If bPhysContig is IMG_TRUE, we must assume psSysPhysAddr points + * to the address of the first page, not an array of page addresses. + */ for (ui32 = 0, ui32AddrChk = psSysPhysAddr[0].uiAddr; ui32 < ui32NumPages; ui32++, ui32AddrChk = (bPhysContig) ? (ui32AddrChk + PAGE_SIZE) : psSysPhysAddr[ui32].uiAddr) @@ -843,7 +1294,7 @@ LinuxMemArea *NewExternalKVLinuxMemArea(IMG_SYS_PHYADDR *pBasePAddr, IMG_VOID *p LinuxMemArea *psLinuxMemArea; psLinuxMemArea = LinuxMemAreaStructAlloc(); - if(!psLinuxMemArea) + if (!psLinuxMemArea) { return NULL; } @@ -896,12 +1347,12 @@ NewIOLinuxMemArea(IMG_CPU_PHYADDR BasePAddr, IMG_UINT32 ui32AreaFlags) { LinuxMemArea *psLinuxMemArea = LinuxMemAreaStructAlloc(); - if(!psLinuxMemArea) + if (!psLinuxMemArea) { return NULL; } - + /* Nothing to activly do. We just keep a record of the physical range. */ psLinuxMemArea->eAreaType = LINUX_MEM_AREA_IO; psLinuxMemArea->uData.sIO.CPUPhysAddr.uiAddr = BasePAddr.uiAddr; psLinuxMemArea->ui32ByteSize = ui32Bytes; @@ -917,7 +1368,7 @@ NewIOLinuxMemArea(IMG_CPU_PHYADDR BasePAddr, ui32Bytes, "unknown", 0 - ); + ); #endif #if defined(DEBUG_LINUX_MEM_AREAS) @@ -942,7 +1393,7 @@ FreeIOLinuxMemArea(LinuxMemArea *psLinuxMemArea) (IMG_VOID *)psLinuxMemArea->uData.sIO.CPUPhysAddr.uiAddr, __FILE__, __LINE__); #endif - + /* Nothing more to do than free the LinuxMemArea struct */ LinuxMemAreaStructFree(psLinuxMemArea); } @@ -952,68 +1403,33 @@ LinuxMemArea * NewAllocPagesLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags) { LinuxMemArea *psLinuxMemArea; - IMG_UINT32 ui32PageCount; - struct page **pvPageList; + IMG_UINT32 ui32NumPages; + struct page **ppsPageList; IMG_HANDLE hBlockPageList; - IMG_INT32 i; - PVRSRV_ERROR eError; - + IMG_BOOL bFromPagePool; + psLinuxMemArea = LinuxMemAreaStructAlloc(); - if(!psLinuxMemArea) + if (!psLinuxMemArea) { goto failed_area_alloc; } - ui32PageCount = RANGE_TO_PAGES(ui32Bytes); - eError = OSAllocMem(0, sizeof(*pvPageList) * ui32PageCount, (IMG_VOID **)&pvPageList, &hBlockPageList, - "Array of pages"); - if(eError != PVRSRV_OK) - { - goto failed_page_list_alloc; - } - - for(i=0; i<(IMG_INT32)ui32PageCount; i++) - { - pvPageList[i] = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, 0); - if(!pvPageList[i]) - { - goto failed_alloc_pages; - } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) - SetPageReserved(pvPageList[i]); -#else - mem_map_reserve(pvPageList[i]); -#endif -#endif + ui32NumPages = RANGE_TO_PAGES(ui32Bytes); + if (!AllocPages(ui32AreaFlags, &ppsPageList, &hBlockPageList, ui32NumPages, &bFromPagePool)) + { + goto failed_alloc_pages; } -#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) - DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, - pvPageList, - 0, - 0, - NULL, - PAGE_ALIGN(ui32Bytes), - "unknown", - 0 - ); -#endif - psLinuxMemArea->eAreaType = LINUX_MEM_AREA_ALLOC_PAGES; - psLinuxMemArea->uData.sPageList.pvPageList = pvPageList; + psLinuxMemArea->uData.sPageList.ppsPageList = ppsPageList; psLinuxMemArea->uData.sPageList.hBlockPageList = hBlockPageList; psLinuxMemArea->ui32ByteSize = ui32Bytes; psLinuxMemArea->ui32AreaFlags = ui32AreaFlags; INIT_LIST_HEAD(&psLinuxMemArea->sMMapOffsetStructList); - - if(ui32AreaFlags & (PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_UNCACHED)) - { - psLinuxMemArea->bNeedsCacheInvalidate = IMG_TRUE; - } + /* We defer the cache flush to the first user mapping of this memory */ + psLinuxMemArea->bNeedsCacheInvalidate = AreaIsUncached(ui32AreaFlags) && !bFromPagePool; #if defined(DEBUG_LINUX_MEM_AREAS) DebugLinuxMemAreaRecordAdd(psLinuxMemArea, ui32AreaFlags); @@ -1022,13 +1438,6 @@ NewAllocPagesLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags) return psLinuxMemArea; failed_alloc_pages: - for(i--; i >= 0; i--) - { - __free_pages(pvPageList[i], 0); - } - (IMG_VOID) OSFreeMem(0, sizeof(*pvPageList) * ui32PageCount, pvPageList, hBlockPageList); - psLinuxMemArea->uData.sPageList.pvPageList = IMG_NULL; -failed_page_list_alloc: LinuxMemAreaStructFree(psLinuxMemArea); failed_area_alloc: PVR_DPF((PVR_DBG_ERROR, "%s: failed", __FUNCTION__)); @@ -1040,10 +1449,9 @@ failed_area_alloc: IMG_VOID FreeAllocPagesLinuxMemArea(LinuxMemArea *psLinuxMemArea) { - IMG_UINT32 ui32PageCount; - struct page **pvPageList; + IMG_UINT32 ui32NumPages; + struct page **ppsPageList; IMG_HANDLE hBlockPageList; - IMG_INT32 i; PVR_ASSERT(psLinuxMemArea); PVR_ASSERT(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_ALLOC_PAGES); @@ -1052,38 +1460,162 @@ FreeAllocPagesLinuxMemArea(LinuxMemArea *psLinuxMemArea) DebugLinuxMemAreaRecordRemove(psLinuxMemArea); #endif - ui32PageCount = RANGE_TO_PAGES(psLinuxMemArea->ui32ByteSize); - pvPageList = psLinuxMemArea->uData.sPageList.pvPageList; + ui32NumPages = RANGE_TO_PAGES(psLinuxMemArea->ui32ByteSize); + ppsPageList = psLinuxMemArea->uData.sPageList.ppsPageList; hBlockPageList = psLinuxMemArea->uData.sPageList.hBlockPageList; -#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) - DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, pvPageList, __FILE__, __LINE__); -#endif + FreePages(CanFreeToPool(psLinuxMemArea), ppsPageList, hBlockPageList, ui32NumPages); + + LinuxMemAreaStructFree(psLinuxMemArea); +} + +#if defined(CONFIG_ION_OMAP) + +#include "env_perproc.h" - for(i=0;i<(IMG_INT32)ui32PageCount;i++) +#include <linux/ion.h> +#include <linux/omap_ion.h> + +extern struct ion_client *gpsIONClient; + +LinuxMemArea * +NewIONLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags, + IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength) +{ + const IMG_UINT32 ui32AllocDataLen = + offsetof(struct omap_ion_tiler_alloc_data, handle); + struct omap_ion_tiler_alloc_data asAllocData[2] = {}; + u32 *pu32PageAddrs[2] = { NULL, NULL }; + IMG_UINT32 i, ui32NumHandlesPerFd; + IMG_BYTE *pbPrivData = pvPrivData; + IMG_CPU_PHYADDR *pCPUPhysAddrs; + int iNumPages[2] = { 0, 0 }; + LinuxMemArea *psLinuxMemArea; + + psLinuxMemArea = LinuxMemAreaStructAlloc(); + if (!psLinuxMemArea) { -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) - ClearPageReserved(pvPageList[i]); -#else - mem_map_reserve(pvPageList[i]); -#endif -#endif - if (psLinuxMemArea->ui32AreaFlags & PVRSRV_HAP_SMART) + PVR_DPF((PVR_DBG_ERROR, "%s: Failed to allocate LinuxMemArea struct", __func__)); + goto err_out; + } + + /* Depending on the UM config, userspace might give us info for + * one or two ION allocations. Divide the total size of data we + * were given by this ui32AllocDataLen, and check it's 1 or 2. + * Otherwise abort. + */ + BUG_ON(ui32PrivDataLength != ui32AllocDataLen && + ui32PrivDataLength != ui32AllocDataLen * 2); + ui32NumHandlesPerFd = ui32PrivDataLength / ui32AllocDataLen; + + /* Shuffle the alloc data into separate Y & UV bits and + * make two separate allocations via the tiler. + */ + for(i = 0; i < ui32NumHandlesPerFd; i++) + { + memcpy(&asAllocData[i], &pbPrivData[i * ui32AllocDataLen], ui32AllocDataLen); + + if (omap_ion_tiler_alloc(gpsIONClient, &asAllocData[i]) < 0) + { + PVR_DPF((PVR_DBG_ERROR, "%s: Failed to allocate via ion_tiler", __func__)); + goto err_free; + } + + if (omap_tiler_pages(gpsIONClient, asAllocData[i].handle, &iNumPages[i], + &pu32PageAddrs[i]) < 0) { - // XXX some race here.. - clear_bit(PG_private, &pvPageList[i]->flags); - clear_bit(PG_private_2, &pvPageList[i]->flags); + PVR_DPF((PVR_DBG_ERROR, "%s: Failed to compute tiler pages", __func__)); + goto err_free; } - __free_pages(pvPageList[i], 0); } - (IMG_VOID) OSFreeMem(0, sizeof(*pvPageList) * ui32PageCount, pvPageList, hBlockPageList); - psLinuxMemArea->uData.sPageList.pvPageList = IMG_NULL; + /* Assume the user-allocator has already done the tiler math and that the + * number of tiler pages allocated matches any other allocation type. + */ + BUG_ON(ui32Bytes != (iNumPages[0] + iNumPages[1]) * PAGE_SIZE); + BUG_ON(sizeof(IMG_CPU_PHYADDR) != sizeof(int)); + + /* Glue the page lists together */ + pCPUPhysAddrs = vmalloc(sizeof(IMG_CPU_PHYADDR) * (iNumPages[0] + iNumPages[1])); + if (!pCPUPhysAddrs) + { + PVR_DPF((PVR_DBG_ERROR, "%s: Failed to allocate page list", __func__)); + goto err_free; + } + for(i = 0; i < iNumPages[0]; i++) + pCPUPhysAddrs[i].uiAddr = pu32PageAddrs[0][i]; + for(i = 0; i < iNumPages[1]; i++) + pCPUPhysAddrs[iNumPages[0] + i].uiAddr = pu32PageAddrs[1][i]; + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordAdd(DEBUG_MEM_ALLOC_TYPE_ION, + asAllocData[0].handle, + 0, + 0, + NULL, + PAGE_ALIGN(ui32Bytes), + "unknown", + 0 + ); +#endif + + for(i = 0; i < 2; i++) + psLinuxMemArea->uData.sIONTilerAlloc.psIONHandle[i] = asAllocData[i].handle; + + psLinuxMemArea->eAreaType = LINUX_MEM_AREA_ION; + psLinuxMemArea->uData.sIONTilerAlloc.pCPUPhysAddrs = pCPUPhysAddrs; + psLinuxMemArea->ui32ByteSize = ui32Bytes; + psLinuxMemArea->ui32AreaFlags = ui32AreaFlags; + INIT_LIST_HEAD(&psLinuxMemArea->sMMapOffsetStructList); + + /* We defer the cache flush to the first user mapping of this memory */ + psLinuxMemArea->bNeedsCacheInvalidate = AreaIsUncached(ui32AreaFlags); + +#if defined(DEBUG_LINUX_MEM_AREAS) + DebugLinuxMemAreaRecordAdd(psLinuxMemArea, ui32AreaFlags); +#endif + +err_out: + return psLinuxMemArea; + +err_free: + LinuxMemAreaStructFree(psLinuxMemArea); + psLinuxMemArea = IMG_NULL; + goto err_out; +} + + +IMG_VOID +FreeIONLinuxMemArea(LinuxMemArea *psLinuxMemArea) +{ + IMG_UINT32 i; + +#if defined(DEBUG_LINUX_MEM_AREAS) + DebugLinuxMemAreaRecordRemove(psLinuxMemArea); +#endif + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_ION, + psLinuxMemArea->uData.sIONTilerAlloc.psIONHandle[0], + __FILE__, __LINE__); +#endif + + for(i = 0; i < 2; i++) + { + if (!psLinuxMemArea->uData.sIONTilerAlloc.psIONHandle[i]) + break; + ion_free(gpsIONClient, psLinuxMemArea->uData.sIONTilerAlloc.psIONHandle[i]); + psLinuxMemArea->uData.sIONTilerAlloc.psIONHandle[i] = IMG_NULL; + } + + /* free copy of page list, originals are freed by ion_free */ + vfree(psLinuxMemArea->uData.sIONTilerAlloc.pCPUPhysAddrs); + psLinuxMemArea->uData.sIONTilerAlloc.pCPUPhysAddrs = IMG_NULL; LinuxMemAreaStructFree(psLinuxMemArea); } +#endif /* defined(CONFIG_ION_OMAP) */ struct page* LinuxMemAreaOffsetToPage(LinuxMemArea *psLinuxMemArea, @@ -1092,11 +1624,11 @@ LinuxMemAreaOffsetToPage(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32PageIndex; IMG_CHAR *pui8Addr; - switch(psLinuxMemArea->eAreaType) + switch (psLinuxMemArea->eAreaType) { case LINUX_MEM_AREA_ALLOC_PAGES: ui32PageIndex = PHYS_TO_PFN(ui32ByteOffset); - return psLinuxMemArea->uData.sPageList.pvPageList[ui32PageIndex]; + return psLinuxMemArea->uData.sPageList.ppsPageList[ui32PageIndex]; case LINUX_MEM_AREA_VMALLOC: pui8Addr = psLinuxMemArea->uData.sVmalloc.pvVmallocAddress; @@ -1104,7 +1636,7 @@ LinuxMemAreaOffsetToPage(LinuxMemArea *psLinuxMemArea, return vmalloc_to_page(pui8Addr); case LINUX_MEM_AREA_SUB_ALLOC: - + /* PRQA S 3670 3 */ /* ignore recursive warning */ return LinuxMemAreaOffsetToPage(psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea, psLinuxMemArea->uData.sSubAlloc.ui32ByteOffset + ui32ByteOffset); @@ -1129,8 +1661,8 @@ KMemCacheCreateWrapper(IMG_CHAR *pszName, return kmem_cache_create(pszName, Size, Align, ui32Flags, NULL #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)) , NULL -#endif - ); +#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22) */ + ); } @@ -1164,7 +1696,7 @@ _KMemCacheAllocWrapper(LinuxKMemCache *psCache, kmem_cache_size(psCache), pszFileName, ui32Line - ); + ); #else PVR_UNREFERENCED_PARAMETER(pszFileName); PVR_UNREFERENCED_PARAMETER(ui32Line); @@ -1174,30 +1706,6 @@ _KMemCacheAllocWrapper(LinuxKMemCache *psCache, } -IMG_VOID -_KMemCacheFreeWrapper(LinuxKMemCache *psCache, IMG_VOID *pvObject, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line) -{ -#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) - DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE, pvObject, pszFileName, ui32Line); -#else - PVR_UNREFERENCED_PARAMETER(pszFileName); - PVR_UNREFERENCED_PARAMETER(ui32Line); -#endif - - kmem_cache_free(psCache, pvObject); -} - - -const IMG_CHAR * -KMemCacheNameWrapper(LinuxKMemCache *psCache) -{ - PVR_UNREFERENCED_PARAMETER(psCache); - - - return ""; -} - - LinuxMemArea * NewSubLinuxMemArea(LinuxMemArea *psParentLinuxMemArea, IMG_UINT32 ui32ByteOffset, @@ -1208,7 +1716,7 @@ NewSubLinuxMemArea(LinuxMemArea *psParentLinuxMemArea, PVR_ASSERT((ui32ByteOffset+ui32Bytes) <= psParentLinuxMemArea->ui32ByteSize); psLinuxMemArea = LinuxMemAreaStructAlloc(); - if(!psLinuxMemArea) + if (!psLinuxMemArea) { return NULL; } @@ -1242,7 +1750,7 @@ FreeSubLinuxMemArea(LinuxMemArea *psLinuxMemArea) DebugLinuxMemAreaRecordRemove(psLinuxMemArea); #endif - + /* Nothing more to do than free the LinuxMemArea structure */ LinuxMemAreaStructFree(psLinuxMemArea); } @@ -1251,14 +1759,15 @@ FreeSubLinuxMemArea(LinuxMemArea *psLinuxMemArea) static LinuxMemArea * LinuxMemAreaStructAlloc(IMG_VOID) { +/* debug */ #if 0 LinuxMemArea *psLinuxMemArea; - psLinuxMemArea = kmem_cache_alloc(psLinuxMemAreaCache, GFP_KERNEL); + psLinuxMemArea = kmem_cache_alloc(g_PsLinuxMemAreaCache, GFP_KERNEL); printk(KERN_ERR "%s: psLinuxMemArea=%p\n", __FUNCTION__, psLinuxMemArea); dump_stack(); return psLinuxMemArea; #else - return KMemCacheAllocWrapper(psLinuxMemAreaCache, GFP_KERNEL); + return KMemCacheAllocWrapper(g_PsLinuxMemAreaCache, GFP_KERNEL); #endif } @@ -1274,16 +1783,16 @@ LinuxMemAreaStructFree(LinuxMemArea *psLinuxMemArea) if (psLinuxMemArea->buf) drm_gem_object_unreference_unlocked(psLinuxMemArea->buf); #endif /* SUPPORT_DRI_DRM_EXTERNAL */ - KMemCacheFreeWrapper(psLinuxMemAreaCache, psLinuxMemArea); - - + KMemCacheFreeWrapper(g_PsLinuxMemAreaCache, psLinuxMemArea); + /* debug */ + //printk(KERN_ERR "%s(%p)\n", __FUNCTION__, psLinuxMemArea); } IMG_VOID LinuxMemAreaDeepFree(LinuxMemArea *psLinuxMemArea) { - switch(psLinuxMemArea->eAreaType) + switch (psLinuxMemArea->eAreaType) { case LINUX_MEM_AREA_VMALLOC: FreeVMallocLinuxMemArea(psLinuxMemArea); @@ -1294,15 +1803,18 @@ LinuxMemAreaDeepFree(LinuxMemArea *psLinuxMemArea) case LINUX_MEM_AREA_IOREMAP: FreeIORemapLinuxMemArea(psLinuxMemArea); break; - case LINUX_MEM_AREA_EXTERNAL_KV: - FreeExternalKVLinuxMemArea(psLinuxMemArea); - break; + case LINUX_MEM_AREA_EXTERNAL_KV: + FreeExternalKVLinuxMemArea(psLinuxMemArea); + break; case LINUX_MEM_AREA_IO: FreeIOLinuxMemArea(psLinuxMemArea); break; case LINUX_MEM_AREA_SUB_ALLOC: FreeSubLinuxMemArea(psLinuxMemArea); break; + case LINUX_MEM_AREA_ION: + FreeIONLinuxMemArea(psLinuxMemArea); + break; default: PVR_DPF((PVR_DBG_ERROR, "%s: Unknown are type (%d)\n", __FUNCTION__, psLinuxMemArea->eAreaType)); @@ -1320,21 +1832,21 @@ DebugLinuxMemAreaRecordAdd(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32Flags) LinuxLockMutex(&g_sDebugMutex); - if(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC) + if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC) { g_LinuxMemAreaWaterMark += psLinuxMemArea->ui32ByteSize; - if(g_LinuxMemAreaWaterMark > g_LinuxMemAreaHighWaterMark) + if (g_LinuxMemAreaWaterMark > g_LinuxMemAreaHighWaterMark) { g_LinuxMemAreaHighWaterMark = g_LinuxMemAreaWaterMark; } } g_LinuxMemAreaCount++; - + /* Create a new memory allocation record */ psNewRecord = kmalloc(sizeof(DEBUG_LINUX_MEM_AREA_REC), GFP_KERNEL); - if(psNewRecord) + if (psNewRecord) { - + /* Record the allocation */ psNewRecord->psLinuxMemArea = psLinuxMemArea; psNewRecord->ui32Flags = ui32Flags; psNewRecord->pid = OSGetCurrentProcessIDKM(); @@ -1348,16 +1860,16 @@ DebugLinuxMemAreaRecordAdd(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32Flags) __FUNCTION__)); } - + /* Sanity check the flags */ pi8FlagsString = HAPFlagsToString(ui32Flags); - if(strstr(pi8FlagsString, "UNKNOWN")) + if (strstr(pi8FlagsString, "UNKNOWN")) { PVR_DPF((PVR_DBG_ERROR, "%s: Unexpected flags (0x%08x) associated with psLinuxMemArea @ %p", __FUNCTION__, ui32Flags, psLinuxMemArea)); - + //dump_stack(); } LinuxUnLockMutex(&g_sDebugMutex); @@ -1371,7 +1883,7 @@ static IMG_VOID* MatchLinuxMemArea_AnyVaCb(DEBUG_LINUX_MEM_AREA_REC *psCurrentRe LinuxMemArea *psLinuxMemArea; psLinuxMemArea = va_arg(va, LinuxMemArea*); - if(psCurrentRecord->psLinuxMemArea == psLinuxMemArea) + if (psCurrentRecord->psLinuxMemArea == psLinuxMemArea) { return psCurrentRecord; } @@ -1392,6 +1904,7 @@ DebugLinuxMemAreaRecordFind(LinuxMemArea *psLinuxMemArea) MatchLinuxMemArea_AnyVaCb, psLinuxMemArea); +/*exit_unlock:*/ LinuxUnLockMutex(&g_sDebugMutex); return psCurrentRecord; @@ -1405,19 +1918,19 @@ DebugLinuxMemAreaRecordRemove(LinuxMemArea *psLinuxMemArea) LinuxLockMutex(&g_sDebugMutex); - if(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC) + if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC) { g_LinuxMemAreaWaterMark -= psLinuxMemArea->ui32ByteSize; } g_LinuxMemAreaCount--; - + /* Locate the corresponding allocation entry */ psCurrentRecord = List_DEBUG_LINUX_MEM_AREA_REC_Any_va(g_LinuxMemAreaRecords, MatchLinuxMemArea_AnyVaCb, psLinuxMemArea); - if(psCurrentRecord) + if (psCurrentRecord) { - + /* Unlink the allocation record */ List_DEBUG_LINUX_MEM_AREA_REC_Remove(psCurrentRecord); kfree(psCurrentRecord); } @@ -1439,7 +1952,7 @@ LinuxMemAreaToCpuVAddr(LinuxMemArea *psLinuxMemArea) { return NULL; } - switch(psLinuxMemArea->eAreaType) + switch (psLinuxMemArea->eAreaType) { case LINUX_MEM_AREA_VMALLOC: return psLinuxMemArea->uData.sVmalloc.pvVmallocAddress; @@ -1450,8 +1963,8 @@ LinuxMemAreaToCpuVAddr(LinuxMemArea *psLinuxMemArea) case LINUX_MEM_AREA_SUB_ALLOC: { IMG_CHAR *pAddr = - LinuxMemAreaToCpuVAddr(psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea); - if(!pAddr) + LinuxMemAreaToCpuVAddr(psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea); /* PRQA S 3670 */ /* ignore recursive warning */ + if (!pAddr) { return NULL; } @@ -1473,7 +1986,7 @@ LinuxMemAreaToCpuPAddr(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32ByteOffset) return CpuPAddr; } - switch(psLinuxMemArea->eAreaType) + switch (psLinuxMemArea->eAreaType) { case LINUX_MEM_AREA_IOREMAP: { @@ -1513,11 +2026,18 @@ LinuxMemAreaToCpuPAddr(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32ByteOffset) CpuPAddr.uiAddr = VMallocToPhys(pCpuVAddr); break; } + case LINUX_MEM_AREA_ION: + { + IMG_UINT32 ui32PageIndex = PHYS_TO_PFN(ui32ByteOffset); + CpuPAddr = psLinuxMemArea->uData.sIONTilerAlloc.pCPUPhysAddrs[ui32PageIndex]; + CpuPAddr.uiAddr += ADDR_TO_PAGE_OFFSET(ui32ByteOffset); + break; + } case LINUX_MEM_AREA_ALLOC_PAGES: { struct page *page; IMG_UINT32 ui32PageIndex = PHYS_TO_PFN(ui32ByteOffset); - page = psLinuxMemArea->uData.sPageList.pvPageList[ui32PageIndex]; + page = psLinuxMemArea->uData.sPageList.ppsPageList[ui32PageIndex]; CpuPAddr.uiAddr = page_to_phys(page); CpuPAddr.uiAddr += ADDR_TO_PAGE_OFFSET(ui32ByteOffset); break; @@ -1546,22 +2066,23 @@ LinuxMemAreaToCpuPAddr(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32ByteOffset) IMG_BOOL LinuxMemAreaPhysIsContig(LinuxMemArea *psLinuxMemArea) { - switch(psLinuxMemArea->eAreaType) + switch (psLinuxMemArea->eAreaType) { case LINUX_MEM_AREA_IOREMAP: case LINUX_MEM_AREA_IO: return IMG_TRUE; - case LINUX_MEM_AREA_EXTERNAL_KV: - return psLinuxMemArea->uData.sExternalKV.bPhysContig; + case LINUX_MEM_AREA_EXTERNAL_KV: + return psLinuxMemArea->uData.sExternalKV.bPhysContig; + case LINUX_MEM_AREA_ION: case LINUX_MEM_AREA_VMALLOC: case LINUX_MEM_AREA_ALLOC_PAGES: - return IMG_FALSE; + return IMG_FALSE; case LINUX_MEM_AREA_SUB_ALLOC: - - return LinuxMemAreaPhysIsContig(psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea); + /* PRQA S 3670 1 */ /* ignore recursive warning */ + return LinuxMemAreaPhysIsContig(psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea); default: PVR_DPF((PVR_DBG_ERROR, "%s: Unknown LinuxMemArea type (%d)\n", @@ -1575,8 +2096,10 @@ LinuxMemAreaPhysIsContig(LinuxMemArea *psLinuxMemArea) const IMG_CHAR * LinuxMemAreaTypeToString(LINUX_MEM_AREA_TYPE eMemAreaType) { - - switch(eMemAreaType) + /* Note we explicitly check the types instead of e.g. + * using the type to index an array of strings so + * we remain orthogonal to enum changes */ + switch (eMemAreaType) { case LINUX_MEM_AREA_IOREMAP: return "LINUX_MEM_AREA_IOREMAP"; @@ -1590,6 +2113,8 @@ LinuxMemAreaTypeToString(LINUX_MEM_AREA_TYPE eMemAreaType) return "LINUX_MEM_AREA_SUB_ALLOC"; case LINUX_MEM_AREA_ALLOC_PAGES: return "LINUX_MEM_AREA_ALLOC_PAGES"; + case LINUX_MEM_AREA_ION: + return "LINUX_MEM_AREA_ION"; default: PVR_ASSERT(0); } @@ -1601,7 +2126,7 @@ LinuxMemAreaTypeToString(LINUX_MEM_AREA_TYPE eMemAreaType) #if defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) static void ProcSeqStartstopDebugMutex(struct seq_file *sfile, IMG_BOOL start) { - if(start) + if (start) { LinuxLockMutex(&g_sDebugMutex); } @@ -1610,7 +2135,7 @@ static void ProcSeqStartstopDebugMutex(struct seq_file *sfile, IMG_BOOL start) LinuxUnLockMutex(&g_sDebugMutex); } } -#endif +#endif /* defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) */ #if defined(DEBUG_LINUX_MEM_AREAS) @@ -1627,7 +2152,7 @@ static IMG_VOID* DecOffMemAreaRec_AnyVaCb(DEBUG_LINUX_MEM_AREA_REC *psNode, va_l } } - +/* seq_file version of generating output, for reference check proc.c:CreateProcReadEntrySeq */ static void* ProcSeqNextMemArea(struct seq_file *sfile,void* el,loff_t off) { DEBUG_LINUX_MEM_AREA_REC *psRecord; @@ -1641,7 +2166,7 @@ static void* ProcSeqNextMemArea(struct seq_file *sfile,void* el,loff_t off) static void* ProcSeqOff2ElementMemArea(struct seq_file * sfile, loff_t off) { DEBUG_LINUX_MEM_AREA_REC *psRecord; - if(!off) + if (!off) { return PVR_PROC_SEQ_START_TOKEN; } @@ -1657,11 +2182,11 @@ static void* ProcSeqOff2ElementMemArea(struct seq_file * sfile, loff_t off) static void ProcSeqShowMemArea(struct seq_file *sfile,void* el) { DEBUG_LINUX_MEM_AREA_REC *psRecord = (DEBUG_LINUX_MEM_AREA_REC*)el; - if(el == PVR_PROC_SEQ_START_TOKEN) + if (el == PVR_PROC_SEQ_START_TOKEN) { #if !defined(DEBUG_LINUX_XML_PROC_FILES) - seq_printf( sfile, + seq_printf(sfile, "Number of Linux Memory Areas: %u\n" "At the current water mark these areas correspond to %u bytes (excluding SUB areas)\n" "At the highest water mark these areas corresponded to %u bytes (excluding SUB areas)\n" @@ -1677,23 +2202,23 @@ static void ProcSeqShowMemArea(struct seq_file *sfile,void* el) "Bytes", "Pid", "Flags" - ); + ); #else - seq_printf( sfile, + seq_printf(sfile, "<mem_areas_header>\n" "\t<count>%u</count>\n" - "\t<watermark key=\"mar0\" description=\"current\" bytes=\"%u\"/>\n" - "\t<watermark key=\"mar1\" description=\"high\" bytes=\"%u\"/>\n" + "\t<watermark key=\"mar0\" description=\"current\" bytes=\"%u\"/>\n" /* (excluding SUB areas) */ + "\t<watermark key=\"mar1\" description=\"high\" bytes=\"%u\"/>\n" /* (excluding SUB areas) */ "</mem_areas_header>\n", g_LinuxMemAreaCount, g_LinuxMemAreaWaterMark, g_LinuxMemAreaHighWaterMark - ); + ); #endif return; } - seq_printf( sfile, + seq_printf(sfile, #if !defined(DEBUG_LINUX_XML_PROC_FILES) "%8p %-24s %8p %08x %-8d %-5u %08x=(%s)\n", #else @@ -1702,9 +2227,9 @@ static void ProcSeqShowMemArea(struct seq_file *sfile,void* el) "\t<type>%s</type>\n" "\t<cpu_virtual>%8p</cpu_virtual>\n" "\t<cpu_physical>%08x</cpu_physical>\n" - "\t<bytes>%ld</bytes>\n" + "\t<bytes>%d</bytes>\n" "\t<pid>%u</pid>\n" - "\t<flags>%08lx</flags>\n" + "\t<flags>%08x</flags>\n" "\t<flags_string>%s</flags_string>\n" "</linux_mem_area>\n", #endif @@ -1716,11 +2241,11 @@ static void ProcSeqShowMemArea(struct seq_file *sfile,void* el) psRecord->pid, psRecord->ui32Flags, HAPFlagsToString(psRecord->ui32Flags) - ); + ); } -#endif +#endif /* DEBUG_LINUX_MEM_AREAS */ #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) @@ -1739,7 +2264,7 @@ static IMG_VOID* DecOffMemAllocRec_AnyVaCb(DEBUG_MEM_ALLOC_REC *psNode, va_list } - +/* seq_file version of generating output, for reference check proc.c:CreateProcReadEntrySeq */ static void* ProcSeqNextMemoryRecords(struct seq_file *sfile,void* el,loff_t off) { DEBUG_MEM_ALLOC_REC *psRecord; @@ -1748,9 +2273,9 @@ static void* ProcSeqNextMemoryRecords(struct seq_file *sfile,void* el,loff_t off DecOffMemAllocRec_AnyVaCb, &off); #if defined(DEBUG_LINUX_XML_PROC_FILES) - if(!psRecord) + if (!psRecord) { - seq_printf( sfile, "</meminfo>\n"); + seq_printf(sfile, "</meminfo>\n"); } #endif @@ -1760,7 +2285,7 @@ static void* ProcSeqNextMemoryRecords(struct seq_file *sfile,void* el,loff_t off static void* ProcSeqOff2ElementMemoryRecords(struct seq_file *sfile, loff_t off) { DEBUG_MEM_ALLOC_REC *psRecord; - if(!off) + if (!off) { return PVR_PROC_SEQ_START_TOKEN; } @@ -1771,9 +2296,9 @@ static void* ProcSeqOff2ElementMemoryRecords(struct seq_file *sfile, loff_t off) &off); #if defined(DEBUG_LINUX_XML_PROC_FILES) - if(!psRecord) + if (!psRecord) { - seq_printf( sfile, "</meminfo>\n"); + seq_printf(sfile, "</meminfo>\n"); } #endif @@ -1783,64 +2308,78 @@ static void* ProcSeqOff2ElementMemoryRecords(struct seq_file *sfile, loff_t off) static void ProcSeqShowMemoryRecords(struct seq_file *sfile,void* el) { DEBUG_MEM_ALLOC_REC *psRecord = (DEBUG_MEM_ALLOC_REC*)el; - if(el == PVR_PROC_SEQ_START_TOKEN) + if (el == PVR_PROC_SEQ_START_TOKEN) { #if !defined(DEBUG_LINUX_XML_PROC_FILES) - - seq_printf( sfile, "%-60s: %d bytes\n", + /* NOTE: If you update this code, please also update the XML varient below + * too! */ + + seq_printf(sfile, "%-60s: %d bytes\n", "Current Water Mark of bytes allocated via kmalloc", g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMALLOC]); - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "Highest Water Mark of bytes allocated via kmalloc", g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMALLOC]); - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "Current Water Mark of bytes allocated via vmalloc", g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMALLOC]); - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "Highest Water Mark of bytes allocated via vmalloc", g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMALLOC]); - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "Current Water Mark of bytes allocated via alloc_pages", g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES]); - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "Highest Water Mark of bytes allocated via alloc_pages", g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES]); - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "Current Water Mark of bytes allocated via ioremap", g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_IOREMAP]); - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "Highest Water Mark of bytes allocated via ioremap", g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_IOREMAP]); - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "Current Water Mark of bytes reserved for \"IO\" memory areas", g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_IO]); - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "Highest Water Mark of bytes allocated for \"IO\" memory areas", g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_IO]); - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "Current Water Mark of bytes allocated via kmem_cache_alloc", g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE]); - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "Highest Water Mark of bytes allocated via kmem_cache_alloc", g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE]); +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) + seq_printf(sfile, "%-60s: %d bytes\n", + "Current Water Mark of bytes mapped via vmap", + g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMAP]); + seq_printf(sfile, "%-60s: %d bytes\n", + "Highest Water Mark of bytes mapped via vmap", + g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMAP]); +#endif +#if (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0) + seq_printf(sfile, "%-60s: %d pages\n", + "Number of pages in page pool", + atomic_read(&g_sPagePoolEntryCount)); +#endif seq_printf( sfile, "\n"); - - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "The Current Water Mark for memory allocated from system RAM", - g_SysRAMWaterMark); - seq_printf( sfile, "%-60s: %d bytes\n", + SysRAMTrueWaterMark()); + seq_printf(sfile, "%-60s: %d bytes\n", "The Highest Water Mark for memory allocated from system RAM", g_SysRAMHighWaterMark); - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "The Current Water Mark for memory allocated from IO memory", g_IOMemWaterMark); - seq_printf( sfile, "%-60s: %d bytes\n", + seq_printf(sfile, "%-60s: %d bytes\n", "The Highest Water Mark for memory allocated from IO memory", g_IOMemHighWaterMark); seq_printf( sfile, "\n"); - seq_printf( sfile, "Details for all known allocations:\n" + seq_printf(sfile, "Details for all known allocations:\n" "%-16s %-8s %-8s %-10s %-5s %-10s %s\n", "Type", "CpuVAddr", @@ -1850,70 +2389,84 @@ static void ProcSeqShowMemoryRecords(struct seq_file *sfile,void* el) "PrivateData", "Filename:Line"); -#else - +#else /* DEBUG_LINUX_XML_PROC_FILES */ - seq_printf( sfile, "<meminfo>\n<meminfo_header>\n"); - seq_printf( sfile, + /* Note: If you want to update the description property of a watermark + * ensure that the key property remains unchanged so that watermark data + * logged over time from different driver revisions may remain comparable + */ + seq_printf(sfile, "<meminfo>\n<meminfo_header>\n"); + seq_printf(sfile, "<watermark key=\"mr0\" description=\"kmalloc_current\" bytes=\"%d\"/>\n", g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMALLOC]); - seq_printf( sfile, + seq_printf(sfile, "<watermark key=\"mr1\" description=\"kmalloc_high\" bytes=\"%d\"/>\n", g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMALLOC]); - seq_printf( sfile, + seq_printf(sfile, "<watermark key=\"mr2\" description=\"vmalloc_current\" bytes=\"%d\"/>\n", g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMALLOC]); - seq_printf( sfile, + seq_printf(sfile, "<watermark key=\"mr3\" description=\"vmalloc_high\" bytes=\"%d\"/>\n", g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMALLOC]); - seq_printf( sfile, + seq_printf(sfile, "<watermark key=\"mr4\" description=\"alloc_pages_current\" bytes=\"%d\"/>\n", g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES]); - seq_printf( sfile, + seq_printf(sfile, "<watermark key=\"mr5\" description=\"alloc_pages_high\" bytes=\"%d\"/>\n", g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES]); - seq_printf( sfile, + seq_printf(sfile, "<watermark key=\"mr6\" description=\"ioremap_current\" bytes=\"%d\"/>\n", g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_IOREMAP]); - seq_printf( sfile, + seq_printf(sfile, "<watermark key=\"mr7\" description=\"ioremap_high\" bytes=\"%d\"/>\n", g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_IOREMAP]); - seq_printf( sfile, + seq_printf(sfile, "<watermark key=\"mr8\" description=\"io_current\" bytes=\"%d\"/>\n", g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_IO]); - seq_printf( sfile, + seq_printf(sfile, "<watermark key=\"mr9\" description=\"io_high\" bytes=\"%d\"/>\n", g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_IO]); - seq_printf( sfile, + seq_printf(sfile, "<watermark key=\"mr10\" description=\"kmem_cache_current\" bytes=\"%d\"/>\n", g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE]); - seq_printf( sfile, + seq_printf(sfile, "<watermark key=\"mr11\" description=\"kmem_cache_high\" bytes=\"%d\"/>\n", g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE]); - seq_printf( sfile,"\n" ); - - seq_printf( sfile, +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) + seq_printf(sfile, + "<watermark key=\"mr12\" description=\"vmap_current\" bytes=\"%d\"/>\n", + g_WaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMAP]); + seq_printf(sfile, + "<watermark key=\"mr13\" description=\"vmap_high\" bytes=\"%d\"/>\n", + g_HighWaterMarkData[DEBUG_MEM_ALLOC_TYPE_VMAP]); +#endif + seq_printf(sfile, "<watermark key=\"mr14\" description=\"system_ram_current\" bytes=\"%d\"/>\n", - g_SysRAMWaterMark); - seq_printf( sfile, + SysRAMTrueWaterMark()); + seq_printf(sfile, "<watermark key=\"mr15\" description=\"system_ram_high\" bytes=\"%d\"/>\n", g_SysRAMHighWaterMark); - seq_printf( sfile, + seq_printf(sfile, "<watermark key=\"mr16\" description=\"system_io_current\" bytes=\"%d\"/>\n", g_IOMemWaterMark); - seq_printf( sfile, + seq_printf(sfile, "<watermark key=\"mr17\" description=\"system_io_high\" bytes=\"%d\"/>\n", g_IOMemHighWaterMark); - seq_printf( sfile, "</meminfo_header>\n"); +#if (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0) + seq_printf(sfile, + "<watermark key=\"mr18\" description=\"page_pool_current\" bytes=\"%d\"/>\n", + PAGES_TO_BYTES(atomic_read(&g_sPagePoolEntryCount))); +#endif + seq_printf(sfile, "</meminfo_header>\n"); -#endif +#endif /* DEBUG_LINUX_XML_PROC_FILES */ return; } - if(psRecord->eAllocType != DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE) + if (psRecord->eAllocType != DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE) { - seq_printf( sfile, + seq_printf(sfile, #if !defined(DEBUG_LINUX_XML_PROC_FILES) "%-16s %-8p %08x %-10d %-5d %-10s %s:%d\n", #else @@ -1939,7 +2492,7 @@ static void ProcSeqShowMemoryRecords(struct seq_file *sfile,void* el) } else { - seq_printf( sfile, + seq_printf(sfile, #if !defined(DEBUG_LINUX_XML_PROC_FILES) "%-16s %-8p %08x %-10d %-5d %-10s %s:%d\n", #else @@ -1965,10 +2518,11 @@ static void ProcSeqShowMemoryRecords(struct seq_file *sfile,void* el) } } -#endif +#endif /* defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) */ #if defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MMAP_AREAS) +/* This could be moved somewhere more general */ const IMG_CHAR * HAPFlagsToString(IMG_UINT32 ui32Flags) { @@ -1978,7 +2532,6 @@ HAPFlagsToString(IMG_UINT32 ui32Flags) IMG_CHAR *apszCacheTypes[] = { "UNCACHED", "CACHED", - "SMART", "WRITECOMBINE", "UNKNOWN" }; @@ -1991,33 +2544,35 @@ HAPFlagsToString(IMG_UINT32 ui32Flags) "UNKNOWN" }; - - if(ui32Flags & PVRSRV_HAP_UNCACHED){ - ui32CacheTypeIndex=0; - }else if(ui32Flags & PVRSRV_HAP_CACHED){ - ui32CacheTypeIndex=1; - }else if(ui32Flags & PVRSRV_HAP_SMART){ - ui32CacheTypeIndex=2; - }else if(ui32Flags & PVRSRV_HAP_WRITECOMBINE){ - ui32CacheTypeIndex=3; - }else{ - ui32CacheTypeIndex=4; + /* FIXME create an enum for the cache type that we can + * cast and select so we get compiler warnings when + * when this code isn't complete due to new flags */ + if (ui32Flags & PVRSRV_HAP_UNCACHED) { + ui32CacheTypeIndex = 0; + } else if (ui32Flags & PVRSRV_HAP_CACHED) { + ui32CacheTypeIndex = 1; + } else if (ui32Flags & PVRSRV_HAP_WRITECOMBINE) { + ui32CacheTypeIndex = 2; + } else { + ui32CacheTypeIndex = 3; PVR_DPF((PVR_DBG_ERROR, "%s: unknown cache type (%u)", __FUNCTION__, (ui32Flags & PVRSRV_HAP_CACHETYPE_MASK))); } - - if(ui32Flags & PVRSRV_HAP_KERNEL_ONLY){ + /* FIXME create an enum for the map type that we can + * cast and select so we get compiler warnings when + * when this code isn't complete due to new flags */ + if (ui32Flags & PVRSRV_HAP_KERNEL_ONLY) { ui32MapTypeIndex = 0; - }else if(ui32Flags & PVRSRV_HAP_SINGLE_PROCESS){ + } else if (ui32Flags & PVRSRV_HAP_SINGLE_PROCESS) { ui32MapTypeIndex = 1; - }else if(ui32Flags & PVRSRV_HAP_MULTI_PROCESS){ + } else if (ui32Flags & PVRSRV_HAP_MULTI_PROCESS) { ui32MapTypeIndex = 2; - }else if(ui32Flags & PVRSRV_HAP_FROM_EXISTING_PROCESS){ + } else if (ui32Flags & PVRSRV_HAP_FROM_EXISTING_PROCESS) { ui32MapTypeIndex = 3; - }else if(ui32Flags & PVRSRV_HAP_NO_CPU_VIRTUAL){ + } else if (ui32Flags & PVRSRV_HAP_NO_CPU_VIRTUAL) { ui32MapTypeIndex = 4; - }else{ + } else { ui32MapTypeIndex = 5; PVR_DPF((PVR_DBG_ERROR, "%s: unknown map type (%u)", __FUNCTION__, (ui32Flags & PVRSRV_HAP_MAPTYPE_MASK))); @@ -2039,3 +2594,222 @@ HAPFlagsToString(IMG_UINT32 ui32Flags) } #endif +#if defined(DEBUG_LINUX_MEM_AREAS) +static IMG_VOID LinuxMMCleanup_MemAreas_ForEachCb(DEBUG_LINUX_MEM_AREA_REC *psCurrentRecord) +{ + LinuxMemArea *psLinuxMemArea; + + psLinuxMemArea = psCurrentRecord->psLinuxMemArea; + PVR_DPF((PVR_DBG_ERROR, "%s: BUG!: Cleaning up Linux memory area (%p), type=%s, size=%d bytes", + __FUNCTION__, + psCurrentRecord->psLinuxMemArea, + LinuxMemAreaTypeToString(psCurrentRecord->psLinuxMemArea->eAreaType), + psCurrentRecord->psLinuxMemArea->ui32ByteSize)); + /* Note this will also remove psCurrentRecord from g_LinuxMemAreaRecords + * but that's ok since we have already got a pointer to the next area. */ + LinuxMemAreaDeepFree(psLinuxMemArea); +} +#endif + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) +static IMG_VOID LinuxMMCleanup_MemRecords_ForEachVa(DEBUG_MEM_ALLOC_REC *psCurrentRecord) + +{ + +/* It's a bug if anything remains allocated at this point. We + * report an error, and simply brute force free anything we find. */ + PVR_DPF((PVR_DBG_ERROR, "%s: BUG!: Cleaning up memory: " + "type=%s " + "CpuVAddr=%p " + "CpuPAddr=0x%08x, " + "allocated @ file=%s,line=%d", + __FUNCTION__, + DebugMemAllocRecordTypeToString(psCurrentRecord->eAllocType), + psCurrentRecord->pvCpuVAddr, + psCurrentRecord->ulCpuPAddr, + psCurrentRecord->pszFileName, + psCurrentRecord->ui32Line)); + switch (psCurrentRecord->eAllocType) + { + case DEBUG_MEM_ALLOC_TYPE_KMALLOC: + KFreeWrapper(psCurrentRecord->pvCpuVAddr); + break; + case DEBUG_MEM_ALLOC_TYPE_IOREMAP: + IOUnmapWrapper(psCurrentRecord->pvCpuVAddr); + break; + case DEBUG_MEM_ALLOC_TYPE_IO: + /* Nothing needed except to free the record */ + DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_IO, psCurrentRecord->pvKey, __FILE__, __LINE__); + break; + case DEBUG_MEM_ALLOC_TYPE_VMALLOC: + VFreeWrapper(psCurrentRecord->pvCpuVAddr); + break; + case DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES: + DebugMemAllocRecordRemove(DEBUG_MEM_ALLOC_TYPE_ALLOC_PAGES, psCurrentRecord->pvKey, __FILE__, __LINE__); + break; + case DEBUG_MEM_ALLOC_TYPE_KMEM_CACHE: + KMemCacheFreeWrapper(psCurrentRecord->pvPrivateData, psCurrentRecord->pvCpuVAddr); + break; +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) + case DEBUG_MEM_ALLOC_TYPE_VMAP: + VUnmapWrapper(psCurrentRecord->pvCpuVAddr); + break; +#endif + default: + PVR_ASSERT(0); + } +} +#endif + + +#if defined(PVR_LINUX_MEM_AREA_POOL_ALLOW_SHRINK) +static struct shrinker g_sShrinker = +{ + .shrink = ShrinkPagePool, + .seeks = DEFAULT_SEEKS +}; + +static IMG_BOOL g_bShrinkerRegistered; +#endif + +IMG_VOID +LinuxMMCleanup(IMG_VOID) +{ +#if defined(DEBUG_LINUX_MEM_AREAS) + { + if (g_LinuxMemAreaCount) + { + PVR_DPF((PVR_DBG_ERROR, "%s: BUG!: There are %d LinuxMemArea allocation unfreed (%d bytes)", + __FUNCTION__, g_LinuxMemAreaCount, g_LinuxMemAreaWaterMark)); + } + + List_DEBUG_LINUX_MEM_AREA_REC_ForEach(g_LinuxMemAreaRecords, LinuxMMCleanup_MemAreas_ForEachCb); + + if (g_SeqFileMemArea) + { + RemoveProcEntrySeq(g_SeqFileMemArea); + } + } +#endif + +#if defined(PVR_LINUX_MEM_AREA_POOL_ALLOW_SHRINK) + if (g_bShrinkerRegistered) + { + unregister_shrinker(&g_sShrinker); + } +#endif + + /* + * The page pool must be freed after any remaining mem areas, but before + * the remaining memory resources. + */ + FreePagePool(); + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + { + + /* + * It's a bug if anything remains allocated at this point. We + * report an error, and simply brute force free anything we find. + */ + List_DEBUG_MEM_ALLOC_REC_ForEach(g_MemoryRecords, LinuxMMCleanup_MemRecords_ForEachVa); + + if (g_SeqFileMemoryRecords) + { + RemoveProcEntrySeq(g_SeqFileMemoryRecords); + } + } +#endif + + if (g_PsLinuxMemAreaCache) + { + KMemCacheDestroyWrapper(g_PsLinuxMemAreaCache); + } + + if (g_PsLinuxPagePoolCache) + { + KMemCacheDestroyWrapper(g_PsLinuxPagePoolCache); + } +} + +PVRSRV_ERROR +LinuxMMInit(IMG_VOID) +{ +#if defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + LinuxInitMutex(&g_sDebugMutex); +#endif + +#if defined(DEBUG_LINUX_MEM_AREAS) + { + g_SeqFileMemArea = CreateProcReadEntrySeq( + "mem_areas", + NULL, + ProcSeqNextMemArea, + ProcSeqShowMemArea, + ProcSeqOff2ElementMemArea, + ProcSeqStartstopDebugMutex + ); + if (!g_SeqFileMemArea) + { + goto failed; + } + } +#endif + + +#if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) + { + g_SeqFileMemoryRecords = CreateProcReadEntrySeq( + "meminfo", + NULL, + ProcSeqNextMemoryRecords, + ProcSeqShowMemoryRecords, + ProcSeqOff2ElementMemoryRecords, + ProcSeqStartstopDebugMutex + ); + if (!g_SeqFileMemoryRecords) + { + goto failed; + } + } +#endif + + g_PsLinuxMemAreaCache = KMemCacheCreateWrapper("img-mm", sizeof(LinuxMemArea), 0, 0); + if (!g_PsLinuxMemAreaCache) + { + PVR_DPF((PVR_DBG_ERROR,"%s: failed to allocate mem area kmem_cache", __FUNCTION__)); + goto failed; + } + +#if (PVR_LINUX_MEM_AREA_POOL_MAX_PAGES != 0) + g_iPagePoolMaxEntries = PVR_LINUX_MEM_AREA_POOL_MAX_PAGES; + if (g_iPagePoolMaxEntries <= 0 || g_iPagePoolMaxEntries > INT_MAX/2) + { + g_iPagePoolMaxEntries = INT_MAX/2; + PVR_TRACE(("%s: No limit set for page pool size", __FUNCTION__)); + } + else + { + PVR_TRACE(("%s: Maximum page pool size: %d", __FUNCTION__, g_iPagePoolMaxEntries)); + } + + g_PsLinuxPagePoolCache = KMemCacheCreateWrapper("img-mm-pool", sizeof(LinuxPagePoolEntry), 0, 0); + if (!g_PsLinuxPagePoolCache) + { + PVR_DPF((PVR_DBG_ERROR,"%s: failed to allocate page pool kmem_cache", __FUNCTION__)); + goto failed; + } +#endif + +#if defined(PVR_LINUX_MEM_AREA_POOL_ALLOW_SHRINK) + register_shrinker(&g_sShrinker); + g_bShrinkerRegistered = IMG_TRUE; +#endif + + return PVRSRV_OK; + +failed: + LinuxMMCleanup(); + return PVRSRV_ERROR_OUT_OF_MEMORY; +} + diff --git a/sgx/services4/srvkm/env/linux/mm.h b/sgx/services4/srvkm/env/linux/mm.h index da49083..2bcf408 100644 --- a/sgx/services4/srvkm/env/linux/mm.h +++ b/sgx/services4/srvkm/env/linux/mm.h @@ -1,29 +1,46 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ - +/*************************************************************************/ /*! +@Title Linux Memory Management. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Declares various memory management utility functions + for Linux. +@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. + +*/ /**************************************************************************/ #ifndef __IMG_LINUX_MM_H__ #define __IMG_LINUX_MM_H__ @@ -48,6 +65,8 @@ #define ADDR_TO_PAGE_OFFSET(addr) (((unsigned long)(addr)) & (PAGE_SIZE - 1)) +#define PAGES_TO_BYTES(pages) ((pages) << PAGE_SHIFT) + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)) #define REMAP_PFN_RANGE(vma, addr, pfn, size, prot) remap_pfn_range(vma, addr, pfn, size, prot) #else @@ -78,33 +97,43 @@ static inline IMG_UINT32 VMallocToPhys(IMG_VOID *pCpuVAddr) typedef enum { LINUX_MEM_AREA_IOREMAP, - LINUX_MEM_AREA_EXTERNAL_KV, + LINUX_MEM_AREA_EXTERNAL_KV, LINUX_MEM_AREA_IO, LINUX_MEM_AREA_VMALLOC, LINUX_MEM_AREA_ALLOC_PAGES, LINUX_MEM_AREA_SUB_ALLOC, + LINUX_MEM_AREA_ION, +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) + LINUX_MEM_AREA_VMAP, +#endif LINUX_MEM_AREA_TYPE_COUNT }LINUX_MEM_AREA_TYPE; typedef struct _LinuxMemArea LinuxMemArea; +/* FIXME - describe this structure. */ struct _LinuxMemArea { LINUX_MEM_AREA_TYPE eAreaType; union _uData { struct _sIORemap { - + /* Note: The memory this represents is _not_ implicitly + * page aligned, neither is its size */ IMG_CPU_PHYADDR CPUPhysAddr; IMG_VOID *pvIORemapCookie; }sIORemap; struct _sExternalKV { - + /* Note: The memory this represents is _not_ implicitly + * page aligned, neither is its size */ IMG_BOOL bPhysContig; union { - + /* + * SYSPhysAddr is valid if bPhysContig is true, else + * pSysPhysAddr is valid + */ IMG_SYS_PHYADDR SysPhysAddr; IMG_SYS_PHYADDR *pSysPhysAddr; } uPhysAddr; @@ -112,44 +141,62 @@ struct _LinuxMemArea { }sExternalKV; struct _sIO { - + /* Note: The memory this represents is _not_ implicitly + * page aligned, neither is its size */ IMG_CPU_PHYADDR CPUPhysAddr; }sIO; struct _sVmalloc { - + /* Note the memory this represents _is_ implicitly + * page aligned _and_ so is its size */ IMG_VOID *pvVmallocAddress; +#if defined(PVR_LINUX_MEM_AREA_USE_VMAP) + struct page **ppsPageList; + IMG_HANDLE hBlockPageList; +#endif }sVmalloc; struct _sPageList { - - struct page **pvPageList; + /* Note the memory this represents _is_ implicitly + * page aligned _and_ so is its size */ + struct page **ppsPageList; IMG_HANDLE hBlockPageList; }sPageList; + struct _sIONTilerAlloc + { + /* Note the memory this represents _is_ implicitly + * page aligned _and_ so is its size */ + IMG_CPU_PHYADDR *pCPUPhysAddrs; + struct ion_handle *psIONHandle[2]; + }sIONTilerAlloc; struct _sSubAlloc { - + /* Note: The memory this represents is _not_ implicitly + * page aligned, neither is its size */ LinuxMemArea *psParentLinuxMemArea; IMG_UINT32 ui32ByteOffset; }sSubAlloc; }uData; - IMG_UINT32 ui32ByteSize; + IMG_UINT32 ui32ByteSize; /* Size of memory area */ + + IMG_UINT32 ui32AreaFlags; /* Flags passed at creation time */ - IMG_UINT32 ui32AreaFlags; + IMG_BOOL bMMapRegistered; /* Registered with mmap code */ - IMG_BOOL bMMapRegistered; + IMG_BOOL bNeedsCacheInvalidate; /* Cache should be invalidated on first map? */ - IMG_BOOL bNeedsCacheInvalidate; + IMG_HANDLE hBMHandle; /* Handle back to BM for this allocation */ - + /* List entry for global list of areas registered for mmap */ struct list_head sMMapItem; - + /* + * Head of list of all mmap offset structures associated with this + * memory area. + */ struct list_head sMMapOffsetStructList; - IMG_HANDLE hSmartCache; - #if defined(SUPPORT_DRI_DRM_EXTERNAL) IMG_HANDLE buf; /* external buffer handle, like a GEM or ION buffer */ #endif /* SUPPORT_DRI_DRM_EXTERNAL */ @@ -162,12 +209,45 @@ typedef struct kmem_cache LinuxKMemCache; #endif +/*! + ******************************************************************************* + * @Function LinuxMMInit + * + * @Description + * + * Initialise linux memory management code. + * This should be called during services initialisation. + * + * @Return none +******************************************************************************/ PVRSRV_ERROR LinuxMMInit(IMG_VOID); +/*! + ******************************************************************************* + * + * @Function LinuxMMCleanup + * + * @Description + * + * Cleanup state for the linux memory management code. + * This should be called at services cleanup. + * + * @Return none +******************************************************************************/ IMG_VOID LinuxMMCleanup(IMG_VOID); +/*! + ******************************************************************************* + * @brief Wrappers for kmalloc/kfree with optional /proc/pvr/km tracking + * They can also be used as more concise replacements for OSAllocMem + * in Linux specific code. + * + * @param ui32ByteSize + * + * @return + ******************************************************************************/ #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) #define KMallocWrapper(ui32ByteSize, uFlags) _KMallocWrapper(ui32ByteSize, uFlags, __FILE__, __LINE__) #else @@ -176,6 +256,14 @@ IMG_VOID LinuxMMCleanup(IMG_VOID); IMG_VOID *_KMallocWrapper(IMG_UINT32 ui32ByteSize, gfp_t uFlags, IMG_CHAR *szFileName, IMG_UINT32 ui32Line); +/*! + ******************************************************************************* + * @brief + * + * @param pvCpuVAddr + * + * @return + ******************************************************************************/ #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) #define KFreeWrapper(pvCpuVAddr) _KFreeWrapper(pvCpuVAddr, __FILE__, __LINE__) #else @@ -184,6 +272,15 @@ IMG_VOID *_KMallocWrapper(IMG_UINT32 ui32ByteSize, gfp_t uFlags, IMG_CHAR *szFil IMG_VOID _KFreeWrapper(IMG_VOID *pvCpuVAddr, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line); +/*! + ******************************************************************************* + * @brief + * + * @param ui32Bytes + * @param ui32AllocFlags + * + * @return + ******************************************************************************/ #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) #define VMallocWrapper(ui32Bytes, ui32AllocFlags) _VMallocWrapper(ui32Bytes, ui32AllocFlags, __FILE__, __LINE__) #else @@ -192,6 +289,14 @@ IMG_VOID _KFreeWrapper(IMG_VOID *pvCpuVAddr, IMG_CHAR *pszFileName, IMG_UINT32 u IMG_VOID *_VMallocWrapper(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AllocFlags, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line); +/*! + ******************************************************************************* + * @brief + * + * @param pvCpuVAddr + * + * @return + ******************************************************************************/ #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) #define VFreeWrapper(pvCpuVAddr) _VFreeWrapper(pvCpuVAddr, __FILE__, __LINE__) #else @@ -200,12 +305,38 @@ IMG_VOID *_VMallocWrapper(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AllocFlags, IMG_C IMG_VOID _VFreeWrapper(IMG_VOID *pvCpuVAddr, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line); +/*! + ******************************************************************************* + * @brief Allocates virtually contiguous pages + * + * @param ui32Bytes number of bytes to reserve + * @param ui32AreaFlags Heap caching and mapping Flags + * + * @return Page-aligned address of virtual allocation or NULL on error + ******************************************************************************/ LinuxMemArea *NewVMallocLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags); +/*! + ******************************************************************************* + * @brief Deallocates virtually contiguous pages + * + * @param LinuxMemArea from NewVMallocLinuxMemArea + * + ******************************************************************************/ IMG_VOID FreeVMallocLinuxMemArea(LinuxMemArea *psLinuxMemArea); +/*! + ******************************************************************************* + * @brief Reserve physical IO memory and create a CPU virtual mapping for it + * + * @param BasePAddr + * @param ui32Bytes + * @param ui32MappingFlags + * + * @return + ******************************************************************************/ #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) #define IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags) \ _IORemapWrapper(BasePAddr, ui32Bytes, ui32MappingFlags, __FILE__, __LINE__) @@ -220,17 +351,63 @@ IMG_VOID *_IORemapWrapper(IMG_CPU_PHYADDR BasePAddr, IMG_UINT32 ui32Line); +/*! + ******************************************************************************* + * @brief Reserve physical IO memory and create a CPU virtual mapping for it + * + * @param BasePAddr + * @param ui32Bytes + * @param ui32AreaFlags Heap caching and mapping Flags + * + * @return + ******************************************************************************/ LinuxMemArea *NewIORemapLinuxMemArea(IMG_CPU_PHYADDR BasePAddr, IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags); +/*! + ******************************************************************************* + * @brief + * + * @param psLinuxMemArea + * + * @return + ********************************************************************************/ IMG_VOID FreeIORemapLinuxMemArea(LinuxMemArea *psLinuxMemArea); +/*! + ******************************************************************************* + * @brief Register physical memory which already has a CPU virtual mapping + * + * @param pBasePAddr + * @param pvCPUVAddr + * @param bPhysContig + * @param ui32Bytes + * @param ui32AreaFlags Heap caching and mapping Flags + * + * @return + ******************************************************************************/ LinuxMemArea *NewExternalKVLinuxMemArea(IMG_SYS_PHYADDR *pBasePAddr, IMG_VOID *pvCPUVAddr, IMG_UINT32 ui32Bytes, IMG_BOOL bPhysContig, IMG_UINT32 ui32AreaFlags); +/*! + ******************************************************************************* + * @brief + * + * @param psLinuxMemArea + * + * @return + ******************************************************************************/ IMG_VOID FreeExternalKVLinuxMemArea(LinuxMemArea *psLinuxMemArea); +/*! + ****************************************************************************** + * @brief Unmaps an IO memory mapping created using IORemap + * + * @param pvIORemapCookie + * + * @return + ******************************************************************************/ #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) #define IOUnmapWrapper(pvIORemapCookie) \ _IOUnmapWrapper(pvIORemapCookie, __FILE__, __LINE__) @@ -241,15 +418,52 @@ IMG_VOID FreeExternalKVLinuxMemArea(LinuxMemArea *psLinuxMemArea); IMG_VOID _IOUnmapWrapper(IMG_VOID *pvIORemapCookie, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line); +/*! + ******************************************************************************* + * @brief + * + * @param psLinuxMemArea + * @param ui32ByteOffset + * + * @return + ******************************************************************************/ struct page *LinuxMemAreaOffsetToPage(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32ByteOffset); +/*! + ******************************************************************************* + * @brief + * + * @param pszName + * @param Size + * @param Align + * @param ui32Flags + * + * @return + ******************************************************************************/ LinuxKMemCache *KMemCacheCreateWrapper(IMG_CHAR *pszName, size_t Size, size_t Align, IMG_UINT32 ui32Flags); +/*! + ******************************************************************************* + * @brief + * + * @param psCache + * + * @return + ******************************************************************************/ IMG_VOID KMemCacheDestroyWrapper(LinuxKMemCache *psCache); +/*! + ******************************************************************************* + * @brief + * + * @param psCache + * @param Flags + * + * @return + ******************************************************************************/ #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) #define KMemCacheAllocWrapper(psCache, Flags) _KMemCacheAllocWrapper(psCache, Flags, __FILE__, __LINE__) #else @@ -262,6 +476,15 @@ IMG_VOID *_KMemCacheAllocWrapper(LinuxKMemCache *psCache, gfp_t Flags, IMG_CHAR IMG_VOID *_KMemCacheAllocWrapper(LinuxKMemCache *psCache, int Flags, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line); #endif +/*! + ******************************************************************************* + * @brief + * + * @param psCache + * @param pvObject + * + * @return + ******************************************************************************/ #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) #define KMemCacheFreeWrapper(psCache, pvObject) _KMemCacheFreeWrapper(psCache, pvObject, __FILE__, __LINE__) #else @@ -270,29 +493,146 @@ IMG_VOID *_KMemCacheAllocWrapper(LinuxKMemCache *psCache, int Flags, IMG_CHAR *p IMG_VOID _KMemCacheFreeWrapper(LinuxKMemCache *psCache, IMG_VOID *pvObject, IMG_CHAR *pszFileName, IMG_UINT32 ui32Line); +/*! + ******************************************************************************* + * @brief + * + * @param psCache + * + * @return + ******************************************************************************/ const IMG_CHAR *KMemCacheNameWrapper(LinuxKMemCache *psCache); +/*! + ******************************************************************************* + * @brief + * + * @param BasePAddr + * @param ui32Bytes + * @param ui32AreaFlags Heap caching and mapping Flags + * + * @return + ******************************************************************************/ LinuxMemArea *NewIOLinuxMemArea(IMG_CPU_PHYADDR BasePAddr, IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags); +/*! + ******************************************************************************* + * @brief + * + * @param psLinuxMemArea + * + * @return + ******************************************************************************/ IMG_VOID FreeIOLinuxMemArea(LinuxMemArea *psLinuxMemArea); +/*! + ******************************************************************************* + * @brief + * + * @param ui32Bytes + * @param ui32AreaFlags E.g Heap caching and mapping Flags + * + * @return + ******************************************************************************/ LinuxMemArea *NewAllocPagesLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags); +/*! + ******************************************************************************* + * @brief + * + * @param psLinuxMemArea + * + * @return + ******************************************************************************/ IMG_VOID FreeAllocPagesLinuxMemArea(LinuxMemArea *psLinuxMemArea); +#if defined(CONFIG_ION_OMAP) + +/*! + ******************************************************************************* + * @brief + * + * @param ui32Bytes + * @param ui32AreaFlags E.g Heap caching and mapping Flags + * + * @return + ******************************************************************************/ +LinuxMemArea * +NewIONLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags, + IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength); + + +/*! + ******************************************************************************* + * @brief + * + * @param psLinuxMemArea + * + * @return + ******************************************************************************/ +IMG_VOID FreeIONLinuxMemArea(LinuxMemArea *psLinuxMemArea); + +#else /* defined(CONFIG_ION_OMAP) */ + +static inline LinuxMemArea * +NewIONLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags, + IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength) +{ + PVR_UNREFERENCED_PARAMETER(ui32Bytes); + PVR_UNREFERENCED_PARAMETER(ui32AreaFlags); + PVR_UNREFERENCED_PARAMETER(pvPrivData); + PVR_UNREFERENCED_PARAMETER(ui32PrivDataLength); + BUG(); + return IMG_NULL; +} + +static inline IMG_VOID FreeIONLinuxMemArea(LinuxMemArea *psLinuxMemArea) +{ + PVR_UNREFERENCED_PARAMETER(psLinuxMemArea); + BUG(); +} + +#endif /* defined(CONFIG_ION_OMAP) */ + + +/*! + ******************************************************************************* + * @brief + * + * @param psParentLinuxMemArea + * @param ui32ByteOffset + * @param ui32Bytes + * + * @return + ******************************************************************************/ LinuxMemArea *NewSubLinuxMemArea(LinuxMemArea *psParentLinuxMemArea, IMG_UINT32 ui32ByteOffset, IMG_UINT32 ui32Bytes); +/*! + ******************************************************************************* + * @brief + * + * @param psLinuxMemArea + * + * @return + ******************************************************************************/ IMG_VOID LinuxMemAreaDeepFree(LinuxMemArea *psLinuxMemArea); +/*! + ******************************************************************************* + * @brief For debug builds, LinuxMemAreas are tracked in /proc + * + * @param psLinuxMemArea + * + ******************************************************************************/ #if defined(LINUX_MEM_AREAS_DEBUG) IMG_VOID LinuxMemAreaRegister(LinuxMemArea *psLinuxMemArea); #else @@ -300,16 +640,49 @@ IMG_VOID LinuxMemAreaRegister(LinuxMemArea *psLinuxMemArea); #endif +/*! + ******************************************************************************* + * @brief + * + * @param psLinuxMemArea + * + * @return + ******************************************************************************/ IMG_VOID *LinuxMemAreaToCpuVAddr(LinuxMemArea *psLinuxMemArea); +/*! + ******************************************************************************* + * @brief + * + * @param psLinuxMemArea + * @param ui32ByteOffset + * + * @return + ******************************************************************************/ IMG_CPU_PHYADDR LinuxMemAreaToCpuPAddr(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32ByteOffset); #define LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32ByteOffset) PHYS_TO_PFN(LinuxMemAreaToCpuPAddr(psLinuxMemArea, ui32ByteOffset).uiAddr) +/*! + ******************************************************************************* + * @brief Indicate whether a LinuxMemArea is physically contiguous + * + * @param psLinuxMemArea + * + * @return IMG_TRUE if the physical address range is contiguous, else IMG_FALSE + ******************************************************************************/ IMG_BOOL LinuxMemAreaPhysIsContig(LinuxMemArea *psLinuxMemArea); +/*! + ******************************************************************************* + * @brief Return the real underlying LinuxMemArea + * + * @param psLinuxMemArea + * + * @return The real underlying LinuxMemArea + ******************************************************************************/ static inline LinuxMemArea * LinuxMemAreaRoot(LinuxMemArea *psLinuxMemArea) { @@ -324,6 +697,14 @@ LinuxMemAreaRoot(LinuxMemArea *psLinuxMemArea) } +/*! + ******************************************************************************* + * @brief Return type of real underlying LinuxMemArea + * + * @param psLinuxMemArea + * + * @return The areas eAreaType or for SUB areas; return the parents eAreaType. + ******************************************************************************/ static inline LINUX_MEM_AREA_TYPE LinuxMemAreaRootType(LinuxMemArea *psLinuxMemArea) { @@ -331,12 +712,28 @@ LinuxMemAreaRootType(LinuxMemArea *psLinuxMemArea) } +/*! + ******************************************************************************* + * @brief Converts the enum type of a LinuxMemArea to a const string + * + * @param eMemAreaType + * + * @return const string representation of type + ******************************************************************************/ const IMG_CHAR *LinuxMemAreaTypeToString(LINUX_MEM_AREA_TYPE eMemAreaType); +/*! + ******************************************************************************* + * @brief + * + * @param ui32Flags + * + * @return + ******************************************************************************/ #if defined(DEBUG_LINUX_MEM_AREAS) || defined(DEBUG_LINUX_MMAP_AREAS) const IMG_CHAR *HAPFlagsToString(IMG_UINT32 ui32Flags); #endif -#endif +#endif /* __IMG_LINUX_MM_H__ */ diff --git a/sgx/services4/srvkm/env/linux/mmap.c b/sgx/services4/srvkm/env/linux/mmap.c index ca38e5d..6e032dc 100644 --- a/sgx/services4/srvkm/env/linux/mmap.c +++ b/sgx/services4/srvkm/env/linux/mmap.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Linux mmap interface +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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 <linux/version.h> @@ -39,6 +55,9 @@ #include <linux/wrapper.h> #endif #include <linux/slab.h> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)) +#include <linux/highmem.h> +#endif #include <asm/io.h> #include <asm/page.h> #include <asm/shmparam.h> @@ -51,15 +70,12 @@ #include <drm/drmP.h> #endif -#include "img_defs.h" -#include "services.h" -#include "servicesint.h" +#include "services_headers.h" + #include "pvrmmap.h" #include "mutils.h" #include "mmap.h" #include "mm.h" -#include "pvr_debug.h" -#include "osfunc.h" #include "proc.h" #include "mutex.h" #include "handle.h" @@ -74,7 +90,19 @@ #error "The mmap code requires PVR_SECURE_HANDLES" #endif -static PVRSRV_LINUX_MUTEX g_sMMapMutex; +/* WARNING: + * The mmap code has its own mutex, to prevent a possible deadlock, + * when using gPVRSRVLock. + * The Linux kernel takes the mm->mmap_sem before calling the mmap + * entry points (PVRMMap, MMapVOpen, MMapVClose), but the ioctl + * entry point may take mm->mmap_sem during fault handling, or + * before calling get_user_pages. If gPVRSRVLock was used in the + * mmap entry points, a deadlock could result, due to the ioctl + * and mmap code taking the two locks in different orders. + * As a corollary to this, the mmap entry points must not call + * any driver code that relies on gPVRSRVLock is held. + */ +PVRSRV_LINUX_MUTEX g_sMMapMutex; static LinuxKMemCache *g_psMemmapCache = NULL; static LIST_HEAD(g_sMMapAreaList); @@ -88,9 +116,28 @@ static inline PKV_OFFSET_STRUCT FindOffsetStructByPID(LinuxMemArea *psLinuxMemAr #if defined(DEBUG_LINUX_MMAP_AREAS) static struct proc_dir_entry *g_ProcMMap; -#endif +#endif /* defined(DEBUG_LINUX_MMAP_AREAS) */ #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) +/* + * Now that we are using mmap2 in srvclient, almost (*) the full 32 + * bit offset is available. The range of values is divided into two. + * The first part of the range, from FIRST_PHYSICAL_PFN to + * LAST_PHYSICAL_PFN, is for raw page mappings (VM_PFNMAP). The + * resulting 43 bit (*) physical address range should be enough for + * the current range of processors we support. + * + * NB: (*) -- the above figures assume 4KB page size. The offset + * argument to mmap2() is in units of 4,096 bytes regardless of page + * size. Thus, we lose (PAGE_SHIFT-12) bits of resolution on other + * architectures. + * + * The second part of the range, from FIRST_SPECIAL_PFN to LAST_SPECIAL_PFN, + * is used for all other mappings. These other mappings will always + * consist of pages with associated page structures, and need not + * represent a contiguous range of physical addresses. + * + */ #define MMAP2_PGOFF_RESOLUTION (32-PAGE_SHIFT+12) #define RESERVED_PGOFF_BITS 1 #define MAX_MMAP_HANDLE ((1UL<<(MMAP2_PGOFF_RESOLUTION-RESERVED_PGOFF_BITS))-1) @@ -100,12 +147,19 @@ static struct proc_dir_entry *g_ProcMMap; #define FIRST_SPECIAL_PFN (LAST_PHYSICAL_PFN + 1) #define LAST_SPECIAL_PFN (FIRST_SPECIAL_PFN + MAX_MMAP_HANDLE) -#else +#else /* !defined(PVR_MAKE_ALL_PFNS_SPECIAL) */ #if PAGE_SHIFT != 12 #error This build variant has not yet been made non-4KB page-size aware #endif +/* + * Since we no longer have to worry about clashes with the mmap + * offsets used for pure PFN mappings (VM_PFNMAP), there is greater + * freedom in choosing the mmap handles. This is useful if the + * mmap offset space has to be shared with another driver component. + */ + #if defined(PVR_MMAP_OFFSET_BASE) #define FIRST_SPECIAL_PFN PVR_MMAP_OFFSET_BASE #else @@ -118,21 +172,21 @@ static struct proc_dir_entry *g_ProcMMap; #define MAX_MMAP_HANDLE 0x7fffffffUL #endif -#endif +#endif /* !defined(PVR_MAKE_ALL_PFNS_SPECIAL) */ #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) static inline IMG_BOOL PFNIsPhysical(IMG_UINT32 pfn) { - - return ( (pfn <= LAST_PHYSICAL_PFN)) ? IMG_TRUE : IMG_FALSE; + /* Unsigned, no need to compare >=0 */ + return (/*(pfn >= FIRST_PHYSICAL_PFN) &&*/ (pfn <= LAST_PHYSICAL_PFN)) ? IMG_TRUE : IMG_FALSE; } static inline IMG_BOOL PFNIsSpecial(IMG_UINT32 pfn) { - - return ((pfn >= FIRST_SPECIAL_PFN) ) ? IMG_TRUE : IMG_FALSE; + /* Unsigned, no need to compare <=MAX_UINT */ + return ((pfn >= FIRST_SPECIAL_PFN) /*&& (pfn <= LAST_SPECIAL_PFN)*/) ? IMG_TRUE : IMG_FALSE; } #endif @@ -169,6 +223,16 @@ HandleToMMapOffset(IMG_HANDLE hHandle) } #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) +/* + * Determine whether physical or special mappings will be used for + * a given memory area. At present, this decision is made on + * whether the mapping represents a contiguous range of physical + * addresses, which is a requirement for raw page mappings (VM_PFNMAP). + * In the VMA structure for such a mapping, vm_pgoff is the PFN + * (page frame number, the physical address divided by the page size) + * of the first page in the VMA. The second page is assumed to have + * PFN (vm_pgoff + 1), the third (vm_pgoff + 2) and so on. + */ static inline IMG_BOOL LinuxMemAreaUsesPhysicalMap(LinuxMemArea *psLinuxMemArea) { @@ -180,11 +244,18 @@ LinuxMemAreaUsesPhysicalMap(LinuxMemArea *psLinuxMemArea) static inline IMG_UINT32 GetCurrentThreadID(IMG_VOID) { - + /* + * The PID is the thread ID, as each thread is a + * seperate process. + */ return (IMG_UINT32)current->pid; } #endif +/* + * Create an offset structure, which is used to hold per-process + * mmap data. + */ static PKV_OFFSET_STRUCT CreateOffsetStruct(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32Offset, IMG_UINT32 ui32RealByteSize) { @@ -216,14 +287,22 @@ CreateOffsetStruct(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32Offset, IMG_UINT psOffsetStruct->ui32RealByteSize = ui32RealByteSize; - + /* + * We store the TID in case two threads within a process + * generate the same offset structure, and both end up on the + * list of structures waiting to be mapped, at the same time. + * This could happen if two sub areas within the same page are + * being mapped at the same time. + * The TID allows the mmap entry point to distinguish which + * mapping is being done by which thread. + */ #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) psOffsetStruct->ui32TID = GetCurrentThreadID(); #endif psOffsetStruct->ui32PID = OSGetCurrentProcessIDKM(); #if defined(DEBUG_LINUX_MMAP_AREAS) - + /* Extra entries to support proc filesystem debug info */ psOffsetStruct->pszName = pszName; #endif @@ -259,6 +338,17 @@ DestroyOffsetStruct(PKV_OFFSET_STRUCT psOffsetStruct) } +/* + * There are no alignment constraints for mapping requests made by user + * mode Services. For this, and potentially other reasons, the + * mapping created for a users request may look different to the + * original request in terms of size and alignment. + * + * This function determines an offset that the user can add to the mapping + * that is _actually_ created which will point to the memory they are + * _really_ interested in. + * + */ static inline IMG_VOID DetermineUsersSizeAndByteOffset(LinuxMemArea *psLinuxMemArea, IMG_UINT32 *pui32RealByteSize, @@ -337,7 +427,7 @@ create_gem_wrapper(struct drm_device *dev, LinuxMemArea *psLinuxMemArea, case LINUX_MEM_AREA_ALLOC_PAGES: pages = kmalloc(sizeof(pages) * npages, GFP_KERNEL); for (i = 0; i < npages; i++) { - pages[i] = psLinuxMemArea->uData.sPageList.pvPageList[i + PHYS_TO_PFN(ui32ByteOffset)]; + pages[i] = psLinuxMemArea->uData.sPageList.ppsPageList[i + PHYS_TO_PFN(ui32ByteOffset)]; } break; case LINUX_MEM_AREA_SUB_ALLOC: @@ -355,7 +445,6 @@ create_gem_wrapper(struct drm_device *dev, LinuxMemArea *psLinuxMemArea, /* map PVR cache type flags to GEM.. */ switch(psLinuxMemArea->ui32AreaFlags & PVRSRV_HAP_CACHETYPE_MASK) { case PVRSRV_HAP_CACHED: - case PVRSRV_HAP_SMART: flags = OMAP_BO_CACHED; break; case PVRSRV_HAP_WRITECOMBINE: @@ -380,6 +469,33 @@ create_gem_wrapper(struct drm_device *dev, LinuxMemArea *psLinuxMemArea, #endif /* SUPPORT_DRI_DRM_EXTERNAL */ +/*! + ******************************************************************************* + + @Function PVRMMapOSMemHandleToMMapData + + @Description + + Determine various parameters needed to mmap a memory area, and to + locate the memory within the mapped area. + + @input psPerProc : Per-process data. + @input hMHandle : Memory handle. + @input pui32MMapOffset : pointer to location for returned mmap offset. + @input pui32ByteOffset : pointer to location for returned byte offset. + @input pui32RealByteSize : pointer to location for returned real byte size. + @input pui32UserVaddr : pointer to location for returned user mode address. + + @output pui32MMapOffset : points to mmap offset to be used in mmap2 sys call. + @output pui32ByteOffset : points to byte offset of start of memory + within mapped area returned by mmap2. + @output pui32RealByteSize : points to size of area to be mapped. + @output pui32UserVAddr : points to user mode address of start of + mapping, or 0 if it hasn't been mapped yet. + + @Return PVRSRV_ERROR : PVRSRV_OK, or error code. + + ******************************************************************************/ PVRSRV_ERROR PVRMMapOSMemHandleToMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc, #if defined (SUPPORT_SID_INTERFACE) @@ -442,24 +558,43 @@ PVRMMapOSMemHandleToMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc, } #endif /* SUPPORT_DRI_DRM_EXTERNAL */ - DetermineUsersSizeAndByteOffset(psLinuxMemArea, - pui32RealByteSize, - pui32ByteOffset); + /* Sparse mappings have to ask the BM for the virtual size */ + if (psLinuxMemArea->hBMHandle) + { + *pui32RealByteSize = BM_GetVirtualSize(psLinuxMemArea->hBMHandle); + *pui32ByteOffset = 0; + } + else + { + DetermineUsersSizeAndByteOffset(psLinuxMemArea, + pui32RealByteSize, + pui32ByteOffset); + } psOffsetStruct = FindOffsetStructByPID(psLinuxMemArea, psPerProc->ui32PID); if (psOffsetStruct) { - PVR_ASSERT(*pui32RealByteSize == psOffsetStruct->ui32RealByteSize); - + if (!psLinuxMemArea->hBMHandle) + { + PVR_ASSERT(*pui32RealByteSize == psOffsetStruct->ui32RealByteSize); + } + /* + * User mode locking is required to stop two threads racing to + * map the same memory area. The lock should prevent a + * second thread retrieving mmap data for a given handle, + * before the first thread has done the mmap. + * Without locking, both threads may attempt the mmap, + * and one of them will fail. + */ *pui32MMapOffset = psOffsetStruct->ui32MMapOffset; *pui32UserVAddr = psOffsetStruct->ui32UserVAddr; - psOffsetStruct->ui32RefCount++; + PVRSRVOffsetStructIncRef(psOffsetStruct); eError = PVRSRV_OK; goto exit_unlock; } - + /* Memory area won't have been mapped yet */ *pui32UserVAddr = 0; #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) @@ -495,18 +630,22 @@ PVRMMapOSMemHandleToMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc, goto exit_unlock; } - + /* + * Offset structures representing physical mappings are added to + * a list, so that they can be located when the memory area is mapped. + */ list_add_tail(&psOffsetStruct->sMMapItem, &g_sMMapOffsetStructList); psOffsetStruct->bOnMMapList = IMG_TRUE; - psOffsetStruct->ui32RefCount++; + PVRSRVOffsetStructIncRef(psOffsetStruct); eError = PVRSRV_OK; - - - + /* Need to scale up the offset to counter the shifting that + is done in the mmap2() syscall, as it expects the pgoff + argument to be in units of 4,096 bytes irrespective of + page size */ *pui32MMapOffset = *pui32MMapOffset << (PAGE_SHIFT - 12); exit_unlock: @@ -517,6 +656,28 @@ exit_unlock: } +/*! + ******************************************************************************* + + @Function PVRMMapReleaseMMapData + + @Description + + Release mmap data. + + @input psPerProc : Per-process data. + @input hMHandle : Memory handle. + @input pbMUnmap : pointer to location for munmap flag. + @input pui32UserVAddr : pointer to location for user mode address of mapping. + @input pui32ByteSize : pointer to location for size of mapping. + + @Output pbMUnmap : points to flag that indicates whether an munmap is + required. + @output pui32UserVAddr : points to user mode address to munmap. + + @Return PVRSRV_ERROR : PVRSRV_OK, or error code. + + ******************************************************************************/ PVRSRV_ERROR PVRMMapReleaseMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc, #if defined (SUPPORT_SID_INTERFACE) @@ -562,7 +723,7 @@ PVRMMapReleaseMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc, goto exit_unlock; } - psOffsetStruct->ui32RefCount--; + PVRSRVOffsetStructDecRef(psOffsetStruct); *pbMUnmap = (IMG_BOOL)((psOffsetStruct->ui32RefCount == 0) && (psOffsetStruct->ui32UserVAddr != 0)); @@ -573,7 +734,7 @@ PVRMMapReleaseMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc, goto exit_unlock; } - + /* MMap data not found */ #if defined (SUPPORT_SID_INTERFACE) PVR_DPF((PVR_DBG_ERROR, "%s: Mapping data not found for handle %x (memory area %p)", __FUNCTION__, hMHandle, psLinuxMemArea)); #else @@ -602,7 +763,11 @@ FindOffsetStructByOffset(IMG_UINT32 ui32Offset, IMG_UINT32 ui32RealByteSize) if (ui32Offset == psOffsetStruct->ui32MMapOffset && ui32RealByteSize == psOffsetStruct->ui32RealByteSize && psOffsetStruct->ui32PID == ui32PID) { #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) - + /* + * If the offset is physical, make sure the thread IDs match, + * as different threads may be mapping different memory areas + * with the same offset. + */ if (!PFNIsPhysical(ui32Offset) || psOffsetStruct->ui32TID == ui32TID) #endif { @@ -627,7 +792,11 @@ FindOffsetStructByPID(LinuxMemArea *psLinuxMemArea, IMG_UINT32 ui32PID) } return NULL; } - +/* + * Map a memory area into user space. + * Note, the ui32ByteOffset is _not_ implicitly page aligned since + * LINUX_MEM_AREA_SUB_ALLOC LinuxMemAreas have no alignment constraints. + */ static IMG_BOOL DoMapToUser(LinuxMemArea *psLinuxMemArea, struct vm_area_struct* ps_vma, @@ -635,19 +804,33 @@ DoMapToUser(LinuxMemArea *psLinuxMemArea, { IMG_UINT32 ui32ByteSize; + if ((psLinuxMemArea->hBMHandle) && (ui32ByteOffset != 0)) + { + /* Partial mapping of sparse allocations should never happen */ + return IMG_FALSE; + } + if (psLinuxMemArea->eAreaType == LINUX_MEM_AREA_SUB_ALLOC) { - return DoMapToUser(LinuxMemAreaRoot(psLinuxMemArea), + return DoMapToUser(LinuxMemAreaRoot(psLinuxMemArea), /* PRQA S 3670 */ /* allow recursion */ ps_vma, psLinuxMemArea->uData.sSubAlloc.ui32ByteOffset + ui32ByteOffset); } - + /* + * Note that ui32ByteSize may be larger than the size of the memory + * area being mapped, as the former is a multiple of the page size. + */ ui32ByteSize = ps_vma->vm_end - ps_vma->vm_start; PVR_ASSERT(ADDR_TO_PAGE_OFFSET(ui32ByteSize) == 0); #if defined (__sparc__) - + /* + * For LINUX_MEM_AREA_EXTERNAL_KV, we don't know where the address range + * we are being asked to map has come from, that is, whether it is memory + * or I/O. For all architectures other than SPARC, there is no distinction. + * Since we don't currently support SPARC, we won't worry about it. + */ #error "SPARC not supported" #endif @@ -658,7 +841,13 @@ DoMapToUser(LinuxMemArea *psLinuxMemArea, PVR_ASSERT(LinuxMemAreaPhysIsContig(psLinuxMemArea)); PVR_ASSERT(LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32ByteOffset) == ps_vma->vm_pgoff); - + /* + * Since the memory is contiguous, we can map the whole range in one + * go . + */ + + PVR_ASSERT(psLinuxMemArea->hBMHandle == IMG_NULL); + result = IO_REMAP_PFN_RANGE(ps_vma, ps_vma->vm_start, ps_vma->vm_pgoff, ui32ByteSize, ps_vma->vm_page_prot); if(result == 0) @@ -671,27 +860,51 @@ DoMapToUser(LinuxMemArea *psLinuxMemArea, #endif { - + /* + * Memory may be non-contiguous, so we map the range page, + * by page. Since VM_PFNMAP mappings are assumed to be physically + * contiguous, we can't legally use REMAP_PFN_RANGE (that is, we + * could, but the resulting VMA may confuse other bits of the kernel + * that attempt to interpret it). + * The only alternative is to use VM_INSERT_PAGE, which requires + * finding the page structure corresponding to each page, or + * if mixed maps are supported (VM_MIXEDMAP), vm_insert_mixed. + */ IMG_UINT32 ulVMAPos; IMG_UINT32 ui32ByteEnd = ui32ByteOffset + ui32ByteSize; IMG_UINT32 ui32PA; + IMG_UINT32 ui32AdjustedPA = ui32ByteOffset; #if defined(PVR_MAKE_ALL_PFNS_SPECIAL) IMG_BOOL bMixedMap = IMG_FALSE; #endif - + /* First pass, validate the page frame numbers */ for(ui32PA = ui32ByteOffset; ui32PA < ui32ByteEnd; ui32PA += PAGE_SIZE) { - IMG_UINT32 pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32PA); + IMG_UINT32 pfn; + IMG_BOOL bMapPage = IMG_TRUE; - if (!pfn_valid(pfn)) - { + if (psLinuxMemArea->hBMHandle) + { + if (!BM_MapPageAtOffset(psLinuxMemArea->hBMHandle, ui32PA)) + { + bMapPage = IMG_FALSE; + } + } + + if (bMapPage) + { + pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32AdjustedPA); + if (!pfn_valid(pfn)) + { #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) - PVR_DPF((PVR_DBG_ERROR,"%s: Error - PFN invalid: 0x%x", __FUNCTION__, pfn)); - return IMG_FALSE; + PVR_DPF((PVR_DBG_ERROR,"%s: Error - PFN invalid: 0x%x", __FUNCTION__, pfn)); + return IMG_FALSE; #else - bMixedMap = IMG_TRUE; + bMixedMap = IMG_TRUE; #endif - } + } + ui32AdjustedPA += PAGE_SIZE; + } } #if defined(PVR_MAKE_ALL_PFNS_SPECIAL) @@ -700,43 +913,58 @@ DoMapToUser(LinuxMemArea *psLinuxMemArea, ps_vma->vm_flags |= VM_MIXEDMAP; } #endif - + /* Second pass, get the page structures and insert the pages */ ulVMAPos = ps_vma->vm_start; + ui32AdjustedPA = ui32ByteOffset; for(ui32PA = ui32ByteOffset; ui32PA < ui32ByteEnd; ui32PA += PAGE_SIZE) { IMG_UINT32 pfn; IMG_INT result; + IMG_BOOL bMapPage = IMG_TRUE; + + if (psLinuxMemArea->hBMHandle) + { + /* We have a sparse allocation, check if this page should be mapped */ + if (!BM_MapPageAtOffset(psLinuxMemArea->hBMHandle, ui32PA)) + { + bMapPage = IMG_FALSE; + } + } - pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32PA); + if (bMapPage) + { + pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ui32AdjustedPA); #if defined(PVR_MAKE_ALL_PFNS_SPECIAL) - if (bMixedMap) - { - result = vm_insert_mixed(ps_vma, ulVMAPos, pfn); - if(result != 0) - { - PVR_DPF((PVR_DBG_ERROR,"%s: Error - vm_insert_mixed failed (%d)", __FUNCTION__, result)); - return IMG_FALSE; - } - } - else + if (bMixedMap) + { + result = vm_insert_mixed(ps_vma, ulVMAPos, pfn); + if(result != 0) + { + PVR_DPF((PVR_DBG_ERROR,"%s: Error - vm_insert_mixed failed (%d)", __FUNCTION__, result)); + return IMG_FALSE; + } + } + else #endif - { - struct page *psPage; - - PVR_ASSERT(pfn_valid(pfn)); - - psPage = pfn_to_page(pfn); - - result = VM_INSERT_PAGE(ps_vma, ulVMAPos, psPage); - if(result != 0) - { - PVR_DPF((PVR_DBG_ERROR,"%s: Error - VM_INSERT_PAGE failed (%d)", __FUNCTION__, result)); - return IMG_FALSE; - } - } - ulVMAPos += PAGE_SIZE; - } + { + struct page *psPage; + + PVR_ASSERT(pfn_valid(pfn)); + + psPage = pfn_to_page(pfn); + + result = VM_INSERT_PAGE(ps_vma, ulVMAPos, psPage); + if(result != 0) + { + PVR_DPF((PVR_DBG_ERROR,"%s: Error - VM_INSERT_PAGE failed (%d)", __FUNCTION__, result)); + return IMG_FALSE; + } + } + ui32AdjustedPA += PAGE_SIZE; + } + ulVMAPos += PAGE_SIZE; + } } return IMG_TRUE; @@ -746,10 +974,11 @@ DoMapToUser(LinuxMemArea *psLinuxMemArea, static IMG_VOID MMapVOpenNoLock(struct vm_area_struct* ps_vma, PKV_OFFSET_STRUCT psOffsetStruct) { - PVR_ASSERT(psOffsetStruct != IMG_NULL) - psOffsetStruct->ui32Mapped++; + PVR_ASSERT(psOffsetStruct != IMG_NULL); PVR_ASSERT(!psOffsetStruct->bOnMMapList); + PVRSRVOffsetStructIncMapped(psOffsetStruct); + if (psOffsetStruct->ui32Mapped > 1) { PVR_DPF((PVR_DBG_WARNING, "%s: Offset structure 0x%p is being shared across processes (psOffsetStruct->ui32Mapped: %u)", __FUNCTION__, psOffsetStruct, psOffsetStruct->ui32Mapped)); @@ -769,6 +998,9 @@ MMapVOpenNoLock(struct vm_area_struct* ps_vma, PKV_OFFSET_STRUCT psOffsetStruct) } +/* + * Linux mmap open entry point. + */ static void MMapVOpen(struct vm_area_struct* ps_vma) { @@ -799,7 +1031,7 @@ MMapVCloseNoLock(struct vm_area_struct* ps_vma, PKV_OFFSET_STRUCT psOffsetStruct #endif PVR_ASSERT(!psOffsetStruct->bOnMMapList); - psOffsetStruct->ui32Mapped--; + PVRSRVOffsetStructDecMapped(psOffsetStruct); if (psOffsetStruct->ui32Mapped == 0) { if (psOffsetStruct->ui32RefCount != 0) @@ -813,6 +1045,9 @@ MMapVCloseNoLock(struct vm_area_struct* ps_vma, PKV_OFFSET_STRUCT psOffsetStruct ps_vma->vm_private_data = NULL; } +/* + * Linux mmap close entry point. + */ static void MMapVClose(struct vm_area_struct* ps_vma) { @@ -823,361 +1058,103 @@ MMapVClose(struct vm_area_struct* ps_vma) LinuxUnLockMutex(&g_sMMapMutex); } - -static struct vm_operations_struct MMapIOOps = -{ - .open=MMapVOpen, - .close=MMapVClose -}; - -/*****************************************************************************/ -/* "Smart" cached buffer support.. +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)) +/* + * This vma operation is used to read data from mmap regions. It is called + * by access_process_vm, which is called to handle PTRACE_PEEKDATA ptrace + * requests and reads from /proc/<pid>/mem. */ - -#include <linux/rmap.h> -#include <linux/pagemap.h> - -typedef struct { - struct mutex lock; /* mutex that protects the page list */ - struct list_head faulted; /* list of touched pages */ - int npages; /* number of pages in buffer */ - struct vm_area_struct *vma; /* vma of initial creator of buffer */ -} PVRMMapSmartCache; - -enum { - PG_touched = PG_private, - PG_written = PG_private_2 -}; - -static IMG_VOID PVRMMapUnmapInv(IMG_HANDLE hSmartCache, bool inv); - - -#ifndef DBG -#define DBG(fmt, ...) do {} while (0) -//#define DBG(fmt, ...) printk(KERN_INFO"[%s:%d] "fmt"\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) -#endif -#ifndef VERB -#define VERB(fmt, ...) do {} while (0) -//#define VERB(fmt, ...) printk(KERN_INFO"[%s:%d] "fmt"\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) -#endif -#define ERR(fmt, ...) printk(KERN_ERR"ERR: [%s:%d] "fmt"\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) - -static int -MMapVFault(struct vm_area_struct *vma, struct vm_fault *vmf) +static int MMapVAccess(struct vm_area_struct *ps_vma, unsigned long addr, + void *buf, int len, int write) { - PKV_OFFSET_STRUCT psOffsetStruct = vma->vm_private_data; - LinuxMemArea *psLinuxMemArea = psOffsetStruct->psLinuxMemArea; - PVRMMapSmartCache *smart = psLinuxMemArea->hSmartCache; - unsigned long offset, pfn; - struct page *page; - pgoff_t pgoff; - int ret = VM_FAULT_NOPAGE; - - if (!smart) - { - ERR("uhh oh, I'm not smart..\n"); - return VM_FAULT_SIGBUS; - } - - /* We don't use vmf->pgoff since that has the fake offset */ - pgoff = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; - offset = pgoff << PAGE_SHIFT; - if (offset >= psOffsetStruct->psLinuxMemArea->ui32ByteSize) - { - ERR("%p: offset too big: %lu vs %u, %p", smart, offset, - psOffsetStruct->psLinuxMemArea->ui32ByteSize, - psOffsetStruct->psLinuxMemArea); - return VM_FAULT_SIGBUS; - } - - pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, offset); - page = pfn_to_page(pfn); - if (!page) - { - ERR("%p: can't find page: %lu, %p", smart, offset, psLinuxMemArea); - return VM_FAULT_SIGBUS; - } - + PKV_OFFSET_STRUCT psOffsetStruct; + LinuxMemArea *psLinuxMemArea; + unsigned long ulOffset; + int iRetVal = -EINVAL; + IMG_VOID *pvKernelAddr; - /* *** BEGIN CRITICAL SECTION ********************************************/ - mutex_lock(&smart->lock); + LinuxLockMutex(&g_sMMapMutex); - /* if we already know of this page the we are done */ - if (test_and_set_bit(PG_touched, &page->flags)) - { - VERB("%p: (already touched) get_page(%p) (idx=%08lx, flg=%08x, cnt=%d)", - smart, page, page->index, vmf->flags, atomic_read(&page->_count)); - goto unlock; - } + psOffsetStruct = (PKV_OFFSET_STRUCT)ps_vma->vm_private_data; + psLinuxMemArea = psOffsetStruct->psLinuxMemArea; + ulOffset = addr - ps_vma->vm_start; - page->index = pgoff + vma->vm_pgoff; + if (ulOffset+len > psLinuxMemArea->ui32ByteSize) + /* Out of range. We shouldn't get here, because the kernel will do + the necessary checks before calling access_process_vm. */ + goto exit_unlock; - VERB("%p: get_page(%p) (idx=%08lx, flg=%08x, cnt=%d)", - smart, page, page->index, vmf->flags, atomic_read(&page->_count)); + pvKernelAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea); - if (vma->vm_file) + if (pvKernelAddr) { - page->mapping = vma->vm_file->f_mapping; + memcpy(buf, pvKernelAddr+ulOffset, len); + iRetVal = len; } else { - ERR("%p: no mapping available\n", smart); - } + IMG_UINT32 pfn, ui32OffsetInPage; + struct page *page; - BUG_ON(!page->mapping); + pfn = LinuxMemAreaToCpuPFN(psLinuxMemArea, ulOffset); - vmf->page = page; + if (!pfn_valid(pfn)) + goto exit_unlock; - get_page(page); - ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); - if (ret) - { - ERR("%p: error inserting page: %d", smart, ret); - goto unlock; - } - ret = VM_FAULT_NOPAGE; - - /* Add the page to the list of pages that have been touched - */ - list_add_tail(&page->lru, &smart->faulted); - -unlock: - mutex_unlock(&smart->lock); - /* *** END CRITICAL SECTION **********************************************/ - - return ret; -} - -static int -MMapVMkWrite(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - PKV_OFFSET_STRUCT psOffsetStruct = (PKV_OFFSET_STRUCT)vma->vm_private_data; - PVRMMapSmartCache *smart = psOffsetStruct->psLinuxMemArea->hSmartCache; - struct page *page = vmf->page; - - VERB("%p: page=%p", smart, page); - - /* *** BEGIN CRITICAL SECTION ********************************************/ - mutex_lock(&smart->lock); - - /* We want the page to remain locked from ->page_mkwrite until - * the PTE is marked dirty to avoid page_mkclean() being called - * before the PTE is updated, which would leave the page ignored. - * - * Do this by locking the page here and informing the caller - * about it with VM_FAULT_LOCKED. - */ - lock_page(page); + page = pfn_to_page(pfn); + ui32OffsetInPage = ADDR_TO_PAGE_OFFSET(ulOffset); - set_bit(PG_written, &page->flags); + if (ui32OffsetInPage+len > PAGE_SIZE) + /* The region crosses a page boundary */ + goto exit_unlock; - mutex_unlock(&smart->lock); - /* *** END CRITICAL SECTION **********************************************/ + pvKernelAddr = kmap(page); + memcpy(buf, pvKernelAddr+ui32OffsetInPage, len); + kunmap(page); - return VM_FAULT_LOCKED; -} - -static void -MMapVClose2(struct vm_area_struct* vma) -{ - PKV_OFFSET_STRUCT psOffsetStruct = (PKV_OFFSET_STRUCT)vma->vm_private_data; - PVRMMapSmartCache *smart = psOffsetStruct->psLinuxMemArea->hSmartCache; - DBG("%p", smart); - PVRMMapUnmapInv(smart, false); - MMapVClose(vma); -} - -static struct vm_operations_struct MMapSmartOps = { - .open=MMapVOpen, - .close=MMapVClose2, - .fault=MMapVFault, - .page_mkwrite=MMapVMkWrite, -}; - -static int -MMapSetPageDirty(struct page *page) -{ - if (!PageDirty(page)) - SetPageDirty(page); - return 0; -} - -static const struct address_space_operations MMapSmartAOps = { - .set_page_dirty = MMapSetPageDirty, -}; - -/* prepare buffer transition CPU -> GPU */ -IMG_VOID -PVRMMapPrepareCpuToGpu(IMG_HANDLE hSmartCache) -{ -#if 0 - PVRMMapSmartCache *smart = hSmartCache; - struct page *page; - int cnt = 0; - - /* hopefully this is the common-path.. */ - if (list_empty(&smart->faulted)) - { - return; + iRetVal = len; } - /* *** BEGIN CRITICAL SECTION ********************************************/ - mutex_lock(&smart->lock); - - list_for_each_entry(page, &smart->faulted, lru) { - if (test_and_clear_bit(PG_written, &page->flags)) - { - void *va = (void *)(smart->vma->vm_start + - ((page->index - smart->vma->vm_pgoff) << PAGE_SHIFT)); - unsigned long pa = page_to_phys(page); - - lock_page(page); - page_mkclean(page); - dmac_clean_range(va, va + PAGE_SIZE); - outer_clean_range(pa, pa + PAGE_SIZE); - unlock_page(page); - - cnt++; - } - } - - mutex_unlock(&smart->lock); - /* *** END CRITICAL SECTION **********************************************/ - - DBG("%p: cleaned %d (of %d)", smart, cnt, smart->npages); -#else - PVRMMapUnmapInv(hSmartCache, true); -#endif -} -/* prepare buffer transition GPU -> CPU */ -IMG_VOID -PVRMMapPrepareGpuToCpu(IMG_HANDLE hSmartCache) -{ - PVRMMapUnmapInv(hSmartCache, true); +exit_unlock: + LinuxUnLockMutex(&g_sMMapMutex); + return iRetVal; } +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) */ -/* remove faulted pages from user's vm, and optionally invalidate.. */ -static IMG_VOID -PVRMMapUnmapInv(IMG_HANDLE hSmartCache, bool inv) +static struct vm_operations_struct MMapIOOps = { - PVRMMapSmartCache *smart = hSmartCache; - struct page *page, *next; - pgoff_t min = ULONG_MAX, max = 0; - struct address_space *mapping = NULL; - int cnt = 0; - - /* hopefully this is the common-path.. */ - if (list_empty(&smart->faulted)) - { - return; - } - - VERB("%p", smart); - - /* *** BEGIN CRITICAL SECTION ********************************************/ - mutex_lock(&smart->lock); - - list_for_each_entry(page, &smart->faulted, lru) { - - if (inv) - { - void *va = (void *)(smart->vma->vm_start + - ((page->index - smart->vma->vm_pgoff) << PAGE_SHIFT)); - -#if 0 - dmac_inv_range(va, va + PAGE_SIZE); -#else - dmac_flush_range(va, va + PAGE_SIZE); -#endif - } - - clear_bit(PG_touched, &page->flags); - clear_bit(PG_written, &page->flags); - - min = min(min, page->index); - max = max(max, page->index); - - mapping = page->mapping; - - cnt++; - } - - /* clear out the mapping that we setup.. do this before - * invalidating to avoid a window where the cache is - * clean, but access to it is not protected by a fault - */ - if (mapping) - { - VERB("unmap_mapping_range: max=%08lx, min=%08lx", max, min); - unmap_mapping_range(mapping, min << PAGE_SHIFT, - (max - min + 1) << PAGE_SHIFT, 1); - } - - list_for_each_entry_safe(page, next, &smart->faulted, lru) { - - if (inv) - { - unsigned long pa = page_to_phys(page); - -#if 0 - outer_inv_range(pa, pa + PAGE_SIZE); -#else - outer_flush_range(pa, pa + PAGE_SIZE); + .open=MMapVOpen, + .close=MMapVClose, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)) + .access=MMapVAccess, #endif - } - - VERB("%p: put_page(%p) (idx=%08lx, cnt=%d)", - smart, page, page->index, atomic_read(&page->_count)); - - page->index = 0; - page->mapping = NULL; - - put_page(page); - - list_del(&page->lru); - } - - mutex_unlock(&smart->lock); - /* *** END CRITICAL SECTION **********************************************/ - - DBG("%p: put %d (of %d)", smart, cnt, smart->npages); -} - -/* setup smart cache buffer */ -IMG_HANDLE -PVRMMapAllocateSmart(PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo) -{ - PVRMMapSmartCache *smart = kzalloc(sizeof(*smart), GFP_KERNEL); - - DBG("%p", smart); +}; - mutex_init(&smart->lock); - INIT_LIST_HEAD(&smart->faulted); - return smart; -} +/*! + ******************************************************************************* -IMG_VOID -PVRMMapFreeSmart(IMG_HANDLE hSmartCache) -{ - PVRMMapSmartCache *smart = hSmartCache; + @Function PVRMMap - DBG("%p", smart); + @Description - PVRMMapUnmapInv(smart, false); + Driver mmap entry point. - mutex_destroy(&smart->lock); + @input pFile : unused. + @input ps_vma : pointer to linux memory area descriptor. - kfree(smart); -} -/*****************************************************************************/ + @Return 0, or Linux error code. + ******************************************************************************/ int PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma) { - IMG_UINT32 ui32ByteSize; + LinuxMemArea *psFlushMemArea = IMG_NULL; PKV_OFFSET_STRUCT psOffsetStruct; + IMG_UINT32 ui32ByteSize; + IMG_VOID *pvBase = IMG_NULL; int iRetVal = 0; + IMG_UINT32 ui32ByteOffset = 0; /* Keep compiler happy */ PVR_UNREFERENCED_PARAMETER(pFile); @@ -1192,17 +1169,23 @@ PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma) ui32ByteSize, ui32ByteSize)); psOffsetStruct = FindOffsetStructByOffset(ps_vma->vm_pgoff, ui32ByteSize); + if (psOffsetStruct == IMG_NULL) { #if defined(SUPPORT_DRI_DRM) LinuxUnLockMutex(&g_sMMapMutex); #if !defined(SUPPORT_DRI_DRM_EXT) - + /* Pass unknown requests onto the DRM module */ return drm_mmap(pFile, ps_vma); #else - - return -ENOENT; + /* + * Indicate to caller that the request is not for us. + * Do not return this error elsewhere in this function, as the + * caller may use it as a clue as to whether the mmap request + * should be passed on to another component (e.g. drm_mmap). + */ + return -ENOENT; #endif #else PVR_UNREFERENCED_PARAMETER(pFile); @@ -1214,10 +1197,11 @@ PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma) #endif goto unlock_and_return; } + list_del(&psOffsetStruct->sMMapItem); psOffsetStruct->bOnMMapList = IMG_FALSE; - + /* Only support shared writeable mappings */ if (((ps_vma->vm_flags & VM_WRITE) != 0) && ((ps_vma->vm_flags & VM_SHARED) == 0)) { @@ -1232,10 +1216,13 @@ PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma) ps_vma->vm_flags |= VM_RESERVED; ps_vma->vm_flags |= VM_IO; - + /* + * Disable mremap because our nopage handler assumes all + * page requests have already been validated. + */ ps_vma->vm_flags |= VM_DONTEXPAND; - + /* Don't allow mapping to be inherited across a process fork */ ps_vma->vm_flags |= VM_DONTCOPY; ps_vma->vm_private_data = (void *)psOffsetStruct; @@ -1243,7 +1230,7 @@ PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma) switch(psOffsetStruct->psLinuxMemArea->ui32AreaFlags & PVRSRV_HAP_CACHETYPE_MASK) { case PVRSRV_HAP_CACHED: - case PVRSRV_HAP_SMART: + /* This is the default, do nothing. */ break; case PVRSRV_HAP_WRITECOMBINE: ps_vma->vm_page_prot = PGPROT_WC(ps_vma->vm_page_prot); @@ -1254,76 +1241,58 @@ PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma) default: PVR_DPF((PVR_DBG_ERROR, "%s: unknown cache type", __FUNCTION__)); iRetVal = -EINVAL; - goto unlock_and_return; + goto unlock_and_return; } - if (psOffsetStruct->psLinuxMemArea->hSmartCache) - { - PVRMMapSmartCache *smart = psOffsetStruct->psLinuxMemArea->hSmartCache; - DBG("using smart cache, smart=%p, psLinuxMemArea=%p (%d, %d)", - psOffsetStruct->psLinuxMemArea->hSmartCache, - psOffsetStruct->psLinuxMemArea, - psOffsetStruct->ui32RealByteSize, - psOffsetStruct->psLinuxMemArea->ui32ByteSize); - smart->npages = (psOffsetStruct->ui32RealByteSize + PAGE_SIZE - 1) / PAGE_SIZE; - /* abuse pgoff a bit less.. in unmap_mapping_range() it is assumed - * that the offset is something sane, and I think it probably - * shouldn't intersect with other page->index's.. otherwise I - * suspect the prio_tree stuff won't work out.. - */ - ps_vma->vm_pgoff = ps_vma->vm_start >> PAGE_SHIFT; - smart->vma = ps_vma; - ps_vma->vm_ops = &MMapSmartOps; - pFile->f_mapping->a_ops = &MMapSmartAOps; - - ps_vma->vm_flags |= VM_MIXEDMAP; - } - else + /* Install open and close handlers for ref-counting */ + ps_vma->vm_ops = &MMapIOOps; + + if(!DoMapToUser(psOffsetStruct->psLinuxMemArea, ps_vma, 0)) { - ps_vma->vm_ops = &MMapIOOps; - if(!DoMapToUser(psOffsetStruct->psLinuxMemArea, ps_vma, 0)) - { - iRetVal = -EAGAIN; - goto unlock_and_return; - } + iRetVal = -EAGAIN; + goto unlock_and_return; } PVR_ASSERT(psOffsetStruct->ui32UserVAddr == 0); psOffsetStruct->ui32UserVAddr = ps_vma->vm_start; - + /* Compute the flush region (if necessary) inside the mmap mutex */ if(psOffsetStruct->psLinuxMemArea->bNeedsCacheInvalidate) { - IMG_UINT32 ui32RealByteSize, ui32ByteOffset; - IMG_VOID *pvBase; + IMG_UINT32 ui32DummyByteSize; DetermineUsersSizeAndByteOffset(psOffsetStruct->psLinuxMemArea, - &ui32RealByteSize, + &ui32DummyByteSize, &ui32ByteOffset); - ui32RealByteSize = psOffsetStruct->psLinuxMemArea->ui32ByteSize; pvBase = (IMG_VOID *)ps_vma->vm_start + ui32ByteOffset; + psFlushMemArea = psOffsetStruct->psLinuxMemArea; - OSInvalidateCPUCacheRangeKM(psOffsetStruct->psLinuxMemArea, - pvBase, ui32RealByteSize); psOffsetStruct->psLinuxMemArea->bNeedsCacheInvalidate = IMG_FALSE; } - + + /* Call the open routine to increment the usage count */ MMapVOpenNoLock(ps_vma, ps_vma->vm_private_data); PVR_DPF((PVR_DBG_MESSAGE, "%s: Mapped area at offset 0x%08lx\n", __FUNCTION__, ps_vma->vm_pgoff)); - + unlock_and_return: if (iRetVal != 0 && psOffsetStruct != IMG_NULL) { - DestroyOffsetStruct(psOffsetStruct); + DestroyOffsetStruct(psOffsetStruct); } LinuxUnLockMutex(&g_sMMapMutex); - + + if(psFlushMemArea) + { + OSInvalidateCPUCacheRangeKM(psFlushMemArea, ui32ByteOffset, pvBase, + psFlushMemArea->ui32ByteSize); + } + return iRetVal; } @@ -1372,6 +1341,11 @@ PVRMMapExt(struct file* pFile, struct vm_area_struct* ps_vma) IMG_UINT32 ui32ByteSize; PKV_OFFSET_STRUCT psOffsetStruct; + /* for cache maintenance: */ + LinuxMemArea *psFlushMemArea = IMG_NULL; + IMG_VOID *pvBase = IMG_NULL; + IMG_UINT32 ui32ByteOffset = 0; /* Keep compiler happy */ + PVR_UNREFERENCED_PARAMETER(pFile); LinuxLockMutex(&g_sMMapMutex); @@ -1390,16 +1364,44 @@ PVRMMapExt(struct file* pFile, struct vm_area_struct* ps_vma) list_del(&psOffsetStruct->sMMapItem); psOffsetStruct->bOnMMapList = IMG_FALSE; + if(!DoMapToUser(psOffsetStruct->psLinuxMemArea, ps_vma, 0)) + { + goto unlock_and_return; + } + PVR_ASSERT(psOffsetStruct->ui32UserVAddr == 0); psOffsetStruct->ui32UserVAddr = ps_vma->vm_start; obj->driver_private = psOffsetStruct->psLinuxMemArea; + + /* Compute the flush region (if necessary) inside the mmap mutex */ + if(psOffsetStruct->psLinuxMemArea->bNeedsCacheInvalidate) + { + IMG_UINT32 ui32DummyByteSize; + + DetermineUsersSizeAndByteOffset(psOffsetStruct->psLinuxMemArea, + &ui32DummyByteSize, + &ui32ByteOffset); + + pvBase = (IMG_VOID *)ps_vma->vm_start + ui32ByteOffset; + psFlushMemArea = psOffsetStruct->psLinuxMemArea; + + psOffsetStruct->psLinuxMemArea->bNeedsCacheInvalidate = IMG_FALSE; + } + + /* Call the open routine to increment the usage count */ MMapVOpenNoLock(ps_vma, psOffsetStruct); unlock_and_return: LinuxUnLockMutex(&g_sMMapMutex); + + if(psFlushMemArea) + { + OSInvalidateCPUCacheRangeKM(psFlushMemArea, ui32ByteOffset, pvBase, + psFlushMemArea->ui32ByteSize); + } } static struct omap_gem_vm_ops gem_ops = { @@ -1411,6 +1413,13 @@ static struct omap_gem_vm_ops gem_ops = { #if defined(DEBUG_LINUX_MMAP_AREAS) +/* + * Lock MMap regions list (called on page start/stop while reading /proc/mmap) + + * sfile : seq_file that handles /proc file + * start : TRUE if it's start, FALSE if it's stop + * +*/ static void ProcSeqStartstopMMapRegistations(struct seq_file *sfile,IMG_BOOL start) { if(start) @@ -1424,6 +1433,16 @@ static void ProcSeqStartstopMMapRegistations(struct seq_file *sfile,IMG_BOOL sta } +/* + * Convert offset (index from KVOffsetTable) to element + * (called when reading /proc/mmap file) + + * sfile : seq_file that handles /proc file + * off : index into the KVOffsetTable from which to print + * + * returns void* : Pointer to element that will be dumped + * +*/ static void* ProcSeqOff2ElementMMapRegistrations(struct seq_file *sfile, loff_t off) { LinuxMemArea *psLinuxMemArea; @@ -1449,12 +1468,28 @@ static void* ProcSeqOff2ElementMMapRegistrations(struct seq_file *sfile, loff_t return (void*)0; } +/* + * Gets next MMap element to show. (called when reading /proc/mmap file) + + * sfile : seq_file that handles /proc file + * el : actual element + * off : index into the KVOffsetTable from which to print + * + * returns void* : Pointer to element to show (0 ends iteration) +*/ static void* ProcSeqNextMMapRegistrations(struct seq_file *sfile,void* el,loff_t off) { return ProcSeqOff2ElementMMapRegistrations(sfile,off); } +/* + * Show MMap element (called when reading /proc/mmap file) + + * sfile : seq_file that handles /proc file + * el : actual element + * +*/ static void ProcSeqShowMMapRegistrations(struct seq_file *sfile, void *el) { KV_OFFSET_STRUCT *psOffsetStruct = (KV_OFFSET_STRUCT*)el; @@ -1528,6 +1563,20 @@ static void ProcSeqShowMMapRegistrations(struct seq_file *sfile, void *el) #endif +/*! + ******************************************************************************* + + @Function PVRMMapRegisterArea + + @Description + + Register a memory area with the mmap code. + + @input psLinuxMemArea : pointer to memory area. + + @Return PVRSRV_OK, or PVRSRV_ERROR. + + ******************************************************************************/ PVRSRV_ERROR PVRMMapRegisterArea(LinuxMemArea *psLinuxMemArea) { @@ -1546,7 +1595,7 @@ PVRMMapRegisterArea(LinuxMemArea *psLinuxMemArea) PVR_ASSERT(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC || LinuxMemAreaRoot(psLinuxMemArea)->eAreaType != LINUX_MEM_AREA_SUB_ALLOC); - + /* Check this mem area hasn't already been registered */ if(psLinuxMemArea->bMMapRegistered) { PVR_DPF((PVR_DBG_ERROR, "%s: psLinuxMemArea 0x%p is already registered", @@ -1561,7 +1610,11 @@ PVRMMapRegisterArea(LinuxMemArea *psLinuxMemArea) #if defined(DEBUG_LINUX_MMAP_AREAS) g_ui32RegisteredAreas++; - + /* + * Sub memory areas are excluded from g_ui32TotalByteSize so that we + * don't count memory twice, once for the parent and again for sub + * allocationis. + */ if (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC) { g_ui32TotalByteSize += psLinuxMemArea->ui32ByteSize; @@ -1577,6 +1630,20 @@ exit_unlock: } +/*! + ******************************************************************************* + + @Function PVRMMapRemoveRegisterArea + + @Description + + Unregister a memory area with the mmap code. + + @input psLinuxMemArea : pointer to memory area. + + @Return PVRSRV_OK, or PVRSRV_ERROR. + + ******************************************************************************/ PVRSRV_ERROR PVRMMapRemoveRegisteredArea(LinuxMemArea *psLinuxMemArea) { @@ -1592,12 +1659,19 @@ PVRMMapRemoveRegisteredArea(LinuxMemArea *psLinuxMemArea) if (psOffsetStruct->ui32Mapped != 0) { PVR_DPF((PVR_DBG_ERROR, "%s: psOffsetStruct 0x%p for memory area 0x0x%p is still mapped; psOffsetStruct->ui32Mapped %u", __FUNCTION__, psOffsetStruct, psLinuxMemArea, psOffsetStruct->ui32Mapped)); + dump_stack(); + PVRSRVDumpRefCountCCB(); eError = PVRSRV_ERROR_STILL_MAPPED; goto exit_unlock; } else { - + /* + * An offset structure is created when a call is made to get + * the mmap data for a physical mapping. If the data is never + * used for mmap, we will be left with an umapped offset + * structure. + */ PVR_DPF((PVR_DBG_WARNING, "%s: psOffsetStruct 0x%p was never mapped", __FUNCTION__, psOffsetStruct)); } @@ -1626,6 +1700,20 @@ exit_unlock: } +/*! + ******************************************************************************* + + @Function LinuxMMapPerProcessConnect + + @Description + + Per-process mmap initialisation code. + + @input psEnvPerProc : pointer to OS specific per-process data. + + @Return PVRSRV_OK, or PVRSRV_ERROR. + + ******************************************************************************/ PVRSRV_ERROR LinuxMMapPerProcessConnect(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc) { @@ -1634,6 +1722,18 @@ LinuxMMapPerProcessConnect(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc) return PVRSRV_OK; } +/*! + ******************************************************************************* + + @Function LinuxMMapPerProcessDisconnect + + @Description + + Per-process mmap deinitialisation code. + + @input psEnvPerProc : pointer to OS specific per-process data. + + ******************************************************************************/ IMG_VOID LinuxMMapPerProcessDisconnect(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc) { @@ -1665,6 +1765,20 @@ LinuxMMapPerProcessDisconnect(PVRSRV_ENV_PER_PROCESS_DATA *psEnvPerProc) } +/*! + ******************************************************************************* + + @Function LinuxMMapPerProcessHandleOptions + + @Description + + Set secure handle options required by mmap code. + + @input psHandleBase : pointer to handle base. + + @Return PVRSRV_OK, or PVRSRV_ERROR. + + ******************************************************************************/ PVRSRV_ERROR LinuxMMapPerProcessHandleOptions(PVRSRV_HANDLE_BASE *psHandleBase) { PVRSRV_ERROR eError; @@ -1680,6 +1794,16 @@ PVRSRV_ERROR LinuxMMapPerProcessHandleOptions(PVRSRV_HANDLE_BASE *psHandleBase) } +/*! + ******************************************************************************* + + @Function PVRMMapInit + + @Description + + MMap initialisation code + + ******************************************************************************/ IMG_VOID PVRMMapInit(IMG_VOID) { @@ -1699,7 +1823,7 @@ PVRMMapInit(IMG_VOID) ProcSeqOff2ElementMMapRegistrations, ProcSeqStartstopMMapRegistations ); -#endif +#endif /* defined(DEBUG_LINUX_MMAP_AREAS) */ return; error: @@ -1708,6 +1832,16 @@ error: } +/*! + ******************************************************************************* + + @Function PVRMMapCleanup + + @Description + + Mmap deinitialisation code + + ******************************************************************************/ IMG_VOID PVRMMapCleanup(IMG_VOID) { @@ -1736,7 +1870,7 @@ PVRMMapCleanup(IMG_VOID) #if defined(DEBUG_LINUX_MMAP_AREAS) RemoveProcEntrySeq(g_ProcMMap); -#endif +#endif /* defined(DEBUG_LINUX_MMAP_AREAS) */ if(g_psMemmapCache) { diff --git a/sgx/services4/srvkm/env/linux/mmap.h b/sgx/services4/srvkm/env/linux/mmap.h index 07d521b..bca8358 100644 --- a/sgx/services4/srvkm/env/linux/mmap.h +++ b/sgx/services4/srvkm/env/linux/mmap.h @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Linux mmap interface declaration +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #if !defined(__MMAP_H__) #define __MMAP_H__ @@ -31,68 +47,146 @@ #include <linux/list.h> #if defined(VM_MIXEDMAP) +/* + * Mixed maps allow us to avoid using raw PFN mappings (VM_PFNMAP) for + * pages without pages structures ("struct page"), giving us more + * freedom in choosing the mmap offset for mappings. Mixed maps also + * allow both the mmap and the wrap code to be simplified somewhat. + */ #define PVR_MAKE_ALL_PFNS_SPECIAL #endif #include "perproc.h" #include "mm.h" +/* + * This structure represents the relationship between an mmap2 file + * offset and a LinuxMemArea for a given process. + */ typedef struct KV_OFFSET_STRUCT_TAG { - + /* + * Mapping count. Incremented when the mapping is created, and + * if the mapping is inherited across a process fork. + */ IMG_UINT32 ui32Mapped; - + /* + * Offset to be passed to mmap2 to map the associated memory area + * into user space. The offset may represent the page frame number + * of the first page in the area (if the area is physically + * contiguous), or it may represent the secure handle associated + * with the area. + */ IMG_UINT32 ui32MMapOffset; IMG_UINT32 ui32RealByteSize; - + /* Memory area associated with this offset structure */ LinuxMemArea *psLinuxMemArea; #if !defined(PVR_MAKE_ALL_PFNS_SPECIAL) - + /* ID of the thread that owns this structure */ IMG_UINT32 ui32TID; #endif - + /* ID of the process that owns this structure */ IMG_UINT32 ui32PID; - + /* + * For offsets that represent actual page frame numbers, this structure + * is temporarily put on a list so that it can be found from the + * driver mmap entry point. This flag indicates the structure is + * on the list. + */ IMG_BOOL bOnMMapList; - + /* Reference count for this structure */ IMG_UINT32 ui32RefCount; - + /* + * User mode address of start of mapping. This is not necessarily the + * first user mode address of the memory area. + */ IMG_UINT32 ui32UserVAddr; - + /* Extra entries to support proc filesystem debug info */ #if defined(DEBUG_LINUX_MMAP_AREAS) const IMG_CHAR *pszName; #endif - + /* List entry field for MMap list */ struct list_head sMMapItem; - + /* List entry field for per-memory area list */ struct list_head sAreaItem; }KV_OFFSET_STRUCT, *PKV_OFFSET_STRUCT; +/*! + ******************************************************************************* + * @Function Mmap initialisation code + ******************************************************************************/ IMG_VOID PVRMMapInit(IMG_VOID); +/*! + ******************************************************************************* + * @Function Mmap de-initialisation code + ******************************************************************************/ IMG_VOID PVRMMapCleanup(IMG_VOID); +/*! + ******************************************************************************* + * @Function Registers a memory area with the mmap code + * + * @Input psLinuxMemArea + * + * @Return PVRSRV_ERROR status + ******************************************************************************/ PVRSRV_ERROR PVRMMapRegisterArea(LinuxMemArea *psLinuxMemArea); +/*! + ******************************************************************************* + * @Function Unregisters a memory area from the mmap code + * + * @Input psLinuxMemArea + * + * @Return PVRSRV_ERROR status + ******************************************************************************/ PVRSRV_ERROR PVRMMapRemoveRegisteredArea(LinuxMemArea *psLinuxMemArea); +/*! + ****************************************************************************** + * @Function When a userspace services client, requests to map a memory + * area to userspace, this function validates the request and + * returns the details that the client must use when calling mmap(2). + * + * @Input psPerProc Per process data. + * @Input hMHandle Handle associated with the memory to map. + * This is a (secure) handle to the OS specific + * memory handle structure (hOSMemHandle), or + * a handle to a structure that contains the + * memory handle. + * @Output pui32MMapOffset The page aligned offset that the client must + * pass to the mmap2 system call. + * @Output pui32ByteOffset The real mapping that will be created for the + * services client may have a different + * size/alignment from it request. This offset + * is returned to the client and should be added + * to virtual address returned from mmap2 to get + * the first address corresponding to its request. + * @Output pui32RealByteOffset The size that the mapping will really be, + * that the client must also pass to mmap/munmap. + * + * @Output pui32UserVAddr Pointer to returned user mode address of + * mapping. + * @Return PVRSRV_ERROR + ******************************************************************************/ PVRSRV_ERROR PVRMMapOSMemHandleToMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc, #if defined (SUPPORT_SID_INTERFACE) IMG_SID hMHandle, @@ -104,6 +198,21 @@ PVRSRV_ERROR PVRMMapOSMemHandleToMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc, IMG_UINT32 *pui32RealByteSize, IMG_UINT32 *pui32UserVAddr); +/*! + ******************************************************************************* + + @Function Release mmap data. + + @Input psPerProc Per-process data. + @Input hMHandle Memory handle. + + @Output pbMUnmap Flag that indicates whether an munmap is + required. + @Output pui32RealByteSize Location for size of mapping. + @Output pui32UserVAddr User mode address to munmap. + + @Return PVRSRV_ERROR + ******************************************************************************/ PVRSRV_ERROR PVRMMapReleaseMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc, #if defined (SUPPORT_SID_INTERFACE) @@ -115,12 +224,18 @@ PVRMMapReleaseMMapData(PVRSRV_PER_PROCESS_DATA *psPerProc, IMG_UINT32 *pui32RealByteSize, IMG_UINT32 *pui32UserVAddr); +/*! + ******************************************************************************* + * @Function driver mmap entry point + * + * @Input pFile : user file structure + * + * @Input ps_vma : vm area structure + * + * @Return 0 for success, -errno for failure. + ******************************************************************************/ int PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma); -IMG_VOID PVRMMapPrepareCpuToGpu(IMG_HANDLE hSmartCache); -IMG_VOID PVRMMapPrepareGpuToCpu(IMG_HANDLE hSmartCache); -IMG_HANDLE PVRMMapAllocateSmart(PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo); -IMG_VOID PVRMMapFreeSmart(IMG_HANDLE hSmartCache); -#endif +#endif /* __MMAP_H__ */ diff --git a/sgx/services4/srvkm/env/linux/module.c b/sgx/services4/srvkm/env/linux/module.c index cda7c21..fe31e41 100644 --- a/sgx/services4/srvkm/env/linux/module.c +++ b/sgx/services4/srvkm/env/linux/module.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Linux module setup +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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 <linux/version.h> @@ -35,13 +51,24 @@ #if defined(SUPPORT_DRI_DRM) && !defined(SUPPORT_DRI_DRM_EXTERNAL) #define PVR_MOD_STATIC #else + /* + * For LDM drivers, define PVR_LDM_MODULE to indicate generic LDM + * support is required, besides indicating the exact support + * required (e.g. platform, or PCI device). + */ #if defined(LDM_PLATFORM) #define PVR_LDM_PLATFORM_MODULE + #define PVR_LDM_DEVICE_CLASS #define PVR_LDM_MODULE #else #if defined(LDM_PCI) + #define PVR_LDM_DEVICE_CLASS #define PVR_LDM_PCI_MODULE #define PVR_LDM_MODULE + #else + #if defined(SYS_SHARES_WITH_3PKM) + #define PVR_LDM_DEVICE_CLASS + #endif #endif #endif #if defined(SUPPORT_DRI_DRM_EXTERNAL) @@ -72,11 +99,15 @@ #if defined(PVR_LDM_PLATFORM_MODULE) #include <linux/platform_device.h> -#endif +#endif /* PVR_LDM_PLATFORM_MODULE */ #if defined(PVR_LDM_PCI_MODULE) #include <linux/pci.h> -#endif +#endif /* PVR_LDM_PCI_MODULE */ + +#if defined(PVR_LDM_DEVICE_CLASS) +#include <linux/device.h> +#endif /* PVR_LDM_DEVICE_CLASS */ #if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL) #include <asm/uaccess.h> @@ -102,38 +133,69 @@ #include "private_data.h" #include "lock.h" #include "linkage.h" +#include "buffer_manager.h" #if defined(SUPPORT_DRI_DRM) #include "pvr_drm.h" #endif +/* + * DRVNAME is the name we use to register our driver. + * DEVNAME is the name we use to register actual device nodes. + */ #if defined(SUPPORT_DRI_DRM_EXTERNAL) #define DRVNAME PVRSRV_MODNAME #define DEVNAME PVRSRV_MODNAME #else -#define DRVNAME PVRSRV_MODNAME +#if defined(PVR_LDM_MODULE) +#define DRVNAME PVR_LDM_DRIVER_REGISTRATION_NAME +#endif #define DEVNAME PVRSRV_MODNAME MODULE_SUPPORTED_DEVICE(DEVNAME); #endif +/* + * This is all module configuration stuff required by the linux kernel. + */ #if defined(PVRSRV_NEED_PVR_DPF) #include <linux/moduleparam.h> extern IMG_UINT32 gPVRDebugLevel; module_param(gPVRDebugLevel, uint, 0644); MODULE_PARM_DESC(gPVRDebugLevel, "Sets the level of debug output (default 0x7)"); -#endif +#endif /* defined(PVRSRV_NEED_PVR_DPF) */ - +#if defined(CONFIG_ION_OMAP) +#include <linux/ion.h> +#include <linux/omap_ion.h> +extern struct ion_device *omap_ion_device; +struct ion_client *gpsIONClient; +EXPORT_SYMBOL(gpsIONClient); +#endif /* defined(CONFIG_ION_OMAP) */ + +/* PRQA S 3207 2 */ /* ignore 'not used' warning */ EXPORT_SYMBOL(PVRGetDisplayClassJTable); EXPORT_SYMBOL(PVRGetBufferClassJTable); #if defined(PVR_LDM_MODULE) +/* + * Device class used for /sys entries (and udev device node creation) + */ static struct class *psPvrClass; #endif #if defined(SUPPORT_DRI_DRM_EXTERNAL) || !defined(SUPPORT_DRI_DRM) +/* + * This is the major number we use for all nodes in /dev. + */ static int AssignedMajorNumber; #endif +/* + * These are the operations that will be associated with the device node + * we create. + * + * With gcc -W, specifying only the non-null members produces "missing + * initializer" warnings. +*/ #if !defined(SUPPORT_DRI_DRM) static int PVRSRVOpen(struct inode* pInode, struct file* pFile); static int PVRSRVRelease(struct inode* pInode, struct file* pFile); @@ -150,6 +212,7 @@ static struct file_operations pvrsrv_fops = PVRSRV_LINUX_MUTEX gPVRSRVLock; +/* PID of process being released */ IMG_UINT32 gui32ReleasePID; #if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL) @@ -161,12 +224,15 @@ static IMG_UINT32 gPVRPowerLevel; #if defined(PVR_LDM_PLATFORM_MODULE) #define LDM_DEV struct platform_device #define LDM_DRV struct platform_driver -#endif +#endif /*PVR_LDM_PLATFORM_MODULE */ #if defined(PVR_LDM_PCI_MODULE) #define LDM_DEV struct pci_dev #define LDM_DRV struct pci_driver -#endif +#endif /* PVR_LDM_PCI_MODULE */ +/* + * This is the driver interface we support. + */ #if defined(PVR_LDM_PLATFORM_MODULE) && !defined(SUPPORT_DRI_DRM_EXTERNAL) static int PVRSRVDriverRemove(LDM_DEV *device); static int PVRSRVDriverProbe(LDM_DEV *device); @@ -177,6 +243,7 @@ static int PVRSRVDriverProbe(LDM_DEV *device, const struct pci_device_id *id); #endif #if defined(PVR_LDM_PCI_MODULE) +/* This structure is used by the Linux module code */ struct pci_device_id powervr_id_table[] __devinitdata = { {PCI_DEVICE(SYS_SGX_DEV_VENDOR_ID, SYS_SGX_DEV_DEVICE_ID)}, #if defined (SYS_SGX_DEV1_DEVICE_ID) @@ -238,6 +305,22 @@ static struct platform_device powervr_device = { }; #endif +/*! +****************************************************************************** + + @Function PVRSRVDriverProbe + + @Description + + See whether a given device is really one we can drive. The platform bus + handler has already established that we should be able to service this device + because of the name match. We probably don't need to do anything else. + + @input pDevice - the device for which a probe is requested + + @Return 0 for success or <0 for an error. + +*****************************************************************************/ #if defined(PVR_LDM_PLATFORM_MODULE) PVR_MOD_STATIC int PVRSRVDriverProbe(LDM_DEV *pDevice) #endif @@ -249,14 +332,19 @@ static int __devinit PVRSRVDriverProbe(LDM_DEV *pDevice, const struct pci_device PVR_TRACE(("PVRSRVDriverProbe(pDevice=%p) (%s)", pDevice, pDevice->name)); -#if 0 - +#if 0 /* INTEGRATION_POINT */ + /* Some systems require device-specific system initialisation. + * E.g. this lets the OS track a device's dependencies on various + * system hardware. + * + * Note: some systems use this to enable HW that SysAcquireData + * will depend on, therefore it must be called first. + */ if (PerDeviceSysInitialise((IMG_PVOID)pDevice) != PVRSRV_OK) { return -EINVAL; } #endif - #if defined(PVR_LDM_PLATFORM_MODULE) if (!pDevice->dev.platform_data) { @@ -264,21 +352,53 @@ static int __devinit PVRSRVDriverProbe(LDM_DEV *pDevice, const struct pci_device } #endif + /* SysInitialise only designed to be called once. + */ psSysData = SysAcquireDataNoCheck(); - if ( psSysData == IMG_NULL) + if (psSysData == IMG_NULL) { gpsPVRLDMDev = pDevice; - if (SysInitialise() != PVRSRV_OK) { return -ENODEV; } } +#if defined(CONFIG_ION_OMAP) + gpsIONClient = ion_client_create(omap_ion_device, + 1 << ION_HEAP_TYPE_CARVEOUT | + 1 << OMAP_ION_HEAP_TYPE_TILER, + "pvr"); + if (IS_ERR_OR_NULL(gpsIONClient)) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVDriverProbe: Couldn't create ion client")); + return PTR_ERR(gpsIONClient); + } +#endif /* defined(CONFIG_ION_OMAP) */ + return 0; } +/*! +****************************************************************************** + + @Function PVRSRVDriverRemove + + @Description + + This call is the opposite of the probe call: it is called when the device is + being removed from the driver's control. See the file $KERNELDIR/drivers/ + base/bus.c:device_release_driver() for the call to this function. + + This is the correct place to clean up anything our driver did while it was + asoociated with the device. + + @input pDevice - the device for which driver detachment is happening + + @Return 0 for success or <0 for an error. + +*****************************************************************************/ #if defined (PVR_LDM_PLATFORM_MODULE) PVR_MOD_STATIC int PVRSRVDriverRemove(LDM_DEV *pDevice) #endif @@ -290,6 +410,11 @@ static void __devexit PVRSRVDriverRemove(LDM_DEV *pDevice) PVR_TRACE(("PVRSRVDriverRemove(pDevice=%p)", pDevice)); +#if defined(CONFIG_ION_OMAP) + ion_client_destroy(gpsIONClient); + gpsIONClient = IMG_NULL; +#endif + SysAcquireData(&psSysData); #if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL) @@ -305,7 +430,8 @@ static void __devexit PVRSRVDriverRemove(LDM_DEV *pDevice) gpsPVRLDMDev = IMG_NULL; -#if 0 +#if 0 /* INTEGRATION_POINT */ + /* See previous integration point for details. */ if (PerDeviceSysDeInitialise((IMG_PVOID)pDevice) != PVRSRV_OK) { return -EINVAL; @@ -319,59 +445,216 @@ static void __devexit PVRSRVDriverRemove(LDM_DEV *pDevice) return; #endif } -#endif +#endif /* defined(PVR_LDM_MODULE) */ +#if defined(PVR_LDM_MODULE) || defined(SUPPORT_DRI_DRM) +static PVRSRV_LINUX_MUTEX gsPMMutex; +static IMG_BOOL bDriverIsSuspended; +static IMG_BOOL bDriverIsShutdown; +#endif #if defined(PVR_LDM_MODULE) || defined(PVR_DRI_DRM_PLATFORM_DEV) +/*! +****************************************************************************** + + @Function PVRSRVDriverShutdown + + @Description + + Suspend device operation for system shutdown. This is called as part of the + system halt/reboot process. The driver is put into a quiescent state by + setting the power state to D3. + + @input pDevice - the device for which shutdown is requested + + @Return nothing + +*****************************************************************************/ PVR_MOD_STATIC void PVRSRVDriverShutdown(LDM_DEV *pDevice) { PVR_TRACE(("PVRSRVDriverShutdown(pDevice=%p)", pDevice)); - (void) PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE_D3); + LinuxLockMutex(&gsPMMutex); + + if (!bDriverIsShutdown && !bDriverIsSuspended) + { + /* + * Take the bridge mutex, and never release it, to stop + * processes trying to use the driver after it has been + * shutdown. + */ + LinuxLockMutex(&gPVRSRVLock); + + (void) PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE_D3); + } + + bDriverIsShutdown = IMG_TRUE; + + /* The bridge mutex is held on exit */ + LinuxUnLockMutex(&gsPMMutex); } -#endif +#endif /* defined(PVR_LDM_MODULE) || defined(PVR_DRI_DRM_PLATFORM_DEV) */ #if defined(PVR_LDM_MODULE) || defined(SUPPORT_DRI_DRM) +/*! +****************************************************************************** + + @Function PVRSRVDriverSuspend + + @Description + + For 2.6 kernels: + Suspend device operation. We always get three calls to this regardless of + the state (D1-D3) chosen. The order is SUSPEND_DISABLE, SUSPEND_SAVE_STATE + then SUSPEND_POWER_DOWN. We take action as soon as we get the disable call, + the other states not being handled by us yet. + + For MontaVista 2.4 kernels: + This call gets made once only when someone does something like + + # echo -e -n "suspend powerdown 0" >/sys.devices/legacy/pvrsrv0/power + + The 3rd, numeric parameter (0) in the above has no relevence and is not + passed into us. The state parameter is always zero and the level parameter + is always SUSPEND_POWER_DOWN. Vive la difference! + + @input pDevice - the device for which resume is requested + + @Return 0 for success or <0 for an error. + +*****************************************************************************/ #if defined(SUPPORT_DRI_DRM) && !defined(PVR_DRI_DRM_PLATFORM_DEV) +#if defined(SUPPORT_DRM_MODESET) +int PVRSRVDriverSuspend(struct pci_dev *pDevice, pm_message_t state) +#else int PVRSRVDriverSuspend(struct drm_device *pDevice, pm_message_t state) +#endif #else PVR_MOD_STATIC int PVRSRVDriverSuspend(LDM_DEV *pDevice, pm_message_t state) #endif { + int res = 0; #if !(defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL) && !defined(SUPPORT_DRI_DRM)) PVR_TRACE(( "PVRSRVDriverSuspend(pDevice=%p)", pDevice)); - if (PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE_D3) != PVRSRV_OK) + LinuxLockMutex(&gsPMMutex); + + if (!bDriverIsSuspended && !bDriverIsShutdown) { - return -EINVAL; + LinuxLockMutex(&gPVRSRVLock); + + if (PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE_D3) == PVRSRV_OK) + { + /* The bridge mutex will be held until we resume */ + bDriverIsSuspended = IMG_TRUE; + } + else + { + LinuxUnLockMutex(&gPVRSRVLock); + res = -EINVAL; + } } + + LinuxUnLockMutex(&gsPMMutex); #endif - return 0; + return res; } +/*! +****************************************************************************** + + @Function PVRSRVDriverResume + + @Description + + Resume device operation following a lull due to earlier suspension. It is + implicit we're returning to D0 (fully operational) state. We always get three + calls to this using level thus: RESUME_POWER_ON, RESUME_RESTORE_STATE then + RESUME_ENABLE. On 2.6 kernels We don't do anything until we get the enable + call; on the MontaVista set-up we only ever get the RESUME_POWER_ON call. + + @input pDevice - the device for which resume is requested + + @Return 0 for success or <0 for an error. + +*****************************************************************************/ #if defined(SUPPORT_DRI_DRM) && !defined(PVR_DRI_DRM_PLATFORM_DEV) +#if defined(SUPPORT_DRM_MODESET) +int PVRSRVDriverResume(struct pci_dev *pDevice) +#else int PVRSRVDriverResume(struct drm_device *pDevice) +#endif #else PVR_MOD_STATIC int PVRSRVDriverResume(LDM_DEV *pDevice) #endif { + int res = 0; #if !(defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL) && !defined(SUPPORT_DRI_DRM)) PVR_TRACE(("PVRSRVDriverResume(pDevice=%p)", pDevice)); - if (PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE_D0) != PVRSRV_OK) + LinuxLockMutex(&gsPMMutex); + + if (bDriverIsSuspended && !bDriverIsShutdown) { - return -EINVAL; + if (PVRSRVSetPowerStateKM(PVRSRV_SYS_POWER_STATE_D0) == PVRSRV_OK) + { + bDriverIsSuspended = IMG_FALSE; + LinuxUnLockMutex(&gPVRSRVLock); + } + else + { + /* The bridge mutex is not released on failure */ + res = -EINVAL; + } } + + LinuxUnLockMutex(&gsPMMutex); #endif - return 0; + return res; } -#endif +#endif /* defined(PVR_LDM_MODULE) || defined(SUPPORT_DRI_DRM) */ #if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL) && !defined(SUPPORT_DRI_DRM) +/* + * If PVR_LDM_PCI_MODULE is defined (and PVR_MANUAL_POWER_CONTROL is *NOT* defined), + * the device can be suspended and resumed without suspending/resuming the + * system, by writing values into the power/state sysfs file for the device. + * To suspend: + * echo -n 2 > power/state + * To Resume: + * echo -n 0 > power/state + * + * The problem with this approach is that the device is usually left + * powered up; it is the responsibility of the bus driver to remove + * the power. + * + * Defining PVR_MANUAL_POWER_CONTROL is intended to make it easier to + * debug power management issues, especially when power is really removed + * from the device. It is easier to debug the driver if it is not being + * suspended/resumed with the rest of the system. + * + * When PVR_MANUAL_POWER_CONTROL is defined, the following proc entry is + * created: + * /proc/pvr/power_control + * The driver suspend/resume entry points defined below no longer suspend or + * resume the device. To suspend the device, type the following: + * echo 2 > /proc/pvr/power_control + * To resume the device, type: + * echo 0 > /proc/pvr/power_control + * + * The following example shows how to suspend/resume the device independently + * of the rest of the system. + * Suspend the device: + * echo 2 > /proc/pvr/power_control + * Suspend the system. Then you should be able to suspend and resume + * as normal. To resume the device type the following: + * echo 0 > /proc/pvr/power_control + */ + IMG_INT PVRProcSetPowerLevel(struct file *file, const IMG_CHAR *buffer, IMG_UINT32 count, IMG_VOID *data) { IMG_CHAR data_buffer[2]; @@ -418,6 +701,23 @@ void ProcSeqShowPowerLevel(struct seq_file *sfile,void* el) #endif +/*! +****************************************************************************** + + @Function PVRSRVOpen + + @Description + + Release access the PVR services node - called when a file is closed, whether + at exit or using close(2) system call. + + @input pInode - the inode for the file being openeded + + @input pFile - the file handle data for the actual file being opened + + @Return 0 for success or <0 for an error. + +*****************************************************************************/ #if defined(SUPPORT_DRI_DRM) int PVRSRVOpen(struct drm_device unref__ *dev, struct drm_file *pFile) #else @@ -478,6 +778,23 @@ err_unlock: } +/*! +****************************************************************************** + + @Function PVRSRVRelease + + @Description + + Release access the PVR services node - called when a file is closed, whether + at exit or using close(2) system call. + + @input pInode - the inode for the file being released + + @input pFile - the file handle data for the actual file being released + + @Return 0 for success or <0 for an error. + +*****************************************************************************/ #if defined(SUPPORT_DRI_DRM) void PVRSRVRelease(void *pvPrivData) #else @@ -485,6 +802,7 @@ static int PVRSRVRelease(struct inode unref__ * pInode, struct file *pFile) #endif { PVRSRV_FILE_PRIVATE_DATA *psPrivateData; + int err = 0; LinuxLockMutex(&gPVRSRVLock); @@ -499,7 +817,40 @@ static int PVRSRVRelease(struct inode unref__ * pInode, struct file *pFile) list_del(&psPrivateData->sDRMAuthListItem); #endif - + if(psPrivateData->hKernelMemInfo) + { + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + + /* Look up the meminfo we just exported */ + if(PVRSRVLookupHandle(KERNEL_HANDLE_BASE, + (IMG_PVOID *)&psKernelMemInfo, + psPrivateData->hKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "%s: Failed to look up export handle", __FUNCTION__)); + err = -EFAULT; + goto err_unlock; + } + + /* Tell the XProc about the export if required */ + if (psKernelMemInfo->sShareMemWorkaround.bInUse) + { + BM_XProcIndexRelease(psKernelMemInfo->sShareMemWorkaround.ui32ShareIndex); + } + + /* This drops the psMemInfo refcount bumped on export */ + if(FreeMemCallBackCommon(psKernelMemInfo, 0, + PVRSRV_FREE_CALLBACK_ORIGIN_EXTERNAL) != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "%s: FreeMemCallBackCommon failed", __FUNCTION__)); + err = -EFAULT; + goto err_unlock; + } + } + + /* Usually this is the same as OSGetCurrentProcessIDKM(), + * but not necessarily (e.g. fork(), child closes last..) + */ gui32ReleasePID = psPrivateData->ui32OpenPID; PVRSRVProcessDisconnect(psPrivateData->ui32OpenPID); gui32ReleasePID = 0; @@ -509,18 +860,56 @@ static int PVRSRVRelease(struct inode unref__ * pInode, struct file *pFile) psPrivateData, psPrivateData->hBlockAlloc); #if !defined(SUPPORT_DRI_DRM) - set_private(pFile, IMG_NULL); + set_private(pFile, IMG_NULL); /*nulling shared pointer*/ #endif } +err_unlock: LinuxUnLockMutex(&gPVRSRVLock); - -#if !defined(SUPPORT_DRI_DRM) - return 0; +#if defined(SUPPORT_DRI_DRM) + return; +#else + return err; #endif } +/*! +****************************************************************************** + + @Function PVRCore_Init + + @Description + + Insert the driver into the kernel. + + The device major number is allocated by the kernel dynamically. This means + that the device node (nominally /dev/pvrsrv) will need to be re-made at boot + time if the number changes between subsequent loads of the module. While the + number often stays constant between loads this is not guaranteed. The node + is made as root on the shell with: + + mknod /dev/pvrsrv c nnn 0 + + where nnn is the major number found in /proc/devices for DEVNAME and also + reported by the PVR_DPF() - look at the boot log using dmesg' to see this). + + Currently the auto-generated script /etc/init.d/rc.pvr handles creation of + the device. In other environments the device may be created either through + devfs or sysfs. + + Readable proc-filesystem entries under /proc/pvr are created with + CreateProcEntries(). These can be read at runtime to get information about + the device (eg. 'cat /proc/pvr/vm') + + __init places the function in a special memory section that the kernel frees + once the function has been run. Refer also to module_init() macro call below. + + @input none + + @Return none + +*****************************************************************************/ #if defined(SUPPORT_DRI_DRM) int PVRCore_Init(void) #else @@ -535,11 +924,17 @@ static int __init PVRCore_Init(void) #endif #if !defined(SUPPORT_DRI_DRM) - + /* + * Must come before attempting to print anything via Services. + * For DRM, the initialisation will already have been done. + */ PVRDPFInit(); #endif PVR_TRACE(("PVRCore_Init")); +#if defined(PVR_LDM_MODULE) || defined(SUPPORT_DRI_DRM) + LinuxInitMutex(&gsPMMutex); +#endif LinuxInitMutex(&gPVRSRVLock); if (CreateProcEntries ()) @@ -586,7 +981,7 @@ static int __init PVRCore_Init(void) goto init_failed; } #endif -#endif +#endif /* PVR_LDM_PLATFORM_MODULE */ #if defined(PVR_LDM_PCI_MODULE) if ((error = pci_register_driver(&powervr_driver)) != 0) @@ -595,10 +990,12 @@ static int __init PVRCore_Init(void) goto init_failed; } -#endif +#endif /* PVR_LDM_PCI_MODULE */ #else - + /* + * Drivers using LDM, will call SysInitialise in the probe/attach code + */ if ((eError = SysInitialise()) != PVRSRV_OK) { error = -ENODEV; @@ -611,7 +1008,7 @@ static int __init PVRCore_Init(void) #endif goto init_failed; } -#endif +#endif /* !defined(PVR_LDM_MODULE) */ #if !defined(SUPPORT_DRI_DRM) AssignedMajorNumber = register_chrdev(0, DEVNAME, &pvrsrv_fops); @@ -625,10 +1022,13 @@ static int __init PVRCore_Init(void) } PVR_TRACE(("PVRCore_Init: major device %d", AssignedMajorNumber)); -#endif +#endif /* !defined(SUPPORT_DRI_DRM) */ #if defined(PVR_LDM_MODULE) - + /* + * This code (using GPL symbols) facilitates automatic device + * node creation on platforms with udev (or similar). + */ psPvrClass = class_create(THIS_MODULE, "pvr"); if (IS_ERR(psPvrClass)) @@ -641,7 +1041,7 @@ static int __init PVRCore_Init(void) psDev = device_create(psPvrClass, NULL, MKDEV(AssignedMajorNumber, 0), #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)) NULL, -#endif +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)) */ DEVNAME); if (IS_ERR(psDev)) { @@ -649,7 +1049,7 @@ static int __init PVRCore_Init(void) error = -EBUSY; goto destroy_class; } -#endif +#endif /* defined(PVR_LDM_DEVICE_CLASS) */ return 0; @@ -674,8 +1074,8 @@ sys_deinit: platform_driver_unregister(&powervr_driver); #endif -#else - +#else /* defined(PVR_LDM_MODULE) */ + /* LDM drivers call SysDeinitialise during PVRSRVDriverRemove */ { SYS_DATA *psSysData; @@ -685,7 +1085,7 @@ sys_deinit: (void) SysDeinitialise(psSysData); } } -#endif +#endif /* defined(PVR_LDM_MODULE) */ init_failed: PVRMMapCleanup(); LinuxMMCleanup(); @@ -695,9 +1095,34 @@ init_failed: return error; -} +} /*PVRCore_Init*/ + + +/*! +***************************************************************************** + + @Function PVRCore_Cleanup + + @Description + + Remove the driver from the kernel. + There's no way we can get out of being unloaded other than panicking; we + just do everything and plough on regardless of error. + __exit places the function in a special memory section that the kernel frees + once the function has been run. Refer also to module_exit() macro call below. + + Note that the for LDM on MontaVista kernels, the positioning of the driver + de-registration is the opposite way around than would be suggested by the + registration case or the 2,6 kernel case. This is the correct way to do it + and the kernel panics if you change it. You have been warned. + + @input none + + @Return none + +*****************************************************************************/ #if defined(SUPPORT_DRI_DRM) void PVRCore_Cleanup(void) #else @@ -721,17 +1146,17 @@ static void __exit PVRCore_Cleanup(void) #if !defined(SUPPORT_DRI_DRM) #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)) if ( -#endif +#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)) */ unregister_chrdev((IMG_UINT)AssignedMajorNumber, DRVNAME) #if !(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)) ; -#else +#else /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)) */ ) { PVR_DPF((PVR_DBG_ERROR," can't unregister device major %d", AssignedMajorNumber)); } -#endif -#endif +#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)) */ +#endif /* !defined(SUPPORT_DRI_DRM) */ #if defined(PVR_LDM_MODULE) @@ -746,7 +1171,7 @@ static void __exit PVRCore_Cleanup(void) platform_driver_unregister(&powervr_driver); #endif -#else +#else /* defined(PVR_LDM_MODULE) */ #if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL) if (gPVRPowerLevel != 0) { @@ -756,9 +1181,9 @@ static void __exit PVRCore_Cleanup(void) } } #endif - + /* LDM drivers call SysDeinitialise during PVRSRVDriverRemove */ (void) SysDeinitialise(psSysData); -#endif +#endif /* defined(PVR_LDM_MODULE) */ PVRMMapCleanup(); @@ -773,6 +1198,12 @@ static void __exit PVRCore_Cleanup(void) PVR_TRACE(("PVRCore_Cleanup: unloading")); } +/* + * These macro calls define the initialisation and removal functions of the + * driver. Although they are prefixed `module_', they apply when compiling + * statically as well; in both cases they define the function the kernel will + * run to start/stop the driver. +*/ #if !defined(SUPPORT_DRI_DRM) module_init(PVRCore_Init); module_exit(PVRCore_Cleanup); diff --git a/sgx/services4/srvkm/env/linux/mutex.c b/sgx/services4/srvkm/env/linux/mutex.c index 742fa03..84e2a74 100644 --- a/sgx/services4/srvkm/env/linux/mutex.c +++ b/sgx/services4/srvkm/env/linux/mutex.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Linux mutex interface +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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 <linux/version.h> #include <linux/errno.h> @@ -79,7 +95,7 @@ IMG_BOOL LinuxIsLockedMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex) } -#else +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) */ IMG_VOID LinuxInitMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex) @@ -98,7 +114,9 @@ PVRSRV_ERROR LinuxLockMutexInterruptible(PVRSRV_LINUX_MUTEX *psPVRSRVMutex) { if(down_interruptible(&psPVRSRVMutex->sSemaphore) == -EINTR) { - + /* The process was sent a signal while waiting for the semaphore + * (e.g. a kill signal from userspace) + */ return PVRSRV_ERROR_MUTEX_INTERRUPTIBLE_ERROR; }else{ atomic_dec(&psPVRSRVMutex->Count); @@ -132,5 +150,5 @@ IMG_BOOL LinuxIsLockedMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex) return (IMG_BOOL)iCount; } -#endif +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) */ diff --git a/sgx/services4/srvkm/env/linux/mutex.h b/sgx/services4/srvkm/env/linux/mutex.h index 5e787b7..2c7d658 100644 --- a/sgx/services4/srvkm/env/linux/mutex.h +++ b/sgx/services4/srvkm/env/linux/mutex.h @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Linux mutex interface +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ + #ifndef __INCLUDED_LINUX_MUTEX_H_ #define __INCLUDED_LINUX_MUTEX_H_ @@ -41,12 +58,16 @@ typedef struct mutex PVRSRV_LINUX_MUTEX; -#else +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) */ typedef struct { struct semaphore sSemaphore; - + /* since Linux's struct semaphore is intended to be + * opaque we don't poke inside for the count and + * instead we track it outselves. (So we can implement + * LinuxIsLockedMutex) + */ atomic_t Count; }PVRSRV_LINUX_MUTEX; @@ -66,5 +87,5 @@ extern IMG_VOID LinuxUnLockMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex); extern IMG_BOOL LinuxIsLockedMutex(PVRSRV_LINUX_MUTEX *psPVRSRVMutex); -#endif +#endif /* __INCLUDED_LINUX_MUTEX_H_ */ diff --git a/sgx/services4/srvkm/env/linux/mutils.c b/sgx/services4/srvkm/env/linux/mutils.c index a012cf5..9679ed7 100644 --- a/sgx/services4/srvkm/env/linux/mutils.c +++ b/sgx/services4/srvkm/env/linux/mutils.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Linux memory interface support functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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 <linux/version.h> @@ -77,15 +93,23 @@ pvr_pat_entry(u64 pat, IMG_UINT index) static IMG_VOID PVRLinuxX86PATProbe(IMG_VOID) { - - if (cpu_has_pat) + /* + * cpu_has_pat indicates whether PAT support is available on the CPU, + * but doesn't indicate if it has been enabled. + */ + if (cpu_has_pat) /* PRQA S 3335 */ /* ignore 'no function declared' */ { u64 pat; IMG_UINT pat_index; IMG_UINT pat_entry; PVR_TRACE(("%s: PAT available", __FUNCTION__)); - + /* + * There is no Linux API for finding out if write combining + * is avaialable through the PAT, so we take the direct + * approach, and see if the PAT MSR contains a write combining + * entry. + */ rdmsrl(MSR_IA32_CR_PAT, pat); PVR_TRACE(("%s: Top 32 bits of PAT: 0x%.8x", __FUNCTION__, (IMG_UINT)(pat >> 32))); PVR_TRACE(("%s: Bottom 32 bits of PAT: 0x%.8x", __FUNCTION__, (IMG_UINT)(pat))); @@ -110,21 +134,28 @@ PVRLinuxX86PATProbe(IMG_VOID) { PVR_TRACE(("%s: Write combining not available", __FUNCTION__)); } -#else +#else /* defined(SUPPORT_LINUX_X86_WRITECOMBINE) */ PVR_TRACE(("%s: Write combining disabled in driver build", __FUNCTION__)); -#endif -#endif +#endif /* defined(SUPPORT_LINUX_X86_WRITECOMBINE) */ +#endif /* DEBUG */ } pgprot_t pvr_pgprot_writecombine(pgprot_t prot) { - - + /* + * It would be worth checking from time to time to see if a + * pgprot_writecombine function (or similar) is introduced on Linux for + * x86 processors. If so, this function, and PVRLinuxX86PATProbe can be + * removed, and a macro used to select between pgprot_writecombine and + * pgprot_noncached, dpending on the value for of + * SUPPORT_LINUX_X86_WRITECOMBINE. + */ + /* PRQA S 0481,0482 2 */ /* scalar expressions */ return (g_write_combining_available) ? __pgprot((pgprot_val(prot) & ~_PAGE_CACHE_MASK) | _PAGE_CACHE_WC) : pgprot_noncached(prot); } -#endif +#endif /* defined(SUPPORT_LINUX_X86_PAT) */ IMG_VOID PVRLinuxMUtilsInit(IMG_VOID) diff --git a/sgx/services4/srvkm/env/linux/mutils.h b/sgx/services4/srvkm/env/linux/mutils.h index b2a8ba0..4921e60 100644 --- a/sgx/services4/srvkm/env/linux/mutils.h +++ b/sgx/services4/srvkm/env/linux/mutils.h @@ -1,29 +1,46 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Memory management support utils +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Declares various memory management support functions + for Linux. +@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. + +*/ /**************************************************************************/ #ifndef __IMG_LINUX_MUTILS_H__ #define __IMG_LINUX_MUTILS_H__ @@ -99,5 +116,5 @@ IMG_VOID PVRLinuxMUtilsInit(IMG_VOID); -#endif +#endif /* __IMG_LINUX_MUTILS_H__ */ diff --git a/sgx/services4/srvkm/env/linux/osfunc.c b/sgx/services4/srvkm/env/linux/osfunc.c index 1fb99f2..4e4b3a0 100644 --- a/sgx/services4/srvkm/env/linux/osfunc.c +++ b/sgx/services4/srvkm/env/linux/osfunc.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Environment related functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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 <linux/version.h> @@ -74,6 +90,15 @@ #include "event.h" #include "linkage.h" #include "pvr_uaccess.h" +#include "lock.h" + +#if defined (SUPPORT_ION) +#include "ion.h" +#endif + +#if defined (CONFIG_X86_PAE) +#error Physical Address Extension not supported with the driver +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) #define ON_EACH_CPU(func, info, wait) on_each_cpu(func, info, wait) @@ -82,6 +107,13 @@ #endif #if defined(PVR_LINUX_USING_WORKQUEUES) && !defined(CONFIG_PREEMPT) +/* + * Services spins at certain points waiting for events (e.g. swap + * chain destrucion). If those events rely on workqueues running, + * it needs to be possible to preempt the waiting thread. + * Removing the need for CONFIG_PREEMPT will require adding preemption + * points at various points in Services. + */ #error "A preemptible Linux kernel is required when using workqueues" #endif @@ -89,7 +121,7 @@ #define EVENT_OBJECT_TIMEOUT_MS (2000) #else #define EVENT_OBJECT_TIMEOUT_MS (100) -#endif +#endif /* EMULATOR */ #if !defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) PVRSRV_ERROR OSAllocMem_Impl(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOID *ppvCpuVAddr, IMG_HANDLE *phBlockAlloc) @@ -102,7 +134,7 @@ PVRSRV_ERROR OSAllocMem_Impl(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOI if (ui32Size > PAGE_SIZE) { - + /* Try to allocate the memory using vmalloc */ #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) *ppvCpuVAddr = _VMallocWrapper(ui32Size, PVRSRV_HAP_CACHED, pszFilename, ui32Line); #else @@ -135,7 +167,7 @@ static inline int is_vmalloc_addr(const void *pvCpuVAddr) return lAddr >= VMALLOC_START && lAddr < VMALLOC_END; } -#endif +#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)) */ #if !defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) PVRSRV_ERROR OSFreeMem_Impl(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOID pvCpuVAddr, IMG_HANDLE hBlockAlloc) @@ -172,6 +204,9 @@ PVRSRV_ERROR OSAllocPages_Impl(IMG_UINT32 ui32AllocFlags, IMG_UINT32 ui32Size, IMG_UINT32 ui32PageSize, + IMG_PVOID pvPrivData, + IMG_UINT32 ui32PrivDataLength, + IMG_HANDLE hBMHandle, IMG_VOID **ppvCpuVAddr, IMG_HANDLE *phOSMemHandle) { @@ -180,7 +215,8 @@ OSAllocPages_Impl(IMG_UINT32 ui32AllocFlags, PVR_UNREFERENCED_PARAMETER(ui32PageSize); #if 0 - + /* For debug: force all OSAllocPages allocations to have a kernel + * virtual address */ if(ui32AllocFlags & PVRSRV_HAP_SINGLE_PROCESS) { ui32AllocFlags &= ~PVRSRV_HAP_SINGLE_PROCESS; @@ -188,6 +224,22 @@ OSAllocPages_Impl(IMG_UINT32 ui32AllocFlags, } #endif + if(ui32AllocFlags & PVRSRV_MEM_ION) + { + /* We'll only see HAP_SINGLE_PROCESS with MEM_ION */ + BUG_ON((ui32AllocFlags & PVRSRV_HAP_MAPTYPE_MASK) != PVRSRV_HAP_SINGLE_PROCESS); + + psLinuxMemArea = NewIONLinuxMemArea(ui32Size, ui32AllocFlags, + pvPrivData, ui32PrivDataLength); + if(!psLinuxMemArea) + { + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + PVRMMapRegisterArea(psLinuxMemArea); + goto ExitSkipSwitch; + } + switch(ui32AllocFlags & PVRSRV_HAP_MAPTYPE_MASK) { case PVRSRV_HAP_KERNEL_ONLY: @@ -201,8 +253,9 @@ OSAllocPages_Impl(IMG_UINT32 ui32AllocFlags, } case PVRSRV_HAP_SINGLE_PROCESS: { - - + /* Currently PVRSRV_HAP_SINGLE_PROCESS implies that we dont need a + * kernel virtual mapping, but will need a user space virtual mapping */ + psLinuxMemArea = NewAllocPagesLinuxMemArea(ui32Size, ui32AllocFlags); if(!psLinuxMemArea) { @@ -214,10 +267,18 @@ OSAllocPages_Impl(IMG_UINT32 ui32AllocFlags, case PVRSRV_HAP_MULTI_PROCESS: { - + /* Currently PVRSRV_HAP_MULTI_PROCESS implies that we need a kernel + * virtual mapping and potentially multiple user space virtual + * mappings: Note: these eat into our limited kernel virtual + * address space. */ + #if defined(VIVT_CACHE) || defined(__sh__) - - ui32AllocFlags &= ~(PVRSRV_HAP_CACHED|PVRSRV_HAP_SMART); + /* ARM9 caches are tagged with virtual pages, not physical. As we are going to + * share this memory in different address spaces, we don't want it to be cached. + * ARM11 has physical tagging, so we can cache this memory without fear of virtual + * address aliasing in the TLB, as long as the kernel supports cache colouring for + * VIPT architectures. */ + ui32AllocFlags &= ~PVRSRV_HAP_CACHED; #endif psLinuxMemArea = NewVMallocLinuxMemArea(ui32Size, ui32AllocFlags); if(!psLinuxMemArea) @@ -234,6 +295,16 @@ OSAllocPages_Impl(IMG_UINT32 ui32AllocFlags, return PVRSRV_ERROR_INVALID_PARAMS; } + /* + In case of sparse mapping we need to handle back to the BM as it + knows the mapping info + */ + if (ui32AllocFlags & PVRSRV_MEM_SPARSE) + { + psLinuxMemArea->hBMHandle = hBMHandle; + } + +ExitSkipSwitch: *ppvCpuVAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea); *phOSMemHandle = psLinuxMemArea; @@ -302,7 +373,7 @@ OSGetSubMemHandle(IMG_HANDLE hOSMemHandle, } *phOSMemHandleRet = psLinuxMemArea; - + /* KERNEL_ONLY areas are never mmapable. */ if(ui32Flags & PVRSRV_HAP_KERNEL_ONLY) { return PVRSRV_OK; @@ -344,23 +415,6 @@ OSReleaseSubMemHandle(IMG_VOID *hOSMemHandle, IMG_UINT32 ui32Flags) return PVRSRV_OK; } -IMG_VOID -OSMemHandleRegisterSmart(IMG_VOID *hOSMemHandle, IMG_HANDLE hSmartCache) -{ - LinuxMemArea *psLinuxMemArea = hOSMemHandle; - psLinuxMemArea->hSmartCache = hSmartCache; -} - -IMG_VOID -OSMemHandleUnegisterSmart(IMG_VOID *hOSMemHandle, IMG_HANDLE hSmartCache) -{ - LinuxMemArea *psLinuxMemArea = hOSMemHandle; - if (psLinuxMemArea->hSmartCache == hSmartCache) - { - psLinuxMemArea->hSmartCache = NULL; - } -} - #if defined(SUPPORT_DRI_DRM_EXTERNAL) IMG_VOID @@ -388,7 +442,33 @@ OSMemHandleToCpuPAddr(IMG_VOID *hOSMemHandle, IMG_UINT32 ui32ByteOffset) } +IMG_BOOL OSMemHandleIsPhysContig(IMG_VOID *hOSMemHandle) +{ + LinuxMemArea *psLinuxMemArea = (LinuxMemArea *)hOSMemHandle; + + PVR_ASSERT(psLinuxMemArea); + if(psLinuxMemArea->eAreaType == LINUX_MEM_AREA_EXTERNAL_KV) + return psLinuxMemArea->uData.sExternalKV.bPhysContig; + + return IMG_FALSE; +} + + +/*! +****************************************************************************** + + @Function OSMemCopy + + @Description Copies memory around + + @Input pvDst - pointer to dst + @Output pvSrc - pointer to src + @Input ui32Size - bytes to copy + + @Return none + +******************************************************************************/ IMG_VOID OSMemCopy(IMG_VOID *pvDst, IMG_VOID *pvSrc, IMG_UINT32 ui32Size) { #if defined(USE_UNOPTIMISED_MEMCPY) @@ -407,6 +487,22 @@ IMG_VOID OSMemCopy(IMG_VOID *pvDst, IMG_VOID *pvSrc, IMG_UINT32 ui32Size) } +/*! +****************************************************************************** + + @Function OSMemSet + + @Description Function that does the same as the C memset() functions + + @Modified *pvDest : pointer to start of buffer to be set + + @Input ui8Value: value to set each byte to + + @Input ui32Size : number of bytes to set + + @Return IMG_VOID + +******************************************************************************/ IMG_VOID OSMemSet(IMG_VOID *pvDest, IMG_UINT8 ui8Value, IMG_UINT32 ui32Size) { #if defined(USE_UNOPTIMISED_MEMSET) @@ -424,11 +520,21 @@ IMG_VOID OSMemSet(IMG_VOID *pvDest, IMG_UINT8 ui8Value, IMG_UINT32 ui32Size) } +/*! +****************************************************************************** + @Function OSStringCopy + @Description strcpy +******************************************************************************/ IMG_CHAR *OSStringCopy(IMG_CHAR *pszDest, const IMG_CHAR *pszSrc) { return (strcpy(pszDest, pszSrc)); } +/*! +****************************************************************************** + @Function OSSNPrintf + @Description snprintf +******************************************************************************/ IMG_INT32 OSSNPrintf(IMG_CHAR *pStr, IMG_UINT32 ui32Size, const IMG_CHAR *pszFormat, ...) { va_list argList; @@ -441,6 +547,19 @@ IMG_INT32 OSSNPrintf(IMG_CHAR *pStr, IMG_UINT32 ui32Size, const IMG_CHAR *pszFor return iCount; } +/*! +****************************************************************************** + + @Function OSBreakResourceLock + + @Description unlocks an OS dependant resource + + @Input phResource - pointer to OS dependent resource structure + @Input ui32ID - Lock value to look for + + @Return + +******************************************************************************/ IMG_VOID OSBreakResourceLock (PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID) { volatile IMG_UINT32 *pui32Access = (volatile IMG_UINT32 *)&psResource->ui32Lock; @@ -464,6 +583,18 @@ IMG_VOID OSBreakResourceLock (PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID) } +/*! +****************************************************************************** + + @Function OSCreateResource + + @Description creates a OS dependant resource object + + @Input phResource - pointer to OS dependent resource + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSCreateResource(PVRSRV_RESOURCE *psResource) { psResource->ui32ID = 0; @@ -473,6 +604,18 @@ PVRSRV_ERROR OSCreateResource(PVRSRV_RESOURCE *psResource) } +/*! +****************************************************************************** + + @Function OSDestroyResource + + @Description destroys an OS dependant resource object + + @Input phResource - pointer to OS dependent resource + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSDestroyResource (PVRSRV_RESOURCE *psResource) { OSBreakResourceLock (psResource, psResource->ui32ID); @@ -481,12 +624,26 @@ PVRSRV_ERROR OSDestroyResource (PVRSRV_RESOURCE *psResource) } +/*! +****************************************************************************** + + @Function OSInitEnvData + + @Description Allocates space for env specific data + + @Input ppvEnvSpecificData - pointer to pointer in which to return + allocated data. + @Input ui32MMUMode - MMU mode. + + @Return nothing + +******************************************************************************/ PVRSRV_ERROR OSInitEnvData(IMG_PVOID *ppvEnvSpecificData) { ENV_DATA *psEnvData; PVRSRV_ERROR eError; - + /* allocate env specific data */ eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(ENV_DATA), (IMG_VOID **)&psEnvData, IMG_NULL, "Environment Data"); if (eError != PVRSRV_OK) @@ -500,22 +657,34 @@ PVRSRV_ERROR OSInitEnvData(IMG_PVOID *ppvEnvSpecificData) if (eError != PVRSRV_OK) { OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(ENV_DATA), psEnvData, IMG_NULL); - + /*not nulling pointer, out of scope*/ return eError; } - + /* ISR installation flags */ psEnvData->bMISRInstalled = IMG_FALSE; psEnvData->bLISRInstalled = IMG_FALSE; - + /* copy structure back */ *ppvEnvSpecificData = psEnvData; return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function OSDeInitEnvData + + @Description frees env specific data memory + + @Input pvEnvSpecificData - pointer to private structure + + @Return PVRSRV_OK on success else PVRSRV_ERROR_OUT_OF_MEMORY + +******************************************************************************/ PVRSRV_ERROR OSDeInitEnvData(IMG_PVOID pvEnvSpecificData) { ENV_DATA *psEnvData = (ENV_DATA*)pvEnvSpecificData; @@ -527,20 +696,42 @@ PVRSRV_ERROR OSDeInitEnvData(IMG_PVOID pvEnvSpecificData) psEnvData->pvBridgeData = IMG_NULL; OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(ENV_DATA), pvEnvSpecificData, IMG_NULL); - + /*not nulling pointer, copy on stack*/ return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function OSReleaseThreadQuanta + @Description + Releases thread quanta + + @Return nothing + +******************************************************************************/ IMG_VOID OSReleaseThreadQuanta(IMG_VOID) { schedule(); } +/*! +****************************************************************************** + + @Function OSClockus + + @Description + This function returns the clock in microseconds + @Input void + + @Return - clock (us) + +******************************************************************************/ IMG_UINT32 OSClockus(IMG_VOID) { IMG_UINT32 time, j = jiffies; @@ -563,25 +754,71 @@ IMG_VOID OSSleepms(IMG_UINT32 ui32Timems) } +/*! +****************************************************************************** + + @Function OSFuncHighResTimerCreate + @Description + This function creates a high res timer who's handle is returned + + @Input nothing + + @Return handle + +******************************************************************************/ IMG_HANDLE OSFuncHighResTimerCreate(IMG_VOID) { - + /* We don't need a handle, but we must return non-NULL */ return (IMG_HANDLE) 1; } +/*! +****************************************************************************** + + @Function OSFuncHighResTimerGetus + + @Description + This function returns the current timestamp in us + @Input nothing + + @Return handle + +******************************************************************************/ IMG_UINT32 OSFuncHighResTimerGetus(IMG_HANDLE hTimer) { return (IMG_UINT32) jiffies_to_usecs(jiffies); } +/*! +****************************************************************************** + + @Function OSFuncHighResTimerDestroy + @Description + This function will destroy the high res timer + + @Input nothing + + @Return handle + +******************************************************************************/ IMG_VOID OSFuncHighResTimerDestroy(IMG_HANDLE hTimer) { PVR_UNREFERENCED_PARAMETER(hTimer); } +/*! +****************************************************************************** + + @Function OSGetCurrentProcessIDKM + + @Description Returns handle for current process + + @Return ID of current process + +*****************************************************************************/ IMG_UINT32 OSGetCurrentProcessIDKM(IMG_VOID) { if (in_interrupt()) @@ -601,6 +838,16 @@ IMG_UINT32 OSGetCurrentProcessIDKM(IMG_VOID) } +/*! +****************************************************************************** + + @Function OSGetPageSize + + @Description gets page size + + @Return page size + +******************************************************************************/ IMG_UINT32 OSGetPageSize(IMG_VOID) { #if defined(__sh__) @@ -613,6 +860,16 @@ IMG_UINT32 OSGetPageSize(IMG_VOID) } #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) +/*! +****************************************************************************** + + @Function DeviceISRWrapper + + @Description wrapper for Device ISR function to conform to ISR OS interface + + @Return + +******************************************************************************/ static irqreturn_t DeviceISRWrapper(int irq, void *dev_id #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) , struct pt_regs *regs @@ -649,6 +906,19 @@ out: +/*! +****************************************************************************** + + @Function SystemISRWrapper + + @Description wrapper for System ISR function to conform to ISR OS interface + + @Input Interrupt - NT interrupt object. + @Input Context - Context parameter + + @Return + +******************************************************************************/ static irqreturn_t SystemISRWrapper(int irq, void *dev_id #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) , struct pt_regs *regs @@ -682,6 +952,21 @@ out: return bStatus ? IRQ_HANDLED : IRQ_NONE; #endif } +/*! +****************************************************************************** + + @Function OSInstallDeviceLISR + + @Description Installs a Device ISR + + @Input pvSysData + @Input ui32Irq - IRQ number + @Input pszISRName - ISR name + @Input pvDeviceNode - device node contains ISR function and data argument + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSInstallDeviceLISR(IMG_VOID *pvSysData, IMG_UINT32 ui32Irq, IMG_CHAR *pszISRName, @@ -718,6 +1003,18 @@ PVRSRV_ERROR OSInstallDeviceLISR(IMG_VOID *pvSysData, return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function OSUninstallDeviceLISR + + @Description Uninstalls a Device ISR + + @Input pvSysData - sysdata + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSUninstallDeviceLISR(IMG_VOID *pvSysData) { SYS_DATA *psSysData = (SYS_DATA*)pvSysData; @@ -739,6 +1036,19 @@ PVRSRV_ERROR OSUninstallDeviceLISR(IMG_VOID *pvSysData) } +/*! +****************************************************************************** + + @Function OSInstallSystemLISR + + @Description Installs a System ISR + + @Input psSysData + @Input ui32Irq - IRQ number + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSInstallSystemLISR(IMG_VOID *pvSysData, IMG_UINT32 ui32Irq) { SYS_DATA *psSysData = (SYS_DATA*)pvSysData; @@ -773,6 +1083,18 @@ PVRSRV_ERROR OSInstallSystemLISR(IMG_VOID *pvSysData, IMG_UINT32 ui32Irq) } +/*! +****************************************************************************** + + @Function OSUninstallSystemLISR + + @Description Uninstalls a System ISR + + @Input psSysData + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSUninstallSystemLISR(IMG_VOID *pvSysData) { SYS_DATA *psSysData = (SYS_DATA*)pvSysData; @@ -794,6 +1116,18 @@ PVRSRV_ERROR OSUninstallSystemLISR(IMG_VOID *pvSysData) } #if defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE) +/*! +****************************************************************************** + + @Function MISRWrapper + + @Description OS dependent MISR wrapper + + @Input psSysData + + @Return error status + +******************************************************************************/ static void MISRWrapper( #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) void *data @@ -809,6 +1143,18 @@ static void MISRWrapper( } +/*! +****************************************************************************** + + @Function OSInstallMISR + + @Description Installs an OS dependent MISR + + @Input psSysData + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData) { SYS_DATA *psSysData = (SYS_DATA*)pvSysData; @@ -843,6 +1189,18 @@ PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData) } +/*! +****************************************************************************** + + @Function OSUninstallMISR + + @Description Uninstalls an OS dependent MISR + + @Input psSysData + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData) { SYS_DATA *psSysData = (SYS_DATA*)pvSysData; @@ -864,6 +1222,18 @@ PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData) } +/*! +****************************************************************************** + + @Function OSScheduleMISR + + @Description Schedules an OS dependent MISR + + @Input pvSysData + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData) { SYS_DATA *psSysData = (SYS_DATA*)pvSysData; @@ -876,8 +1246,20 @@ PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData) return PVRSRV_OK; } -#else +#else /* defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE) */ #if defined(PVR_LINUX_MISR_USING_WORKQUEUE) +/*! +****************************************************************************** + + @Function MISRWrapper + + @Description OS dependent MISR wrapper + + @Input psSysData + + @Return error status + +******************************************************************************/ static void MISRWrapper( #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) void *data @@ -893,6 +1275,18 @@ static void MISRWrapper( } +/*! +****************************************************************************** + + @Function OSInstallMISR + + @Description Installs an OS dependent MISR + + @Input psSysData + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData) { SYS_DATA *psSysData = (SYS_DATA*)pvSysData; @@ -919,6 +1313,18 @@ PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData) } +/*! +****************************************************************************** + + @Function OSUninstallMISR + + @Description Uninstalls an OS dependent MISR + + @Input psSysData + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData) { SYS_DATA *psSysData = (SYS_DATA*)pvSysData; @@ -940,6 +1346,18 @@ PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData) } +/*! +****************************************************************************** + + @Function OSScheduleMISR + + @Description Schedules an OS dependent MISR + + @Input pvSysData + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData) { SYS_DATA *psSysData = (SYS_DATA*)pvSysData; @@ -953,9 +1371,21 @@ PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData) return PVRSRV_OK; } -#else +#else /* #if defined(PVR_LINUX_MISR_USING_WORKQUEUE) */ +/*! +****************************************************************************** + + @Function MISRWrapper + + @Description OS dependent MISR wrapper + + @Input psSysData + + @Return error status + +******************************************************************************/ static void MISRWrapper(unsigned long data) { SYS_DATA *psSysData; @@ -966,6 +1396,18 @@ static void MISRWrapper(unsigned long data) } +/*! +****************************************************************************** + + @Function OSInstallMISR + + @Description Installs an OS dependent MISR + + @Input psSysData + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData) { SYS_DATA *psSysData = (SYS_DATA*)pvSysData; @@ -987,6 +1429,18 @@ PVRSRV_ERROR OSInstallMISR(IMG_VOID *pvSysData) } +/*! +****************************************************************************** + + @Function OSUninstallMISR + + @Description Uninstalls an OS dependent MISR + + @Input psSysData + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData) { SYS_DATA *psSysData = (SYS_DATA*)pvSysData; @@ -1007,6 +1461,18 @@ PVRSRV_ERROR OSUninstallMISR(IMG_VOID *pvSysData) return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function OSScheduleMISR + + @Description Schedules an OS dependent MISR + + @Input pvSysData + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData) { SYS_DATA *psSysData = (SYS_DATA*)pvSysData; @@ -1020,10 +1486,10 @@ PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData) return PVRSRV_OK; } -#endif -#endif +#endif /* #if defined(PVR_LINUX_MISR_USING_WORKQUEUE) */ +#endif /* #if defined(PVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE) */ -#endif +#endif /* #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) */ IMG_VOID OSPanic(IMG_VOID) { @@ -1035,6 +1501,19 @@ IMG_VOID OSPanic(IMG_VOID) #else #define OS_TAS(p) tas(p) #endif +/*! +****************************************************************************** + + @Function OSLockResource + + @Description locks an OS dependant Resource + + @Input phResource - pointer to OS dependent Resource + @Input bBlock - do we want to block? + + @Return error status + +******************************************************************************/ PVRSRV_ERROR OSLockResource ( PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID) @@ -1050,6 +1529,18 @@ PVRSRV_ERROR OSLockResource ( PVRSRV_RESOURCE *psResource, } +/*! +****************************************************************************** + + @Function OSUnlockResource + + @Description unlocks an OS dependant resource + + @Input phResource - pointer to OS dependent resource structure + + @Return + +******************************************************************************/ PVRSRV_ERROR OSUnlockResource (PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID) { volatile IMG_UINT32 *pui32Access = (volatile IMG_UINT32 *)&psResource->ui32Lock; @@ -1080,6 +1571,18 @@ PVRSRV_ERROR OSUnlockResource (PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID) } +/*! +****************************************************************************** + + @Function OSIsResourceLocked + + @Description tests if resource is locked + + @Input phResource - pointer to OS dependent resource structure + + @Return error status + +******************************************************************************/ IMG_BOOL OSIsResourceLocked (PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID) { volatile IMG_UINT32 *pui32Access = (volatile IMG_UINT32 *)&psResource->ui32Lock; @@ -1101,7 +1604,7 @@ PVRSRV_ERROR OSPowerLockWrap(IMG_BOOL bTryLock) IMG_VOID OSPowerLockUnwrap (IMG_VOID) { } -#endif +#endif /* SYS_CUSTOM_POWERLOCK_WRAP */ IMG_CPU_PHYADDR OSMapLinToCPUPhys(IMG_HANDLE hOSMemHandle, @@ -1114,8 +1617,6 @@ IMG_CPU_PHYADDR OSMapLinToCPUPhys(IMG_HANDLE hOSMemHandle, PVR_ASSERT(hOSMemHandle != IMG_NULL); - - psLinuxMemArea = (LinuxMemArea *)hOSMemHandle; uiByteOffset = (IMG_UINTPTR_T)pvLinAddr - (IMG_UINTPTR_T)LinuxMemAreaToCpuVAddr(psLinuxMemArea); @@ -1127,6 +1628,22 @@ IMG_CPU_PHYADDR OSMapLinToCPUPhys(IMG_HANDLE hOSMemHandle, } +/*! +****************************************************************************** + + @Function OSMapPhysToLin + + @Description Maps the physical memory into linear addr range + + @Input BasePAddr : physical cpu address + + @Input ui32Bytes - bytes to map + + @Input ui32CacheType - cache type + + @Return : Linear addr of mapping on success, else NULL + + ******************************************************************************/ IMG_VOID * OSMapPhysToLin(IMG_CPU_PHYADDR BasePAddr, IMG_UINT32 ui32Bytes, @@ -1135,7 +1652,11 @@ OSMapPhysToLin(IMG_CPU_PHYADDR BasePAddr, { if(ui32MappingFlags & PVRSRV_HAP_KERNEL_ONLY) { - + /* + * Provide some backwards compatibility, until all callers + * have been updated to pass a non-null OSMemHandle pointer. + * Such callers must not call OSMapLinToCPUPhys. + */ if(phOSMemHandle == IMG_NULL) { IMG_VOID *pvIORemapCookie; @@ -1167,6 +1688,12 @@ OSMapPhysToLin(IMG_CPU_PHYADDR BasePAddr, return IMG_NULL; } +/*! +****************************************************************************** + @Function OSUnMapPhysToLin + @Description Unmaps memory that was mapped with OSMapPhysToLin + @Return TRUE on success, else FALSE +******************************************************************************/ IMG_BOOL OSUnMapPhysToLin(IMG_VOID *pvLinAddr, IMG_UINT32 ui32Bytes, IMG_UINT32 ui32MappingFlags, IMG_HANDLE hOSMemHandle) { @@ -1198,6 +1725,12 @@ OSUnMapPhysToLin(IMG_VOID *pvLinAddr, IMG_UINT32 ui32Bytes, IMG_UINT32 ui32Mappi return IMG_FALSE; } +/*! +****************************************************************************** + @Function RegisterExternalMem + @Description Registers external memory for user mode mapping + @Return TRUE on success, else FALSE, MemHandle out +******************************************************************************/ static PVRSRV_ERROR RegisterExternalMem(IMG_SYS_PHYADDR *pBasePAddr, IMG_VOID *pvCPUVAddr, @@ -1233,10 +1766,19 @@ RegisterExternalMem(IMG_SYS_PHYADDR *pBasePAddr, } case PVRSRV_HAP_MULTI_PROCESS: { - + /* Currently PVRSRV_HAP_MULTI_PROCESS implies that we need a kernel + * virtual mapping and potentially multiple user space virtual mappings. + * Beware that the kernel virtual address space is a limited resource. + */ #if defined(VIVT_CACHE) || defined(__sh__) - - ui32MappingFlags &= ~(PVRSRV_HAP_CACHED|PVRSRV_HAP_SMART); + /* + * ARM9 caches are tagged with virtual pages, not physical. As we are going to + * share this memory in different address spaces, we don't want it to be cached. + * ARM11 has physical tagging, so we can cache this memory without fear of virtual + * address aliasing in the TLB, as long as the kernel supports cache colouring for + * VIPT architectures. + */ + ui32MappingFlags &= ~PVRSRV_HAP_CACHED; #endif psLinuxMemArea = NewExternalKVLinuxMemArea(pBasePAddr, pvCPUVAddr, ui32Bytes, bPhysContig, ui32MappingFlags); @@ -1261,6 +1803,13 @@ RegisterExternalMem(IMG_SYS_PHYADDR *pBasePAddr, } +/*! +****************************************************************************** + @Function OSRegisterMem + @Description Registers external memory for user mode mapping + @Output phOSMemHandle - handle to registered memory + @Return TRUE on success, else FALSE +******************************************************************************/ PVRSRV_ERROR OSRegisterMem(IMG_CPU_PHYADDR BasePAddr, IMG_VOID *pvCPUVAddr, @@ -1280,6 +1829,12 @@ PVRSRV_ERROR OSRegisterDiscontigMem(IMG_SYS_PHYADDR *pBasePAddr, IMG_VOID *pvCPU } +/*! +****************************************************************************** + @Function OSUnRegisterMem + @Description UnRegisters external memory for user mode mapping + @Return TRUE on success, else FALSE +******************************************************************************/ PVRSRV_ERROR OSUnRegisterMem (IMG_VOID *pvCpuVAddr, IMG_UINT32 ui32Bytes, @@ -1326,17 +1881,27 @@ PVRSRV_ERROR OSUnRegisterDiscontigMem(IMG_VOID *pvCpuVAddr, IMG_UINT32 ui32Bytes return OSUnRegisterMem(pvCpuVAddr, ui32Bytes, ui32Flags, hOSMemHandle); } +/*! +****************************************************************************** + @Function OSReservePhys + @Description Registers physical memory for user mode mapping + @Output ppvCpuVAddr + @Output phOsMemHandle handle to registered memory + @Return TRUE on success, else FALSE +******************************************************************************/ PVRSRV_ERROR OSReservePhys(IMG_CPU_PHYADDR BasePAddr, IMG_UINT32 ui32Bytes, IMG_UINT32 ui32MappingFlags, + IMG_HANDLE hBMHandle, IMG_VOID **ppvCpuVAddr, IMG_HANDLE *phOSMemHandle) { LinuxMemArea *psLinuxMemArea; #if 0 - + /* For debug: force all OSReservePhys reservations to have a kernel + * virtual address */ if(ui32MappingFlags & PVRSRV_HAP_SINGLE_PROCESS) { ui32MappingFlags &= ~PVRSRV_HAP_SINGLE_PROCESS; @@ -1348,7 +1913,10 @@ OSReservePhys(IMG_CPU_PHYADDR BasePAddr, { case PVRSRV_HAP_KERNEL_ONLY: { - + /* Currently PVRSRV_HAP_KERNEL_ONLY implies that a kernel virtual + * mapping is required for the allocation and no user virtual + * mappings are allowed: Note these eat into our limited kernel + * virtual address space */ psLinuxMemArea = NewIORemapLinuxMemArea(BasePAddr, ui32Bytes, ui32MappingFlags); if(!psLinuxMemArea) { @@ -1358,7 +1926,8 @@ OSReservePhys(IMG_CPU_PHYADDR BasePAddr, } case PVRSRV_HAP_SINGLE_PROCESS: { - + /* Currently this implies that we dont need a kernel virtual + * mapping, but will need a user space virtual mapping */ psLinuxMemArea = NewIOLinuxMemArea(BasePAddr, ui32Bytes, ui32MappingFlags); if(!psLinuxMemArea) { @@ -1369,10 +1938,19 @@ OSReservePhys(IMG_CPU_PHYADDR BasePAddr, } case PVRSRV_HAP_MULTI_PROCESS: { - + /* Currently PVRSRV_HAP_MULTI_PROCESS implies that we need a kernel + * virtual mapping and potentially multiple user space virtual mappings. + * Beware that the kernel virtual address space is a limited resource. + */ #if defined(VIVT_CACHE) || defined(__sh__) - - ui32MappingFlags &= ~(PVRSRV_HAP_CACHED|PVRSRV_HAP_SMART); + /* + * ARM9 caches are tagged with virtual pages, not physical. As we are going to + * share this memory in different address spaces, we don't want it to be cached. + * ARM11 has physical tagging, so we can cache this memory without fear of virtual + * address aliasing in the TLB, as long as the kernel supports cache colouring for + * VIPT architectures. + */ + ui32MappingFlags &= ~PVRSRV_HAP_CACHED; #endif psLinuxMemArea = NewIORemapLinuxMemArea(BasePAddr, ui32Bytes, ui32MappingFlags); if(!psLinuxMemArea) @@ -1389,6 +1967,16 @@ OSReservePhys(IMG_CPU_PHYADDR BasePAddr, return PVRSRV_ERROR_INVALID_FLAGS; } + /* + In case of sparse mapping we need to handle back to the BM as it + knows the mapping info + */ + if (ui32MappingFlags & PVRSRV_MEM_SPARSE) + { + PVR_ASSERT(hBMHandle != IMG_NULL); + psLinuxMemArea->hBMHandle = hBMHandle; + } + *phOSMemHandle = (IMG_HANDLE)psLinuxMemArea; *ppvCpuVAddr = LinuxMemAreaToCpuVAddr(psLinuxMemArea); @@ -1397,6 +1985,12 @@ OSReservePhys(IMG_CPU_PHYADDR BasePAddr, return PVRSRV_OK; } +/*! +****************************************************************************** + @Function OSUnReservePhys + @Description UnRegisters physical memory for user mode mapping + @Return TRUE on success, else FALSE +******************************************************************************/ PVRSRV_ERROR OSUnReservePhys(IMG_VOID *pvCpuVAddr, IMG_UINT32 ui32Bytes, @@ -1441,6 +2035,14 @@ OSUnReservePhys(IMG_VOID *pvCpuVAddr, } +/*! +****************************************************************************** + @Function OSBaseAllocContigMemory + @Description Allocate a block of contiguous virtual non-paged memory. + @Input ui32Size - number of bytes to allocate + @Output ppvLinAddr - pointer to variable that will receive the linear address of buffer + @Return PVRSRV_OK if allocation successed else returns PVRSRV_ERROR_OUT_OF_MEMORY + **************************************************************************/ PVRSRV_ERROR OSBaseAllocContigMemory(IMG_UINT32 ui32Size, IMG_CPU_VIRTADDR *pvLinAddr, IMG_CPU_PHYADDR *psPhysAddr) { #if !defined(NO_HARDWARE) @@ -1451,6 +2053,13 @@ PVRSRV_ERROR OSBaseAllocContigMemory(IMG_UINT32 ui32Size, IMG_CPU_VIRTADDR *pvLi return PVRSRV_ERROR_OUT_OF_MEMORY; #else +/* + * On Linux, the returned virtual address should be used for CPU access, + * and not be remapped into the CPU virtual address using ioremap. The fact + * that the RAM is being managed by the kernel, and already has a virtual + * address, seems to lead to problems when the attributes of the memory are + * changed in the ioremap call (such as from cached to non-cached). + */ IMG_VOID *pvKernLinAddr; #if defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) @@ -1468,10 +2077,16 @@ PVRSRV_ERROR OSBaseAllocContigMemory(IMG_UINT32 ui32Size, IMG_CPU_VIRTADDR *pvLi psPhysAddr->uiAddr = virt_to_phys(pvKernLinAddr); return PVRSRV_OK; -#endif +#endif /* !defined(NO_HARDWARE) */ } +/*! +****************************************************************************** + @Function OSBaseFreeContigMemory + @Description Frees memory allocated with OSBaseAllocContigMemory + @Input LinAddr - pointer to buffer allocated with OSBaseAllocContigMemory + **************************************************************************/ PVRSRV_ERROR OSBaseFreeContigMemory(IMG_UINT32 ui32Size, IMG_CPU_VIRTADDR pvLinAddr, IMG_CPU_PHYADDR psPhysAddr) { #if !defined(NO_HARDWARE) @@ -1489,6 +2104,25 @@ PVRSRV_ERROR OSBaseFreeContigMemory(IMG_UINT32 ui32Size, IMG_CPU_VIRTADDR pvLinA return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function OSWriteHWReg + + @Description + + register access function + + @input pvLinRegBaseAddr : lin addr of register block base + + @input ui32Offset : + + @input ui32Value : + + @Return none + +******************************************************************************/ + IMG_UINT32 OSReadHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset) { #if !defined(NO_HARDWARE) @@ -1509,6 +2143,22 @@ IMG_VOID OSWriteHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UIN #if defined(CONFIG_PCI) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)) +/*! +****************************************************************************** + + @Function OSPCISetDev + + @Description + + Set a PCI device for subsequent use. + + @input pvPCICookie : Pointer to OS specific PCI structure/cookie + + @input eFlags : Flags + + @Return Pointer to PCI device handle + +******************************************************************************/ PVRSRV_PCI_DEV_HANDLE OSPCISetDev(IMG_VOID *pvPCICookie, HOST_PCI_INIT_FLAGS eFlags) { int err; @@ -1534,26 +2184,26 @@ PVRSRV_PCI_DEV_HANDLE OSPCISetDev(IMG_VOID *pvPCICookie, HOST_PCI_INIT_FLAGS eFl return IMG_NULL; } - if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER) + if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER) /* PRQA S 3358 */ /* misuse of enums */ { pci_set_master(psPVRPCI->psPCIDev); } - if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_MSI) + if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_MSI) /* PRQA S 3358 */ /* misuse of enums */ { #if defined(CONFIG_PCI_MSI) err = pci_enable_msi(psPVRPCI->psPCIDev); if (err != 0) { PVR_DPF((PVR_DBG_WARNING, "OSPCISetDev: Couldn't enable MSI (%d)", err)); - psPVRPCI->ePCIFlags &= ~HOST_PCI_INIT_FLAG_MSI; + psPVRPCI->ePCIFlags &= ~HOST_PCI_INIT_FLAG_MSI; /* PRQA S 1474,3358,4130 */ /* misuse of enums */ } #else PVR_DPF((PVR_DBG_WARNING, "OSPCISetDev: MSI support not enabled in the kernel")); #endif } - + /* Initialise the PCI resource tracking array */ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { psPVRPCI->abPCIResourceInUse[i] = IMG_FALSE; @@ -1562,6 +2212,24 @@ PVRSRV_PCI_DEV_HANDLE OSPCISetDev(IMG_VOID *pvPCICookie, HOST_PCI_INIT_FLAGS eFl return (PVRSRV_PCI_DEV_HANDLE)psPVRPCI; } +/*! +****************************************************************************** + + @Function OSPCIAcquireDev + + @Description + + Acquire a PCI device for subsequent use. + + @input ui16VendorID : Vendor PCI ID + + @input ui16VendorID : Device PCI ID + + @input eFlags : Flags + + @Return PVESRV_ERROR + +******************************************************************************/ PVRSRV_PCI_DEV_HANDLE OSPCIAcquireDev(IMG_UINT16 ui16VendorID, IMG_UINT16 ui16DeviceID, HOST_PCI_INIT_FLAGS eFlags) { struct pci_dev *psPCIDev; @@ -1576,6 +2244,22 @@ PVRSRV_PCI_DEV_HANDLE OSPCIAcquireDev(IMG_UINT16 ui16VendorID, IMG_UINT16 ui16De return OSPCISetDev((IMG_VOID *)psPCIDev, eFlags); } +/*! +****************************************************************************** + + @Function OSPCIIRQ + + @Description + + Get the interrupt number for the device. + + @input hPVRPCI : PCI device handle + + @input pui32IRQ : Pointer to where the interrupt number should be returned + + @Return PVESRV_ERROR + +******************************************************************************/ PVRSRV_ERROR OSPCIIRQ(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 *pui32IRQ) { PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI; @@ -1585,6 +2269,7 @@ PVRSRV_ERROR OSPCIIRQ(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 *pui32IRQ) return PVRSRV_OK; } +/* Functions supported by OSPCIAddrRangeFunc */ enum HOST_PCI_ADDR_RANGE_FUNC { HOST_PCI_ADDR_RANGE_FUNC_LEN, @@ -1594,6 +2279,24 @@ enum HOST_PCI_ADDR_RANGE_FUNC HOST_PCI_ADDR_RANGE_FUNC_RELEASE }; +/*! +****************************************************************************** + + @Function OSPCIAddrRangeFunc + + @Description + + Internal support function for various address range related functions + + @input eFunc : Function to perform + + @input hPVRPCI : PCI device handle + + @input ui32Index : Address range index + + @Return function dependent + +******************************************************************************/ static IMG_UINT32 OSPCIAddrRangeFunc(enum HOST_PCI_ADDR_RANGE_FUNC eFunc, PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index) @@ -1643,32 +2346,126 @@ static IMG_UINT32 OSPCIAddrRangeFunc(enum HOST_PCI_ADDR_RANGE_FUNC eFunc, return 0; } +/*! +****************************************************************************** + + @Function OSPCIAddrRangeLen + + @Description + + Returns length of a given address range length + + @input hPVRPCI : PCI device handle + + @input ui32Index : Address range index + + @Return Length of address range, or 0 if no such range + +******************************************************************************/ IMG_UINT32 OSPCIAddrRangeLen(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index) { return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_LEN, hPVRPCI, ui32Index); } +/*! +****************************************************************************** + + @Function OSPCIAddrRangeStart + + @Description + + Returns the start of a given address range + + @input hPVRPCI : PCI device handle + + @input ui32Index : Address range index + + @Return Start of address range, or 0 if no such range + +******************************************************************************/ IMG_UINT32 OSPCIAddrRangeStart(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index) { return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_START, hPVRPCI, ui32Index); } +/*! +****************************************************************************** + + @Function OSPCIAddrRangeEnd + + @Description + + Returns the end of a given address range + + @input hPVRPCI : PCI device handle"ayy + + @input ui32Index : Address range index + + @Return End of address range, or 0 if no such range + +******************************************************************************/ IMG_UINT32 OSPCIAddrRangeEnd(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index) { return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_END, hPVRPCI, ui32Index); } +/*! +****************************************************************************** + + @Function OSPCIRequestAddrRange + + @Description + + Request a given address range index for subsequent use + + @input hPVRPCI : PCI device handle + + @input ui32Index : Address range index + + @Return PVESRV_ERROR + +******************************************************************************/ PVRSRV_ERROR OSPCIRequestAddrRange(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index) { return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_REQUEST, hPVRPCI, ui32Index) == 0 ? PVRSRV_ERROR_PCI_CALL_FAILED : PVRSRV_OK; } +/*! +****************************************************************************** + + @Function OSPCIReleaseAddrRange + + @Description + + Release a given address range that is no longer being used + + @input hPVRPCI : PCI device handle + + @input ui32Index : Address range index + + @Return PVESRV_ERROR + +******************************************************************************/ PVRSRV_ERROR OSPCIReleaseAddrRange(PVRSRV_PCI_DEV_HANDLE hPVRPCI, IMG_UINT32 ui32Index) { return OSPCIAddrRangeFunc(HOST_PCI_ADDR_RANGE_FUNC_RELEASE, hPVRPCI, ui32Index) == 0 ? PVRSRV_ERROR_PCI_CALL_FAILED : PVRSRV_OK; } +/*! +****************************************************************************** + + @Function OSPCIReleaseDev + + @Description + + Release a PCI device that is no longer being used + + @input hPVRPCI : PCI device handle + + @Return PVESRV_ERROR + +******************************************************************************/ PVRSRV_ERROR OSPCIReleaseDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI) { PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI; @@ -1676,7 +2473,7 @@ PVRSRV_ERROR OSPCIReleaseDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI) PVR_TRACE(("OSPCIReleaseDev")); - + /* Release all PCI regions that are currently in use */ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { if (psPVRPCI->abPCIResourceInUse[i]) @@ -1688,14 +2485,14 @@ PVRSRV_ERROR OSPCIReleaseDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI) } #if defined(CONFIG_PCI_MSI) - if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_MSI) + if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_MSI) /* PRQA S 3358 */ /* misuse of enums */ { pci_disable_msi(psPVRPCI->psPCIDev); } #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) - if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER) + if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER) /* PRQA S 3358 */ /* misuse of enums */ { pci_clear_master(psPVRPCI->psPCIDev); } @@ -1703,11 +2500,25 @@ PVRSRV_ERROR OSPCIReleaseDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI) pci_disable_device(psPVRPCI->psPCIDev); OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psPVRPCI), (IMG_VOID *)psPVRPCI, IMG_NULL); - + /*not nulling pointer, copy on stack*/ return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function OSPCISuspendDev + + @Description + + Prepare PCI device to be turned off by power management + + @input hPVRPCI : PCI device handle + + @Return PVESRV_ERROR + +******************************************************************************/ PVRSRV_ERROR OSPCISuspendDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI) { PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI; @@ -1716,7 +2527,7 @@ PVRSRV_ERROR OSPCISuspendDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI) PVR_TRACE(("OSPCISuspendDev")); - + /* Release all PCI regions that are currently in use */ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { if (psPVRPCI->abPCIResourceInUse[i]) @@ -1753,6 +2564,24 @@ PVRSRV_ERROR OSPCISuspendDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI) return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function OSPCIResumeDev + + @Description + + Prepare a PCI device to be resumed by power management + + @input hPVRPCI : PCI device handle + + @input pvPCICookie : Pointer to OS specific PCI structure/cookie + + @input eFlags : Flags + + @Return PVESRV_ERROR + +******************************************************************************/ PVRSRV_ERROR OSPCIResumeDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI) { PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI; @@ -1795,10 +2624,10 @@ PVRSRV_ERROR OSPCIResumeDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI) return PVRSRV_ERROR_PCI_CALL_FAILED; } - if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER) + if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER) /* PRQA S 3358 */ /* misuse of enums */ pci_set_master(psPVRPCI->psPCIDev); - + /* Restore the PCI resource tracking array */ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { if (psPVRPCI->abPCIResourceInUse[i]) @@ -1815,10 +2644,11 @@ PVRSRV_ERROR OSPCIResumeDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI) return PVRSRV_OK; } -#endif +#endif /* #if defined(CONFIG_PCI) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) */ #define OS_MAX_TIMERS 8 +/* Timer callback strucure used by OSAddTimer */ typedef struct TIMER_CALLBACK_DATA_TAG { IMG_BOOL bInUse; @@ -1842,9 +2672,11 @@ static TIMER_CALLBACK_DATA sTimers[OS_MAX_TIMERS]; DEFINE_MUTEX(sTimerStructLock); #else #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)) +/* The lock is used to control access to sTimers */ +/* PRQA S 0671,0685 1 */ /* C99 macro not understood by QAC */ static spinlock_t sTimerStructLock = SPIN_LOCK_UNLOCKED; #else -static spinlock_t sTimerStructLock = __SPIN_LOCK_UNLOCKED(sTimerStructLock); +static DEFINE_SPINLOCK(sTimerStructLock); #endif #endif @@ -1853,14 +2685,28 @@ static void OSTimerCallbackBody(TIMER_CALLBACK_DATA *psTimerCBData) if (!psTimerCBData->bActive) return; - + /* call timer callback */ psTimerCBData->pfnTimerFunc(psTimerCBData->pvData); - + /* reset timer */ mod_timer(&psTimerCBData->sTimer, psTimerCBData->ui32Delay + jiffies); } +/*! +****************************************************************************** + + @Function OSTimerCallbackWrapper + + @Description + + OS specific timer callback wrapper function + + @Input ui32Data : timer callback data + + @Return NONE + +******************************************************************************/ static IMG_VOID OSTimerCallbackWrapper(IMG_UINT32 ui32Data) { TIMER_CALLBACK_DATA *psTimerCBData = (TIMER_CALLBACK_DATA*)ui32Data; @@ -1892,6 +2738,24 @@ static void OSTimerWorkQueueCallBack(struct work_struct *psWork) } #endif +/*! +****************************************************************************** + + @Function OSAddTimer + + @Description + + OS specific function to install a timer callback + + @Input pfnTimerFunc : timer callback + + @Input *pvData :callback data + + @Input ui32MsTimeout: callback period + + @Return IMG_HANDLE : valid handle success, NULL failure + +******************************************************************************/ IMG_HANDLE OSAddTimer(PFN_TIMER_FUNC pfnTimerFunc, IMG_VOID *pvData, IMG_UINT32 ui32MsTimeout) { TIMER_CALLBACK_DATA *psTimerCBData; @@ -1900,14 +2764,14 @@ IMG_HANDLE OSAddTimer(PFN_TIMER_FUNC pfnTimerFunc, IMG_VOID *pvData, IMG_UINT32 unsigned long ulLockFlags; #endif - + /* check callback */ if(!pfnTimerFunc) { PVR_DPF((PVR_DBG_ERROR, "OSAddTimer: passed invalid callback")); return IMG_NULL; } - + /* Allocate timer callback data structure */ #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) || defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE) mutex_lock(&sTimerStructLock); #else @@ -1937,17 +2801,19 @@ IMG_HANDLE OSAddTimer(PFN_TIMER_FUNC pfnTimerFunc, IMG_VOID *pvData, IMG_UINT32 psTimerCBData->pvData = pvData; psTimerCBData->bActive = IMG_FALSE; - - - + /* + HZ = ticks per second + ui32MsTimeout = required ms delay + ticks = (Hz * ui32MsTimeout) / 1000 + */ psTimerCBData->ui32Delay = ((HZ * ui32MsTimeout) < 1000) ? 1 : ((HZ * ui32MsTimeout) / 1000); - + /* initialise object */ init_timer(&psTimerCBData->sTimer); - - + /* setup timer object */ + /* PRQA S 0307,0563 1 */ /* ignore warning about inconpartible ptr casting */ psTimerCBData->sTimer.function = (IMG_VOID *)OSTimerCallbackWrapper; psTimerCBData->sTimer.data = (IMG_UINT32)psTimerCBData; @@ -1964,6 +2830,20 @@ static inline TIMER_CALLBACK_DATA *GetTimerStructure(IMG_HANDLE hTimer) return &sTimers[ui32i]; } +/*! +****************************************************************************** + + @Function OSRemoveTimer + + @Description + + OS specific function to remove a timer callback + + @Input hTimer : timer handle + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR OSRemoveTimer (IMG_HANDLE hTimer) { TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer); @@ -1971,13 +2851,27 @@ PVRSRV_ERROR OSRemoveTimer (IMG_HANDLE hTimer) PVR_ASSERT(psTimerCBData->bInUse); PVR_ASSERT(!psTimerCBData->bActive); - + /* free timer callback data struct */ psTimerCBData->bInUse = IMG_FALSE; return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function OSEnableTimer + + @Description + + OS specific function to enable a timer callback + + @Input hTimer : timer handle + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR OSEnableTimer (IMG_HANDLE hTimer) { TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer); @@ -1985,19 +2879,33 @@ PVRSRV_ERROR OSEnableTimer (IMG_HANDLE hTimer) PVR_ASSERT(psTimerCBData->bInUse); PVR_ASSERT(!psTimerCBData->bActive); - + /* Start timer arming */ psTimerCBData->bActive = IMG_TRUE; - + /* set the expire time */ psTimerCBData->sTimer.expires = psTimerCBData->ui32Delay + jiffies; - + /* Add the timer to the list */ add_timer(&psTimerCBData->sTimer); return PVRSRV_OK; } +/*! +****************************************************************************** + + @Function OSDisableTimer + + @Description + + OS specific function to disable a timer callback + + @Input hTimer : timer handle + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR OSDisableTimer (IMG_HANDLE hTimer) { TIMER_CALLBACK_DATA *psTimerCBData = GetTimerStructure(hTimer); @@ -2005,7 +2913,7 @@ PVRSRV_ERROR OSDisableTimer (IMG_HANDLE hTimer) PVR_ASSERT(psTimerCBData->bInUse); PVR_ASSERT(psTimerCBData->bActive); - + /* Stop timer from arming */ psTimerCBData->bActive = IMG_FALSE; smp_mb(); @@ -2016,11 +2924,17 @@ PVRSRV_ERROR OSDisableTimer (IMG_HANDLE hTimer) flush_scheduled_work(); #endif - + /* remove timer */ del_timer_sync(&psTimerCBData->sTimer); #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) - + /* + * This second flush is to catch the case where the timer ran + * before we managed to delete it, in which case, it will have + * queued more work for the workqueue. Since the bActive flag + * has been cleared, this second flush won't result in the + * timer being rearmed. + */ flush_workqueue(psTimerWorkQueue); #endif #if defined(PVR_LINUX_TIMERS_USING_SHARED_WORKQUEUE) @@ -2031,6 +2945,22 @@ PVRSRV_ERROR OSDisableTimer (IMG_HANDLE hTimer) } +/*! +****************************************************************************** + + @Function OSEventObjectCreateKM + + @Description + + OS specific function to create an event object + + @Input pszName : Globally unique event object name (if null name must be autogenerated) + + @Output psEventObject : OS event object info structure + + @Return PVRSRV_ERROR : + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR OSEventObjectCreateKM(const IMG_CHAR *pszName, PVRSRV_EVENTOBJECT_KM *psEventObject) #else @@ -2044,12 +2974,12 @@ PVRSRV_ERROR OSEventObjectCreateKM(const IMG_CHAR *pszName, PVRSRV_EVENTOBJECT * { if(pszName) { - + /* copy over the event object name */ strncpy(psEventObject->szName, pszName, EVENTOBJNAME_MAXLENGTH); } else { - + /* autogenerate a name */ static IMG_UINT16 ui16NameIndex = 0; #if defined (SUPPORT_SID_INTERFACE) snprintf(psEventObject->szName, EVENTOBJNAME_MAXLENGTH, "PVRSRV_EVENTOBJECT_KM_%d", ui16NameIndex++); @@ -2075,6 +3005,20 @@ PVRSRV_ERROR OSEventObjectCreateKM(const IMG_CHAR *pszName, PVRSRV_EVENTOBJECT * } +/*! +****************************************************************************** + + @Function OSEventObjectDestroyKM + + @Description + + OS specific function to destroy an event object + + @Input psEventObject : OS event object info structure + + @Return PVRSRV_ERROR : + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR OSEventObjectDestroyKM(PVRSRV_EVENTOBJECT_KM *psEventObject) #else @@ -2104,6 +3048,20 @@ PVRSRV_ERROR OSEventObjectDestroyKM(PVRSRV_EVENTOBJECT *psEventObject) return eError; } +/*! +****************************************************************************** + + @Function OSEventObjectWaitKM + + @Description + + OS specific function to wait for an event object. Called from client + + @Input hOSEventKM : OS and kernel specific handle to event object + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR OSEventObjectWaitKM(IMG_HANDLE hOSEventKM) { PVRSRV_ERROR eError; @@ -2121,6 +3079,21 @@ PVRSRV_ERROR OSEventObjectWaitKM(IMG_HANDLE hOSEventKM) return eError; } +/*! +****************************************************************************** + + @Function OSEventObjectOpenKM + + @Description + + OS specific function to open an event object. Called from client + + @Input psEventObject : Pointer to an event object + @Output phOSEvent : OS and kernel specific handle to event object + + @Return PVRSRV_ERROR : + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR OSEventObjectOpenKM(PVRSRV_EVENTOBJECT_KM *psEventObject, #else @@ -2148,6 +3121,22 @@ PVRSRV_ERROR OSEventObjectOpenKM(PVRSRV_EVENTOBJECT *psEventObject, return eError; } +/*! +****************************************************************************** + + @Function OSEventObjectCloseKM + + @Description + + OS specific function to close an event object. Called from client + + @Input psEventObject : Pointer to an event object + @OInput hOSEventKM : OS and kernel specific handle to event object + + + @Return PVRSRV_ERROR : + +******************************************************************************/ #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR OSEventObjectCloseKM(PVRSRV_EVENTOBJECT_KM *psEventObject, #else @@ -2176,6 +3165,20 @@ PVRSRV_ERROR OSEventObjectCloseKM(PVRSRV_EVENTOBJECT *psEventObject, } +/*! +****************************************************************************** + + @Function OSEventObjectSignalKM + + @Description + + OS specific function to 'signal' an event object. Called from L/MISR + + @Input hOSEventKM : OS and kernel specific handle to event object + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR OSEventObjectSignalKM(IMG_HANDLE hOSEventKM) { PVRSRV_ERROR eError; @@ -2193,11 +3196,43 @@ PVRSRV_ERROR OSEventObjectSignalKM(IMG_HANDLE hOSEventKM) return eError; } +/*! +****************************************************************************** + + @Function OSProcHasPrivSrvInit + + @Description + + Does the process have sufficient privileges to initialise services? + + @Input none + + @Return IMG_BOOL : + +******************************************************************************/ IMG_BOOL OSProcHasPrivSrvInit(IMG_VOID) { return (capable(CAP_SYS_MODULE) != 0) ? IMG_TRUE : IMG_FALSE; } +/*! +****************************************************************************** + + @Function OSCopyToUser + + @Description + + Copy a block of data into user space + + @Input pvSrc + + @Output pvDest + + @Input ui32Bytes + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR OSCopyToUser(IMG_PVOID pvProcess, IMG_VOID *pvDest, IMG_VOID *pvSrc, @@ -2211,6 +3246,24 @@ PVRSRV_ERROR OSCopyToUser(IMG_PVOID pvProcess, return PVRSRV_ERROR_FAILED_TO_COPY_VIRT_MEMORY; } +/*! +****************************************************************************** + + @Function OSCopyFromUser + + @Description + + Copy a block of data from the user space + + @Output pvDest + + @Input pvSrc + + @Input ui32Bytes + + @Return PVRSRV_ERROR : + +******************************************************************************/ PVRSRV_ERROR OSCopyFromUser( IMG_PVOID pvProcess, IMG_VOID *pvDest, IMG_VOID *pvSrc, @@ -2224,6 +3277,24 @@ PVRSRV_ERROR OSCopyFromUser( IMG_PVOID pvProcess, return PVRSRV_ERROR_FAILED_TO_COPY_VIRT_MEMORY; } +/*! +****************************************************************************** + + @Function OSAccessOK + + @Description + + Checks if a user space pointer is valide + + @Input eVerification + + @Input pvUserPtr + + @Input ui32Bytes + + @Return IMG_BOOL : + +******************************************************************************/ IMG_BOOL OSAccessOK(IMG_VERIFY_TEST eVerification, IMG_VOID *pvUserPtr, IMG_UINT32 ui32Bytes) { IMG_INT linuxType; @@ -2264,6 +3335,28 @@ typedef struct _sWrapMemInfo_ } sWrapMemInfo; +/*! +****************************************************************************** + + @Function *CPUVAddrToPFN + + @Description + + Find the PFN associated with a given CPU virtual address, and return + the associated page structure, if it exists. + The page in question must be present (i.e. no fault handling required), + and must be writable. A get_page is done on the returned page structure. + + @Input psVMArea - pointer to VM area structure + ulCPUVAddr - CPU virtual address + pulPFN - Pointer to returned PFN. + ppsPAge - Pointer to returned page structure pointer. + + @Output *pulPFN - Set to PFN + *ppsPage - Pointer to the page structure if present, else NULL. + @Return IMG_TRUE if PFN lookup was succesful. + +******************************************************************************/ static IMG_BOOL CPUVAddrToPFN(struct vm_area_struct *psVMArea, IMG_UINT32 ulCPUVAddr, IMG_UINT32 *pulPFN, struct page **ppsPage) { #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)) @@ -2313,6 +3406,20 @@ static IMG_BOOL CPUVAddrToPFN(struct vm_area_struct *psVMArea, IMG_UINT32 ulCPUV #endif } +/*! +****************************************************************************** + + @Function OSReleasePhysPageAddr + + @Description + + Release wrapped memory. + + @Input hOSWrapMem : Driver cookie + + @Return PVRSRV_ERROR + +******************************************************************************/ PVRSRV_ERROR OSReleasePhysPageAddr(IMG_HANDLE hOSWrapMem) { sWrapMemInfo *psInfo = (sWrapMemInfo *)hOSWrapMem; @@ -2341,7 +3448,12 @@ PVRSRV_ERROR OSReleasePhysPageAddr(IMG_HANDLE hOSWrapMem) PVR_ASSERT(psPage != NULL); - + /* + * If the number of pages mapped is not the same as + * the number of pages in the address range, then + * get_user_pages must have failed, so we are cleaning + * up after failure, and the pages can't be dirty. + */ if (psInfo->iNumPagesMapped == psInfo->iNumPages) { if (!PageReserved(psPage)) @@ -2387,6 +3499,59 @@ PVRSRV_ERROR OSReleasePhysPageAddr(IMG_HANDLE hOSWrapMem) return PVRSRV_OK; } +#if defined(CONFIG_TI_TILER) + +static IMG_UINT32 CPUAddrToTilerPhy(IMG_UINT32 uiAddr) +{ + IMG_UINT32 ui32PhysAddr = 0; + pte_t *ptep, pte; + pgd_t *pgd; + pmd_t *pmd; + + pgd = pgd_offset(current->mm, uiAddr); + if (pgd_none(*pgd) || pgd_bad(*pgd)) + goto err_out; + + pmd = pmd_offset(pgd, uiAddr); + if (pmd_none(*pmd) || pmd_bad(*pmd)) + goto err_out; + + ptep = pte_offset_map(pmd, uiAddr); + if (!ptep) + goto err_out; + + pte = *ptep; + if (!pte_present(pte)) + goto err_out; + + ui32PhysAddr = (pte & PAGE_MASK) | (~PAGE_MASK & uiAddr); + + /* If the physAddr is not in the TILER physical range + * then we don't proceed. + */ + if (ui32PhysAddr < 0x60000000 && ui32PhysAddr > 0x7fffffff) + { + PVR_DPF((PVR_DBG_ERROR, "CPUAddrToTilerPhy: Not in tiler range")); + ui32PhysAddr = 0; + goto err_out; + } + +err_out: + return ui32PhysAddr; +} + +#endif /* defined(CONFIG_TI_TILER) */ + +/*! +****************************************************************************** + + @Function OSAcquirePhysPageAddr + + @Description + + @Return PVRSRV_ERROR + +******************************************************************************/ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, IMG_UINT32 ui32Bytes, IMG_SYS_PHYADDR *psSysPAddr, @@ -2404,16 +3569,18 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, sWrapMemInfo *psInfo = NULL; IMG_BOOL bHavePageStructs = IMG_FALSE; IMG_BOOL bHaveNoPageStructs = IMG_FALSE; - IMG_BOOL bPFNMismatch = IMG_FALSE; IMG_BOOL bMMapSemHeld = IMG_FALSE; PVRSRV_ERROR eError = PVRSRV_ERROR_OUT_OF_MEMORY; - + /* Align start and end addresses to page boundaries */ ulStartAddr = ulStartAddrOrig & PAGE_MASK; ulBeyondEndAddr = PAGE_ALIGN(ulBeyondEndAddrOrig); ulAddrRange = ulBeyondEndAddr - ulStartAddr; - + /* + * Check for address range calculation overflow, and attempts to wrap + * zero bytes. + */ if (ulBeyondEndAddr <= ulStartAddr) { PVR_DPF((PVR_DBG_ERROR, @@ -2422,7 +3589,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, goto error; } - + /* Allocate information structure */ psInfo = kmalloc(sizeof(*psInfo), GFP_KERNEL); if (psInfo == NULL) { @@ -2440,7 +3607,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, psInfo->iNumPages = (IMG_INT)(ulAddrRange >> PAGE_SHIFT); psInfo->iPageOffset = (IMG_INT)(ulStartAddrOrig & ~PAGE_MASK); - + /* Allocate physical address array */ psInfo->psPhysAddr = kmalloc((size_t)psInfo->iNumPages * sizeof(*psInfo->psPhysAddr), GFP_KERNEL); if (psInfo->psPhysAddr == NULL) { @@ -2450,7 +3617,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, } memset(psInfo->psPhysAddr, 0, (size_t)psInfo->iNumPages * sizeof(*psInfo->psPhysAddr)); - + /* Allocate page array */ psInfo->ppsPages = kmalloc((size_t)psInfo->iNumPages * sizeof(*psInfo->ppsPages), GFP_KERNEL); if (psInfo->ppsPages == NULL) { @@ -2460,22 +3627,22 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, } memset(psInfo->ppsPages, 0, (size_t)psInfo->iNumPages * sizeof(*psInfo->ppsPages)); - + /* Default error code from now on */ eError = PVRSRV_ERROR_BAD_MAPPING; - + /* Set the mapping type to aid clean up */ psInfo->eType = WRAP_TYPE_GET_USER_PAGES; - + /* Lock down user memory */ down_read(¤t->mm->mmap_sem); bMMapSemHeld = IMG_TRUE; - + /* Get page list */ psInfo->iNumPagesMapped = get_user_pages(current, current->mm, ulStartAddr, psInfo->iNumPages, 1, 0, psInfo->ppsPages, NULL); if (psInfo->iNumPagesMapped >= 0) { - + /* See if we got all the pages we wanted */ if (psInfo->iNumPagesMapped != psInfo->iNumPages) { PVR_TRACE(("OSAcquirePhysPageAddr: Couldn't map all the pages needed (wanted: %d, got %d)", psInfo->iNumPages, psInfo->iNumPagesMapped)); @@ -2483,7 +3650,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, goto error; } - + /* Build list of physical page addresses */ for (i = 0; i < psInfo->iNumPages; i++) { IMG_CPU_PHYADDR CPUPhysAddr; @@ -2508,13 +3675,18 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, PVR_DPF((PVR_DBG_MESSAGE, "OSAcquirePhysPageAddr: get_user_pages failed (%d), using CPU page table", psInfo->iNumPagesMapped)); - + /* Reset some fields */ psInfo->eType = WRAP_TYPE_NULL; psInfo->iNumPagesMapped = 0; memset(psInfo->ppsPages, 0, (size_t)psInfo->iNumPages * sizeof(*psInfo->ppsPages)); - - + /* + * get_user_pages didn't work. If this is due to the address range + * representing memory mapped I/O, then we'll look for the pages + * in the appropriate memory region of the process. + */ + + /* Set the mapping type to aid clean up */ psInfo->eType = WRAP_TYPE_FIND_VMA; psVMArea = find_vma(current->mm, ulStartAddrOrig); @@ -2529,7 +3701,10 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, psInfo->psVMArea = psVMArea; #endif - + /* + * find_vma locates a region with an end point past a given + * virtual address. So check the address is actually in the region. + */ if (ulStartAddrOrig < psVMArea->vm_start) { PVR_DPF((PVR_DBG_ERROR, @@ -2537,7 +3712,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, goto error; } - + /* Now check the end address is in range */ if (ulBeyondEndAddrOrig > psVMArea->vm_end) { PVR_DPF((PVR_DBG_ERROR, @@ -2545,7 +3720,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, goto error; } - + /* Does the region represent memory mapped I/O? */ if ((psVMArea->vm_flags & (VM_IO | VM_RESERVED)) != (VM_IO | VM_RESERVED)) { PVR_DPF((PVR_DBG_ERROR, @@ -2553,7 +3728,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, goto error; } - + /* We require read and write access */ if ((psVMArea->vm_flags & (VM_READ | VM_WRITE)) != (VM_READ | VM_WRITE)) { PVR_DPF((PVR_DBG_ERROR, @@ -2577,20 +3752,20 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, } if (psInfo->ppsPages[i] == NULL) { +#if defined(CONFIG_TI_TILER) + /* This could be tiler memory.*/ + IMG_UINT32 ui32TilerAddr = CPUAddrToTilerPhy(ulAddr); + if (ui32TilerAddr) + { + bHavePageStructs = IMG_TRUE; + psInfo->iNumPagesMapped++; + psInfo->psPhysAddr[i].uiAddr = ui32TilerAddr; + psSysPAddr[i].uiAddr = ui32TilerAddr; + continue; + } +#endif /* defined(CONFIG_TI_TILER) */ bHaveNoPageStructs = IMG_TRUE; - -#if defined(VM_PFNMAP) - if ((psVMArea->vm_flags & VM_PFNMAP) != 0) - { - IMG_UINT32 ulPFNRaw = ((ulAddr - psVMArea->vm_start) >> PAGE_SHIFT) + psVMArea->vm_pgoff; - - if (ulPFNRaw != ulPFN) - { - bPFNMismatch = IMG_TRUE; - } - } -#endif } else { @@ -2631,7 +3806,7 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, if (!bHaveNoPageStructs) { - + /* The ideal case; every page has a page structure */ goto exit; } @@ -2644,34 +3819,21 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr, goto error; } - if (bPFNMismatch) - { - PVR_DPF((PVR_DBG_ERROR, - "OSAcquirePhysPageAddr: PFN calculation mismatch for VM_PFNMAP region")); - goto error; - } - exit: PVR_ASSERT(bMMapSemHeld); up_read(¤t->mm->mmap_sem); - + /* Return the cookie */ *phOSWrapMem = (IMG_HANDLE)psInfo; if (bHaveNoPageStructs) { - PVR_DPF((PVR_DBG_WARNING, + PVR_DPF((PVR_DBG_MESSAGE, "OSAcquirePhysPageAddr: Region contains pages which can't be locked down (no page structures)")); } PVR_ASSERT(psInfo->eType != 0); -#if 0 - - - OSCleanCPUCacheRangeKM(pvCPUVAddr, (IMG_VOID *)((IMG_CHAR *)pvCPUVAddr + ui32Bytes)); -#endif - return PVRSRV_OK; error: @@ -2687,52 +3849,96 @@ error: } typedef void (*InnerCacheOp_t)(const void *pvStart, const void *pvEnd); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)) -typedef void (*OuterCacheOp_t)(unsigned long ulStart, unsigned long ulEnd); + +#if defined(__arm__) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)) +typedef void (*OuterCacheOp_t)(phys_addr_t uStart, phys_addr_t uEnd); #else -typedef void (*OuterCacheOp_t)(phys_addr_t ulStart, phys_addr_t ulEnd); +typedef void (*OuterCacheOp_t)(unsigned long ulStart, unsigned long ulEnd); #endif #if defined(CONFIG_OUTER_CACHE) -typedef unsigned long (*MemAreaToPhys_t)(LinuxMemArea *psLinuxMemArea, +typedef IMG_BOOL (*MemAreaToPhys_t)(LinuxMemArea *psLinuxMemArea, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32PageNumOffset, - IMG_UINT32 ui32PageNum); + IMG_UINT32 ui32PageNum, + unsigned long *pulStart); -static unsigned long VMallocAreaToPhys(LinuxMemArea *psLinuxMemArea, - IMG_VOID *pvRangeAddrStart, - IMG_UINT32 ui32PageNumOffset, - IMG_UINT32 ui32PageNum) +static IMG_BOOL VMallocAreaToPhys(LinuxMemArea *psLinuxMemArea, + IMG_VOID *pvRangeAddrStart, + IMG_UINT32 ui32PageNumOffset, + IMG_UINT32 ui32PageNum, + unsigned long *pulStart) { - return vmalloc_to_pfn(pvRangeAddrStart + ui32PageNum * PAGE_SIZE) << PAGE_SHIFT; + *pulStart = vmalloc_to_pfn(pvRangeAddrStart + ui32PageNum * PAGE_SIZE) << PAGE_SHIFT; + return IMG_TRUE; } -static unsigned long ExternalKVAreaToPhys(LinuxMemArea *psLinuxMemArea, - IMG_VOID *pvRangeAddrStart, - IMG_UINT32 ui32PageNumOffset, - IMG_UINT32 ui32PageNum) +static IMG_BOOL ExternalKVAreaToPhys(LinuxMemArea *psLinuxMemArea, + IMG_VOID *pvRangeAddrStart, + IMG_UINT32 ui32PageNumOffset, + IMG_UINT32 ui32PageNum, + unsigned long *pulStart) { IMG_SYS_PHYADDR SysPAddr; IMG_CPU_PHYADDR CpuPAddr; SysPAddr = psLinuxMemArea->uData.sExternalKV.uPhysAddr.pSysPhysAddr[ui32PageNumOffset + ui32PageNum]; CpuPAddr = SysSysPAddrToCpuPAddr(SysPAddr); - return CpuPAddr.uiAddr; + *pulStart = CpuPAddr.uiAddr; + return IMG_TRUE; } -static unsigned long AllocPagesAreaToPhys(LinuxMemArea *psLinuxMemArea, - IMG_VOID *pvRangeAddrStart, - IMG_UINT32 ui32PageNumOffset, - IMG_UINT32 ui32PageNum) +static IMG_BOOL AllocPagesAreaToPhys(LinuxMemArea *psLinuxMemArea, + IMG_VOID *pvRangeAddrStart, + IMG_UINT32 ui32PageNumOffset, + IMG_UINT32 ui32PageNum, + unsigned long *pulStart) { struct page *pPage; - pPage = psLinuxMemArea->uData.sPageList.pvPageList[ui32PageNumOffset + ui32PageNum]; - return page_to_pfn(pPage) << PAGE_SHIFT; + + pPage = psLinuxMemArea->uData.sPageList.ppsPageList[ui32PageNumOffset + ui32PageNum]; + *pulStart = page_to_pfn(pPage) << PAGE_SHIFT; + return IMG_TRUE; } -#endif +static IMG_BOOL AllocPagesSparseAreaToPhys(LinuxMemArea *psLinuxMemArea, + IMG_VOID *pvRangeAddrStart, + IMG_UINT32 ui32PageNumOffset, + IMG_UINT32 ui32PageNum, + unsigned long *pulStart) +{ + IMG_UINT32 ui32VirtOffset = (ui32PageNumOffset + ui32PageNum) << PAGE_SHIFT; + IMG_UINT32 ui32PhysOffset; + struct page *pPage; + + if (BM_VirtOffsetToPhysical(psLinuxMemArea->hBMHandle, ui32VirtOffset, &ui32PhysOffset)) + { + PVR_ASSERT(ui32PhysOffset <= ui32VirtOffset); + pPage = psLinuxMemArea->uData.sPageList.ppsPageList[ui32PhysOffset >> PAGE_SHIFT]; + *pulStart = page_to_pfn(pPage) << PAGE_SHIFT; + return IMG_TRUE; + } + + return IMG_FALSE; +} + + +static IMG_BOOL IONAreaToPhys(LinuxMemArea *psLinuxMemArea, + IMG_VOID *pvRangeAddrStart, + IMG_UINT32 ui32PageNumOffset, + IMG_UINT32 ui32PageNum, + unsigned long *pulStart) +{ + IMG_CPU_PHYADDR CpuPAddr; + CpuPAddr = psLinuxMemArea->uData.sIONTilerAlloc.pCPUPhysAddrs[ui32PageNumOffset + ui32PageNum]; + *pulStart = CpuPAddr.uiAddr; + return IMG_TRUE; +} + +#endif /* defined(CONFIG_OUTER_CACHE) */ + +/* g_sMMapMutex must be held while this function is called */ -#ifndef __mips__ static IMG_VOID *FindMMapBaseVAddr(struct list_head *psMMapOffsetStructList, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length) @@ -2740,7 +3946,10 @@ IMG_VOID *FindMMapBaseVAddr(struct list_head *psMMapOffsetStructList, PKV_OFFSET_STRUCT psOffsetStruct; IMG_VOID *pvMinVAddr; - + /* There's no kernel-virtual for this type of allocation, so if + * we're flushing it, it must be user-virtual, and therefore + * have a mapping. + */ list_for_each_entry(psOffsetStruct, psMMapOffsetStructList, sAreaItem) { if(OSGetCurrentProcessIDKM() != psOffsetStruct->ui32PID) @@ -2748,7 +3957,7 @@ IMG_VOID *FindMMapBaseVAddr(struct list_head *psMMapOffsetStructList, pvMinVAddr = (IMG_VOID *)psOffsetStruct->ui32UserVAddr; - + /* Within permissible range */ if(pvRangeAddrStart >= pvMinVAddr && ui32Length <= psOffsetStruct->ui32RealByteSize) return pvMinVAddr; @@ -2757,8 +3966,42 @@ IMG_VOID *FindMMapBaseVAddr(struct list_head *psMMapOffsetStructList, return IMG_NULL; } +extern PVRSRV_LINUX_MUTEX g_sMMapMutex; + +static inline void DoInnerCacheOp(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, + IMG_VOID *pvRangeAddrStart, + IMG_UINT32 ui32Length, + InnerCacheOp_t pfnInnerCacheOp) +{ + LinuxMemArea *psLinuxMemArea = hOSMemHandle; + + if (!psLinuxMemArea->hBMHandle) + { + pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length); + } + else + { + IMG_UINT32 ui32ByteRemain = ui32Length; + IMG_UINT32 ui32BytesToDo = PAGE_SIZE - (((IMG_UINT32) pvRangeAddrStart) & (~PAGE_MASK)); + IMG_UINT8 *pbDo = (IMG_UINT8 *) pvRangeAddrStart; + + while(ui32ByteRemain) + { + if (BM_MapPageAtOffset(psLinuxMemArea->hBMHandle, ui32ByteOffset + (ui32Length - ui32ByteRemain))) + { + pfnInnerCacheOp(pbDo, pbDo + ui32BytesToDo); + } + pbDo += ui32BytesToDo; + ui32ByteRemain -= ui32BytesToDo; + ui32BytesToDo = MIN(ui32ByteRemain, PAGE_SIZE); + } + } +} + static IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length, InnerCacheOp_t pfnInnerCacheOp, @@ -2776,8 +4019,10 @@ IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle, PVR_ASSERT(psLinuxMemArea != IMG_NULL); - ui32AreaLength = psLinuxMemArea->ui32ByteSize; + LinuxLockMutex(&g_sMMapMutex); + psMMapOffsetStructList = &psLinuxMemArea->sMMapOffsetStructList; + ui32AreaLength = psLinuxMemArea->ui32ByteSize; PVR_ASSERT(ui32Length <= ui32AreaLength); @@ -2787,7 +4032,7 @@ IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle, psLinuxMemArea = psLinuxMemArea->uData.sSubAlloc.psParentLinuxMemArea; } - + /* Recursion surely isn't possible? */ PVR_ASSERT(psLinuxMemArea->eAreaType != LINUX_MEM_AREA_SUB_ALLOC); switch(psLinuxMemArea->eAreaType) @@ -2798,63 +4043,84 @@ IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle, { pvMinVAddr = psLinuxMemArea->uData.sVmalloc.pvVmallocAddress + ui32AreaOffset; - + /* Outside permissible range */ if(pvRangeAddrStart < pvMinVAddr) goto err_blocked; - pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length); + DoInnerCacheOp(hOSMemHandle, + ui32ByteOffset, + pvRangeAddrStart, + ui32Length, + pfnInnerCacheOp); } else { - - + /* If this isn't a vmalloc address, assume we're flushing by + * user-virtual. Compute the mmap base vaddr and use this to + * compute the offset in vmalloc space. + */ pvMinVAddr = FindMMapBaseVAddr(psMMapOffsetStructList, pvRangeAddrStart, ui32Length); if(!pvMinVAddr) goto err_blocked; - pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length); + DoInnerCacheOp(hOSMemHandle, + ui32ByteOffset, + pvRangeAddrStart, + ui32Length, + pfnInnerCacheOp); #if defined(CONFIG_OUTER_CACHE) - + /* + * We don't need to worry about cache aliasing here because + * we have already flushed the virtually-indexed caches (L1 + * etc.) by the supplied user-virtual addresses. + * + * The vmalloc address will only be used to determine + * affected physical pages for outer cache flushing. + */ pvRangeAddrStart = psLinuxMemArea->uData.sVmalloc.pvVmallocAddress + (ui32AreaOffset & PAGE_MASK) + (pvRangeAddrStart - pvMinVAddr); } pfnMemAreaToPhys = VMallocAreaToPhys; -#else +#else /* defined(CONFIG_OUTER_CACHE) */ } -#endif +#endif /* defined(CONFIG_OUTER_CACHE) */ break; } case LINUX_MEM_AREA_EXTERNAL_KV: { - + /* We'll only see bPhysContig for frame buffers, and we shouldn't + * be flushing those (they're write combined or uncached). + */ if (psLinuxMemArea->uData.sExternalKV.bPhysContig == IMG_TRUE) { PVR_DPF((PVR_DBG_WARNING, "%s: Attempt to flush contiguous external memory", __func__)); - goto err_blocked; } - + /* If it has a kernel virtual address, something odd has happened. + * We expect EXTERNAL_KV _only_ from the wrapping of ALLOC_PAGES. + */ if (psLinuxMemArea->uData.sExternalKV.pvExternalKV != IMG_NULL) { PVR_DPF((PVR_DBG_WARNING, "%s: Attempt to flush external memory with a kernel virtual address", __func__)); - goto err_blocked; } - - pvMinVAddr = FindMMapBaseVAddr(psMMapOffsetStructList, pvRangeAddrStart, ui32Length); if(!pvMinVAddr) goto err_blocked; - pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length); + DoInnerCacheOp(hOSMemHandle, + ui32ByteOffset, + pvRangeAddrStart, + ui32Length, + pfnInnerCacheOp); #if defined(CONFIG_OUTER_CACHE) ui32PageNumOffset = ((ui32AreaOffset & PAGE_MASK) + (pvRangeAddrStart - pvMinVAddr)) >> PAGE_SHIFT; @@ -2863,6 +4129,26 @@ IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle, break; } + case LINUX_MEM_AREA_ION: + { + pvMinVAddr = FindMMapBaseVAddr(psMMapOffsetStructList, + pvRangeAddrStart, ui32Length); + if(!pvMinVAddr) + goto err_blocked; + + DoInnerCacheOp(hOSMemHandle, + ui32ByteOffset, + pvRangeAddrStart, + ui32Length, + pfnInnerCacheOp); + +#if defined(CONFIG_OUTER_CACHE) + ui32PageNumOffset = ((ui32AreaOffset & PAGE_MASK) + (pvRangeAddrStart - pvMinVAddr)) >> PAGE_SHIFT; + pfnMemAreaToPhys = IONAreaToPhys; +#endif + break; + } + case LINUX_MEM_AREA_ALLOC_PAGES: { pvMinVAddr = FindMMapBaseVAddr(psMMapOffsetStructList, @@ -2870,11 +4156,22 @@ IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle, if(!pvMinVAddr) goto err_blocked; - pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length); + DoInnerCacheOp(hOSMemHandle, + ui32ByteOffset, + pvRangeAddrStart, + ui32Length, + pfnInnerCacheOp); #if defined(CONFIG_OUTER_CACHE) ui32PageNumOffset = ((ui32AreaOffset & PAGE_MASK) + (pvRangeAddrStart - pvMinVAddr)) >> PAGE_SHIFT; - pfnMemAreaToPhys = AllocPagesAreaToPhys; + if (psLinuxMemArea->hBMHandle) + { + pfnMemAreaToPhys = AllocPagesSparseAreaToPhys; + } + else + { + pfnMemAreaToPhys = AllocPagesAreaToPhys; + } #endif break; } @@ -2883,35 +4180,41 @@ IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle, PVR_DBG_BREAK; } + LinuxUnLockMutex(&g_sMMapMutex); + #if defined(CONFIG_OUTER_CACHE) PVR_ASSERT(pfnMemAreaToPhys != IMG_NULL); - + /* Outer caches need some more work, to get a list of physical addresses */ { unsigned long ulStart, ulEnd, ulLength, ulStartOffset, ulEndOffset; IMG_UINT32 i, ui32NumPages; + IMG_BOOL bValidPage; - + /* Length and offsets of flush region WRT page alignment */ ulLength = (unsigned long)ui32Length; ulStartOffset = ((unsigned long)pvRangeAddrStart) & (PAGE_SIZE - 1); ulEndOffset = ((unsigned long)pvRangeAddrStart + ulLength) & (PAGE_SIZE - 1); - + /* The affected pages, rounded up */ ui32NumPages = (ulStartOffset + ulLength + PAGE_SIZE - 1) >> PAGE_SHIFT; for(i = 0; i < ui32NumPages; i++) { - ulStart = pfnMemAreaToPhys(psLinuxMemArea, pvRangeAddrStart, - ui32PageNumOffset, i); - ulEnd = ulStart + PAGE_SIZE; - - if(i == ui32NumPages - 1 && ulEndOffset != 0) - ulEnd = ulStart + ulEndOffset; - - if(i == 0) - ulStart += ulStartOffset; - - pfnOuterCacheOp(ulStart, ulEnd); + bValidPage = pfnMemAreaToPhys(psLinuxMemArea, pvRangeAddrStart, + ui32PageNumOffset, i, &ulStart); + if (bValidPage) + { + ulEnd = ulStart + PAGE_SIZE; + + if(i == ui32NumPages - 1 && ulEndOffset != 0) + ulEnd = ulStart + ulEndOffset; + + if(i == 0) + ulStart += ulStartOffset; + + pfnOuterCacheOp(ulStart, ulEnd); + } } } #endif @@ -2923,11 +4226,10 @@ err_blocked: "%p-%p (type %d)", __func__, pvRangeAddrStart, pvRangeAddrStart + ui32Length, psLinuxMemArea->eAreaType)); + LinuxUnLockMutex(&g_sMMapMutex); return IMG_FALSE; } -#endif - #if defined(__i386__) #define ROUND_UP(x,a) (((x) + (a) - 1) & ~((a) - 1)) @@ -2949,13 +4251,15 @@ static void x86_flush_cache_range(const void *pvStart, const void *pvEnd) mb(); for(pbBase = pbStart; pbBase < pbEnd; pbBase += boot_cpu_data.x86_clflush_size) + { clflush(pbBase); + } mb(); } IMG_VOID OSCleanCPUCacheKM(IMG_VOID) { - + /* No clean feature on x86 */ ON_EACH_CPU(per_cpu_cache_flush, NULL, 1); } @@ -2965,33 +4269,36 @@ IMG_VOID OSFlushCPUCacheKM(IMG_VOID) } IMG_BOOL OSFlushCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length) { - - return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length, + /* Write-back and invalidate */ + return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset, pvRangeAddrStart, ui32Length, x86_flush_cache_range, IMG_NULL); } IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length) { - - return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length, + /* No clean feature on x86 */ + return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset, pvRangeAddrStart, ui32Length, x86_flush_cache_range, IMG_NULL); } IMG_BOOL OSInvalidateCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length) { - - return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length, + /* No invalidate-only support */ + return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset, pvRangeAddrStart, ui32Length, x86_flush_cache_range, IMG_NULL); } -#else +#else /* defined(__i386__) */ #if defined(__arm__) @@ -3003,25 +4310,35 @@ static void per_cpu_cache_flush(void *arg) IMG_VOID OSCleanCPUCacheKM(IMG_VOID) { - + /* No full (inner) cache clean op */ ON_EACH_CPU(per_cpu_cache_flush, NULL, 1); -#if defined(CONFIG_OUTER_CACHE) && !defined(PVR_NO_FULL_CACHE_OPS) - outer_clean_all(); +#if defined(CONFIG_OUTER_CACHE) + outer_clean_range(0, ULONG_MAX); #endif } IMG_VOID OSFlushCPUCacheKM(IMG_VOID) { ON_EACH_CPU(per_cpu_cache_flush, NULL, 1); -#if defined(CONFIG_OUTER_CACHE) && !defined(PVR_NO_FULL_CACHE_OPS) +#if defined(CONFIG_OUTER_CACHE) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) + /* To use the "deferred flush" (not clean) DDK feature you need a kernel + * implementation of outer_flush_all() for ARM CPUs with an outer cache + * controller (e.g. PL310, common with Cortex A9 and later). + * + * Reference DDKs don't require this functionality, as they will only + * clean the cache, never flush (clean+invalidate) it. + */ outer_flush_all(); #endif } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) static inline size_t pvr_dmac_range_len(const void *pvStart, const void *pvEnd) { return (size_t)((char *)pvEnd - (char *)pvStart); } +#endif static void pvr_dmac_inv_range(const void *pvStart, const void *pvEnd) { @@ -3042,90 +4359,244 @@ static void pvr_dmac_clean_range(const void *pvStart, const void *pvEnd) } IMG_BOOL OSFlushCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length) { - return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length, + return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset, + pvRangeAddrStart, ui32Length, dmac_flush_range, outer_flush_range); } IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length) { - IMG_BOOL retval = IMG_TRUE; + IMG_BOOL retval = IMG_TRUE; #if defined(CONFIG_OUTER_CACHE) && !defined(PVR_NO_FULL_CACHE_OPS) if (ui32Length > PVR_FULL_CACHE_OP_THRESHOLD) OSCleanCPUCacheKM(); else #endif { - retval = CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length, + retval = CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset, + pvRangeAddrStart, ui32Length, pvr_dmac_clean_range, outer_clean_range); } return retval; } IMG_BOOL OSInvalidateCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length) { - return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length, + return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset, + pvRangeAddrStart, ui32Length, pvr_dmac_inv_range, outer_inv_range); } -#else +#else /* defined(__arm__) */ #if defined(__mips__) +/* + * dmac cache functions are supposed to be used for dma + * memory which comes from dma-able memory. However examining + * the implementation of dmac cache functions and experimenting, + * can assert that dmac functions are safe to use for high-mem + * memory as well for our OS{Clean/Flush/Invalidate}Cache functions + * + */ + IMG_VOID OSCleanCPUCacheKM(IMG_VOID) { - + /* dmac functions flush full cache if size is larger than + * p-cache size. This is a workaround for the fact that + * __flush_cache_all is not an exported symbol. Please + * replace with custom function if available in latest + * version of linux being used. + * Arbitrary large number (1MB) which should be larger than + * mips p-cache sizes for some time in future. + * */ dma_cache_wback(0, 0x100000); } IMG_VOID OSFlushCPUCacheKM(IMG_VOID) { - + /* dmac functions flush full cache if size is larger than + * p-cache size. This is a workaround for the fact that + * __flush_cache_all is not an exported symbol. Please + * replace with custom function if available in latest + * version of linux being used. + * Arbitrary large number (1MB) which should be larger than + * mips p-cache sizes for some time in future. + * */ dma_cache_wback_inv(0, 0x100000); } +static inline IMG_UINT32 pvr_dma_range_len(const void *pvStart, const void *pvEnd) +{ + return (IMG_UINT32)((char *)pvEnd - (char *)pvStart); +} + +static void pvr_dma_cache_wback_inv(const void *pvStart, const void *pvEnd) +{ + dma_cache_wback_inv((IMG_UINTPTR_T)pvStart, pvr_dma_range_len(pvStart, pvEnd)); +} + +static void pvr_dma_cache_wback(const void *pvStart, const void *pvEnd) +{ + dma_cache_wback((IMG_UINTPTR_T)pvStart, pvr_dma_range_len(pvStart, pvEnd)); +} + +static void pvr_dma_cache_inv(const void *pvStart, const void *pvEnd) +{ + dma_cache_inv((IMG_UINTPTR_T)pvStart, pvr_dma_range_len(pvStart, pvEnd)); +} + IMG_BOOL OSFlushCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length) { - if (ui32Length) - dma_cache_wback_inv((IMG_UINTPTR_T)pvRangeAddrStart, ui32Length); - return IMG_TRUE; + return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset, + pvRangeAddrStart, ui32Length, + pvr_dma_cache_wback_inv, IMG_NULL); } IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length) { - if (ui32Length) - dma_cache_wback((IMG_UINTPTR_T)pvRangeAddrStart, ui32Length); - return IMG_TRUE; + return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset, + pvRangeAddrStart, ui32Length, + pvr_dma_cache_wback, IMG_NULL); } IMG_BOOL OSInvalidateCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length) { - if (ui32Length) - dma_cache_inv((IMG_UINTPTR_T)pvRangeAddrStart, ui32Length); - return IMG_TRUE; + return CheckExecuteCacheOp(hOSMemHandle, ui32ByteOffset, + pvRangeAddrStart, ui32Length, + pvr_dma_cache_inv, IMG_NULL); } -#else +#else /* defined(__mips__) */ #error "Implement CPU cache flush/clean/invalidate primitives for this CPU!" -#endif +#endif /* defined(__mips__) */ + +#endif /* defined(__arm__) */ + +#endif /* defined(__i386__) */ + +typedef struct _AtomicStruct +{ + atomic_t RefCount; +} AtomicStruct; + +PVRSRV_ERROR OSAtomicAlloc(IMG_PVOID *ppvRefCount) +{ + AtomicStruct *psRefCount; + + psRefCount = kmalloc(sizeof(AtomicStruct), GFP_KERNEL); + if (psRefCount == NULL) + { + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + atomic_set(&psRefCount->RefCount, 0); + + *ppvRefCount = psRefCount; + return PVRSRV_OK; +} + +IMG_VOID OSAtomicFree(IMG_PVOID pvRefCount) +{ + AtomicStruct *psRefCount = pvRefCount; + + PVR_ASSERT(atomic_read(&psRefCount->RefCount) == 0); + kfree(psRefCount); +} + +IMG_VOID OSAtomicInc(IMG_PVOID pvRefCount) +{ + AtomicStruct *psRefCount = pvRefCount; + + atomic_inc(&psRefCount->RefCount); +} + +IMG_BOOL OSAtomicDecAndTest(IMG_PVOID pvRefCount) +{ + AtomicStruct *psRefCount = pvRefCount; + + return atomic_dec_and_test(&psRefCount->RefCount) ? IMG_TRUE:IMG_FALSE; +} + +IMG_UINT32 OSAtomicRead(IMG_PVOID pvRefCount) +{ + AtomicStruct *psRefCount = pvRefCount; + + return (IMG_UINT32) atomic_read(&psRefCount->RefCount); +} + +IMG_VOID OSReleaseBridgeLock(IMG_VOID) +{ + LinuxUnLockMutex(&gPVRSRVLock); +} + +IMG_VOID OSReacquireBridgeLock(IMG_VOID) +{ + LinuxLockMutex(&gPVRSRVLock); +} + +typedef struct _OSTime +{ + unsigned long ulTime; +} OSTime; + +PVRSRV_ERROR OSTimeCreateWithUSOffset(IMG_PVOID *pvRet, IMG_UINT32 ui32USOffset) +{ + OSTime *psOSTime; + + psOSTime = kmalloc(sizeof(OSTime), GFP_KERNEL); + if (psOSTime == IMG_NULL) + { + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + + psOSTime->ulTime = usecs_to_jiffies(jiffies_to_usecs(jiffies) + ui32USOffset); + *pvRet = psOSTime; + return PVRSRV_OK; +} + -#endif +IMG_BOOL OSTimeHasTimePassed(IMG_PVOID pvData) +{ + OSTime *psOSTime = pvData; + + if (time_is_before_jiffies(psOSTime->ulTime)) + { + return IMG_TRUE; + } + return IMG_FALSE; +} + +IMG_VOID OSTimeDestroy(IMG_PVOID pvData) +{ + kfree(pvData); +} -#endif +IMG_VOID OSGetCurrentProcessNameKM(IMG_CHAR *pszName, IMG_UINT32 ui32Size) +{ + strncpy(pszName, current->comm, MIN(ui32Size,TASK_COMM_LEN)); +} +/* One time osfunc initialisation */ PVRSRV_ERROR PVROSFuncInit(IMG_VOID) { #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) @@ -3152,11 +4623,30 @@ PVRSRV_ERROR PVROSFuncInit(IMG_VOID) } } #endif + +#if defined (SUPPORT_ION) + { + PVRSRV_ERROR eError; + + eError = IonInit(); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "%s: IonInit failed", __FUNCTION__)); + } + } +#endif return PVRSRV_OK; } +/* + * Osfunc deinitialisation. + * Note that PVROSFuncInit may not have been called + */ IMG_VOID PVROSFuncDeInit(IMG_VOID) { +#if defined (SUPPORT_ION) + IonDeinit(); +#endif #if defined(PVR_LINUX_TIMERS_USING_WORKQUEUES) if (psTimerWorkQueue != NULL) { diff --git a/sgx/services4/srvkm/env/linux/osperproc.c b/sgx/services4/srvkm/env/linux/osperproc.c index 6b57dfc..5116c36 100644 --- a/sgx/services4/srvkm/env/linux/osperproc.c +++ b/sgx/services4/srvkm/env/linux/osperproc.c @@ -1,35 +1,55 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Linux specific per process data functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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 "services_headers.h" #include "osperproc.h" #include "env_perproc.h" #include "proc.h" +#if defined (SUPPORT_ION) +#include "linux/ion.h" +extern struct ion_device *psIonDev; +#endif extern IMG_UINT32 gui32ReleasePID; PVRSRV_ERROR OSPerProcessPrivateDataInit(IMG_HANDLE *phOsPrivateData) @@ -57,14 +77,28 @@ PVRSRV_ERROR OSPerProcessPrivateDataInit(IMG_HANDLE *phOsPrivateData) psEnvPerProc->hBlockAlloc = hBlockAlloc; - + /* Linux specific mmap processing */ LinuxMMapPerProcessConnect(psEnvPerProc); #if defined(SUPPORT_DRI_DRM) && defined(PVR_SECURE_DRM_AUTH_EXPORT) - + /* Linked list of PVRSRV_FILE_PRIVATE_DATA structures */ INIT_LIST_HEAD(&psEnvPerProc->sDRMAuthListHead); #endif - +#if defined(SUPPORT_ION) + OSSNPrintf(psEnvPerProc->azIonClientName, ION_CLIENT_NAME_SIZE, "pvr_ion_client-%d", OSGetCurrentProcessIDKM()); + psEnvPerProc->psIONClient = + ion_client_create(psIonDev, + 1 << ION_HEAP_TYPE_SYSTEM_CONTIG | + 1 << ION_HEAP_TYPE_SYSTEM, + psEnvPerProc->azIonClientName); + + if (IS_ERR_OR_NULL(psEnvPerProc->psIONClient)) + { + PVR_DPF((PVR_DBG_ERROR, "OSPerProcessPrivateDataInit: Couldn't create " + "ion client for per process data")); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } +#endif /* SUPPORT_ION */ return PVRSRV_OK; } @@ -80,17 +114,17 @@ PVRSRV_ERROR OSPerProcessPrivateDataDeInit(IMG_HANDLE hOsPrivateData) psEnvPerProc = (PVRSRV_ENV_PER_PROCESS_DATA *)hOsPrivateData; - + /* Linux specific mmap processing */ LinuxMMapPerProcessDisconnect(psEnvPerProc); - + /* Remove per process /proc entries */ RemovePerProcessProcDir(psEnvPerProc); eError = OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_ENV_PER_PROCESS_DATA), hOsPrivateData, psEnvPerProc->hBlockAlloc); - + /*not nulling pointer, copy on stack*/ if (eError != PVRSRV_OK) { diff --git a/sgx/services4/srvkm/env/linux/pdump.c b/sgx/services4/srvkm/env/linux/pdump.c index 13d9b0d..192640f 100644 --- a/sgx/services4/srvkm/env/linux/pdump.c +++ b/sgx/services4/srvkm/env/linux/pdump.c @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Parameter dump macro target routines +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #if defined (SUPPORT_SGX) || defined (SUPPORT_VGX) #if defined (PDUMP) @@ -30,7 +46,7 @@ #include <asm/atomic.h> #include <stdarg.h> #if defined (SUPPORT_SGX) -#include "sgxdefs.h" +#include "sgxdefs.h" /* Is this still needed? */ #endif #include "services_headers.h" @@ -39,14 +55,14 @@ #include "dbgdrvif.h" #if defined (SUPPORT_SGX) -#include "sgxmmu.h" +#include "sgxmmu.h"/* Is this still needed? */ #endif #include "mm.h" #include "pdump_km.h" #include "pdump_int.h" -#include <linux/kernel.h> -#include <linux/string.h> +#include <linux/kernel.h> // sprintf +#include <linux/string.h> // strncpy, strlen static IMG_BOOL PDumpWriteString2 (IMG_CHAR * pszString, IMG_UINT32 ui32Flags); static IMG_BOOL PDumpWriteILock (PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_UINT32 ui32Count, IMG_UINT32 ui32Flags); @@ -56,6 +72,9 @@ static IMG_VOID DbgSetMarker (PDBG_STREAM psStream, IMG_UINT32 ui32Marker); #define PDUMP_DATAMASTER_PIXEL (1) #define PDUMP_DATAMASTER_EDM (3) +/* + Maximum file size to split output files +*/ #define MAX_FILE_SIZE 0x40000000 static atomic_t gsPDumpSuspended = ATOMIC_INIT(0); @@ -87,13 +106,14 @@ static PDBG_PDUMP_STATE gsDBGPdumpState = {{IMG_NULL}, 0, IMG_NULL, IMG_NULL, IM -IMG_VOID DBGDrvGetServiceTable(IMG_VOID **fn_table); - static inline IMG_BOOL PDumpSuspended(IMG_VOID) { return (atomic_read(&gsPDumpSuspended) != 0) ? IMG_TRUE : IMG_FALSE; } +/*! + * \name PDumpOSGetScriptString + */ PVRSRV_ERROR PDumpOSGetScriptString(IMG_HANDLE *phScript, IMG_UINT32 *pui32MaxLen) { @@ -106,6 +126,9 @@ PVRSRV_ERROR PDumpOSGetScriptString(IMG_HANDLE *phScript, return PVRSRV_OK; } +/*! + * \name PDumpOSGetMessageString + */ PVRSRV_ERROR PDumpOSGetMessageString(IMG_CHAR **ppszMsg, IMG_UINT32 *pui32MaxLen) { @@ -118,6 +141,9 @@ PVRSRV_ERROR PDumpOSGetMessageString(IMG_CHAR **ppszMsg, return PVRSRV_OK; } +/*! + * \name PDumpOSGetFilenameString + */ PVRSRV_ERROR PDumpOSGetFilenameString(IMG_CHAR **ppszFile, IMG_UINT32 *pui32MaxLen) { @@ -130,11 +156,17 @@ PVRSRV_ERROR PDumpOSGetFilenameString(IMG_CHAR **ppszFile, return PVRSRV_OK; } +/*! + * \name PDumpOSWriteString2 + */ IMG_BOOL PDumpOSWriteString2(IMG_HANDLE hScript, IMG_UINT32 ui32Flags) { return PDumpWriteString2(hScript, ui32Flags); } +/*! + * \name PDumpOSBufprintf + */ PVRSRV_ERROR PDumpOSBufprintf(IMG_HANDLE hBuf, IMG_UINT32 ui32ScriptSizeMax, IMG_CHAR* pszFormat, ...) { IMG_CHAR* pszBuf = hBuf; @@ -147,7 +179,7 @@ PVRSRV_ERROR PDumpOSBufprintf(IMG_HANDLE hBuf, IMG_UINT32 ui32ScriptSizeMax, IMG va_end(vaArgs); - if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1) + if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1) /* glibc >= 2.1 or glibc 2.0 */ { PVR_DPF((PVR_DBG_ERROR, "Buffer overflow detected, pdump output may be incomplete.")); @@ -160,13 +192,16 @@ PVRSRV_ERROR PDumpOSBufprintf(IMG_HANDLE hBuf, IMG_UINT32 ui32ScriptSizeMax, IMG return PVRSRV_OK; } +/*! + * \name PDumpOSVSprintf + */ PVRSRV_ERROR PDumpOSVSprintf(IMG_CHAR *pszComment, IMG_UINT32 ui32ScriptSizeMax, IMG_CHAR* pszFormat, PDUMP_va_list vaArgs) { IMG_INT32 n; n = vsnprintf(pszComment, ui32ScriptSizeMax, pszFormat, vaArgs); - if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1) + if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1) /* glibc >= 2.1 or glibc 2.0 */ { PVR_DPF((PVR_DBG_ERROR, "Buffer overflow detected, pdump output may be incomplete.")); @@ -176,13 +211,19 @@ PVRSRV_ERROR PDumpOSVSprintf(IMG_CHAR *pszComment, IMG_UINT32 ui32ScriptSizeMax, return PVRSRV_OK; } +/*! + * \name PDumpOSDebugPrintf + */ IMG_VOID PDumpOSDebugPrintf(IMG_CHAR* pszFormat, ...) { PVR_UNREFERENCED_PARAMETER(pszFormat); - + /* FIXME: Implement using services PVR_DBG or otherwise with kprintf */ } +/*! + * \name PDumpOSSprintf + */ PVRSRV_ERROR PDumpOSSprintf(IMG_CHAR *pszComment, IMG_UINT32 ui32ScriptSizeMax, IMG_CHAR *pszFormat, ...) { IMG_INT32 n; @@ -194,7 +235,7 @@ PVRSRV_ERROR PDumpOSSprintf(IMG_CHAR *pszComment, IMG_UINT32 ui32ScriptSizeMax, va_end(vaArgs); - if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1) + if (n>=(IMG_INT32)ui32ScriptSizeMax || n==-1) /* glibc >= 2.1 or glibc 2.0 */ { PVR_DPF((PVR_DBG_ERROR, "Buffer overflow detected, pdump output may be incomplete.")); @@ -204,6 +245,9 @@ PVRSRV_ERROR PDumpOSSprintf(IMG_CHAR *pszComment, IMG_UINT32 ui32ScriptSizeMax, return PVRSRV_OK; } +/*! + * \name PDumpOSBuflen + */ IMG_UINT32 PDumpOSBuflen(IMG_HANDLE hBuffer, IMG_UINT32 ui32BufferSizeMax) { IMG_CHAR* pszBuf = hBuffer; @@ -216,15 +260,18 @@ IMG_UINT32 PDumpOSBuflen(IMG_HANDLE hBuffer, IMG_UINT32 ui32BufferSizeMax) return(ui32Count); } +/*! + * \name PDumpOSVerifyLineEnding + */ IMG_VOID PDumpOSVerifyLineEnding(IMG_HANDLE hBuffer, IMG_UINT32 ui32BufferSizeMax) { IMG_UINT32 ui32Count; IMG_CHAR* pszBuf = hBuffer; - + /* strlen */ ui32Count = PDumpOSBuflen(hBuffer, ui32BufferSizeMax); - + /* Put \r \n sequence at the end if it isn't already there */ if ((ui32Count >= 1) && (pszBuf[ui32Count-1] != '\n') && (ui32Count<ui32BufferSizeMax)) { pszBuf[ui32Count] = '\n'; @@ -240,22 +287,34 @@ IMG_VOID PDumpOSVerifyLineEnding(IMG_HANDLE hBuffer, IMG_UINT32 ui32BufferSizeMa } } +/*! + * \name PDumpOSGetStream + */ IMG_HANDLE PDumpOSGetStream(IMG_UINT32 ePDumpStream) { return (IMG_HANDLE)gsDBGPdumpState.psStream[ePDumpStream]; } +/*! + * \name PDumpOSGetStreamOffset + */ IMG_UINT32 PDumpOSGetStreamOffset(IMG_UINT32 ePDumpStream) { PDBG_STREAM psStream = gsDBGPdumpState.psStream[ePDumpStream]; return gpfnDbgDrv->pfnGetStreamOffset(psStream); } +/*! + * \name PDumpOSGetParamFileNum + */ IMG_UINT32 PDumpOSGetParamFileNum(IMG_VOID) { return gsDBGPdumpState.ui32ParamFileNum; } +/*! + * \name PDumpOSWriteString + */ IMG_BOOL PDumpOSWriteString(IMG_HANDLE hStream, IMG_UINT8 *psui8Data, IMG_UINT32 ui32Size, @@ -268,14 +327,21 @@ IMG_BOOL PDumpOSWriteString(IMG_HANDLE hStream, ui32Flags); } +/*! + * \name PDumpOSCheckForSplitting + */ IMG_VOID PDumpOSCheckForSplitting(IMG_HANDLE hStream, IMG_UINT32 ui32Size, IMG_UINT32 ui32Flags) { - + /* File size limit not implemented for this OS. + */ PVR_UNREFERENCED_PARAMETER(hStream); PVR_UNREFERENCED_PARAMETER(ui32Size); PVR_UNREFERENCED_PARAMETER(ui32Flags); } +/*! + * \name PDumpOSJTInitialised + */ IMG_BOOL PDumpOSJTInitialised(IMG_VOID) { if(gpfnDbgDrv) @@ -285,11 +351,17 @@ IMG_BOOL PDumpOSJTInitialised(IMG_VOID) return IMG_FALSE; } +/*! + * \name PDumpOSIsSuspended + */ inline IMG_BOOL PDumpOSIsSuspended(IMG_VOID) { return (atomic_read(&gsPDumpSuspended) != 0) ? IMG_TRUE : IMG_FALSE; } +/*! + * \name PDumpOSCPUVAddrToDevPAddr + */ IMG_VOID PDumpOSCPUVAddrToDevPAddr(PVRSRV_DEVICE_TYPE eDeviceType, IMG_HANDLE hOSMemHandle, IMG_UINT32 ui32Offset, @@ -300,19 +372,23 @@ IMG_VOID PDumpOSCPUVAddrToDevPAddr(PVRSRV_DEVICE_TYPE eDeviceType, IMG_CPU_PHYADDR sCpuPAddr; PVR_UNREFERENCED_PARAMETER(pui8LinAddr); - PVR_UNREFERENCED_PARAMETER(ui32PageSize); + PVR_UNREFERENCED_PARAMETER(ui32PageSize); /* for when no assert */ - + /* Caller must now alway supply hOSMemHandle, even though we only (presently) + use it here in the linux implementation */ PVR_ASSERT (hOSMemHandle != IMG_NULL); sCpuPAddr = OSMemHandleToCpuPAddr(hOSMemHandle, ui32Offset); PVR_ASSERT((sCpuPAddr.uiAddr & (ui32PageSize - 1)) == 0); - + /* convert CPU physical addr to device physical */ *psDevPAddr = SysCpuPAddrToDevPAddr(eDeviceType, sCpuPAddr); } +/*! + * \name PDumpOSCPUVAddrToPhysPages + */ IMG_VOID PDumpOSCPUVAddrToPhysPages(IMG_HANDLE hOSMemHandle, IMG_UINT32 ui32Offset, IMG_PUINT8 pui8LinAddr, @@ -321,7 +397,9 @@ IMG_VOID PDumpOSCPUVAddrToPhysPages(IMG_HANDLE hOSMemHandle, { if(hOSMemHandle) { - + /* + * If a Services memory handle is provided then use it. + */ IMG_CPU_PHYADDR sCpuPAddr; PVR_UNREFERENCED_PARAMETER(pui8LinAddr); @@ -338,6 +416,9 @@ IMG_VOID PDumpOSCPUVAddrToPhysPages(IMG_HANDLE hOSMemHandle, } } +/*! + * \name PDumpOSDebugDriverWrite + */ IMG_UINT32 PDumpOSDebugDriverWrite( PDBG_STREAM psStream, PDUMP_DDWMODE eDbgDrvWriteMode, IMG_UINT8 *pui8Data, @@ -365,29 +446,43 @@ IMG_UINT32 PDumpOSDebugDriverWrite( PDBG_STREAM psStream, return 0xFFFFFFFFU; } +/*! + * \name PDumpOSReleaseExecution + */ IMG_VOID PDumpOSReleaseExecution(IMG_VOID) { OSReleaseThreadQuanta(); } +/************************************************************************** + * Function Name : PDumpInit + * Outputs : None + * Returns : + * Description : Reset connection to vldbgdrv + * Then try to connect to PDUMP streams +**************************************************************************/ IMG_VOID PDumpInit(IMG_VOID) { IMG_UINT32 i; DBGKM_CONNECT_NOTIFIER sConnectNotifier; - + /* If we tried this earlier, then we might have connected to the driver + * But if pdump.exe was running then the stream connected would fail + */ if (!gpfnDbgDrv) { - DBGDrvGetServiceTable((IMG_VOID **)&gpfnDbgDrv); + DBGDrvGetServiceTable(&gpfnDbgDrv); - + // If something failed then no point in trying to connect streams if (gpfnDbgDrv == IMG_NULL) { return; } - + /* + * Pass the connection notify callback + */ sConnectNotifier.pfnConnectNotifier = &PDumpConnectionNotify; gpfnDbgDrv->pfnSetConnectNotifier(sConnectNotifier); @@ -457,7 +552,9 @@ init_failed: gsDBGPdumpState.pszMsg = IMG_NULL; } - + /* + * Remove the connection notify callback + */ sConnectNotifier.pfnConnectNotifier = 0; gpfnDbgDrv->pfnSetConnectNotifier(sConnectNotifier); @@ -493,13 +590,22 @@ IMG_VOID PDumpDeInit(IMG_VOID) gsDBGPdumpState.pszMsg = IMG_NULL; } - + /* + * Remove the connection notify callback + */ sConnectNotifier.pfnConnectNotifier = 0; gpfnDbgDrv->pfnSetConnectNotifier(sConnectNotifier); gpfnDbgDrv = IMG_NULL; } +/************************************************************************** + * Function Name : PDumpStartInitPhaseKM + * Inputs : None + * Outputs : None + * Returns : None + * Description : Resume init phase state +**************************************************************************/ PVRSRV_ERROR PDumpStartInitPhaseKM(IMG_VOID) { IMG_UINT32 i; @@ -515,6 +621,13 @@ PVRSRV_ERROR PDumpStartInitPhaseKM(IMG_VOID) return PVRSRV_OK; } +/************************************************************************** + * Function Name : PDumpStopInitPhaseKM + * Inputs : None + * Outputs : None + * Returns : None + * Description : End init phase state +**************************************************************************/ PVRSRV_ERROR PDumpStopInitPhaseKM(IMG_VOID) { IMG_UINT32 i; @@ -531,12 +644,26 @@ PVRSRV_ERROR PDumpStopInitPhaseKM(IMG_VOID) return PVRSRV_OK; } +/************************************************************************** + * Function Name : PDumpIsLastCaptureFrameKM + * Inputs : None + * Outputs : None + * Returns : True or false + * Description : Tests whether the current frame is being pdumped +**************************************************************************/ IMG_BOOL PDumpIsLastCaptureFrameKM(IMG_VOID) { return gpfnDbgDrv->pfnIsLastCaptureFrame(gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2]); } +/************************************************************************** + * Function Name : PDumpIsCaptureFrameKM + * Inputs : None + * Outputs : None + * Returns : True or false + * Description : Tests whether the current frame is being pdumped +**************************************************************************/ IMG_BOOL PDumpOSIsCaptureFrameKM(IMG_VOID) { if (PDumpSuspended()) @@ -546,6 +673,13 @@ IMG_BOOL PDumpOSIsCaptureFrameKM(IMG_VOID) return gpfnDbgDrv->pfnIsCaptureFrame(gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2], IMG_FALSE); } +/************************************************************************** + * Function Name : PDumpSetFrameKM + * Inputs : None + * Outputs : None + * Returns : None + * Description : Sets a frame +**************************************************************************/ PVRSRV_ERROR PDumpOSSetFrameKM(IMG_UINT32 ui32Frame) { IMG_UINT32 ui32Stream; @@ -562,12 +696,30 @@ PVRSRV_ERROR PDumpOSSetFrameKM(IMG_UINT32 ui32Frame) } +/***************************************************************************** + FUNCTION : PDumpWriteString2 + + PURPOSE : + + PARAMETERS : + + RETURNS : +*****************************************************************************/ static IMG_BOOL PDumpWriteString2(IMG_CHAR * pszString, IMG_UINT32 ui32Flags) { return PDumpWriteILock(gsDBGPdumpState.psStream[PDUMP_STREAM_SCRIPT2], (IMG_UINT8 *) pszString, strlen(pszString), ui32Flags); } +/***************************************************************************** + FUNCTION : PDumpWriteILock + + PURPOSE : Writes, making sure it all goes... + + PARAMETERS : + + RETURNS : +*****************************************************************************/ static IMG_BOOL PDumpWriteILock(PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_UINT32 ui32Count, IMG_UINT32 ui32Flags) { IMG_UINT32 ui32Written = 0; @@ -578,7 +730,9 @@ static IMG_BOOL PDumpWriteILock(PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_U } - + /* + Set the stream marker to split output files + */ if (psStream == gsDBGPdumpState.psStream[PDUMP_STREAM_PARAM2]) { @@ -604,11 +758,31 @@ static IMG_BOOL PDumpWriteILock(PDBG_STREAM psStream, IMG_UINT8 *pui8Data, IMG_U return IMG_TRUE; } +/***************************************************************************** + FUNCTION : DbgSetFrame + + PURPOSE : Sets the frame in the stream + + PARAMETERS : psStream - Stream pointer + ui32Frame - Frame number to set + + RETURNS : None +*****************************************************************************/ static IMG_VOID DbgSetFrame(PDBG_STREAM psStream, IMG_UINT32 ui32Frame) { gpfnDbgDrv->pfnSetFrame(psStream, ui32Frame); } +/***************************************************************************** + FUNCTION : DbgSetMarker + + PURPOSE : Sets the marker of the stream to split output files + + PARAMETERS : psStream - Stream pointer + ui32Marker - Marker number to set + + RETURNS : None +*****************************************************************************/ static IMG_VOID DbgSetMarker(PDBG_STREAM psStream, IMG_UINT32 ui32Marker) { gpfnDbgDrv->pfnSetMarker(psStream, ui32Marker); @@ -624,5 +798,8 @@ IMG_VOID PDumpResumeKM(IMG_VOID) atomic_dec(&gsPDumpSuspended); } -#endif -#endif +#endif /* #if defined (PDUMP) */ +#endif /* #if defined (SUPPORT_SGX) */ +/***************************************************************************** + End of file (PDUMP.C) +*****************************************************************************/ diff --git a/sgx/services4/srvkm/env/linux/private_data.h b/sgx/services4/srvkm/env/linux/private_data.h index a460798..1b0f045 100644 --- a/sgx/services4/srvkm/env/linux/private_data.h +++ b/sgx/services4/srvkm/env/linux/private_data.h @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Linux private data structure +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #ifndef __INCLUDED_PRIVATE_DATA_H_ #define __INCLUDED_PRIVATE_DATA_H_ @@ -32,12 +48,23 @@ #include <drm/drmP.h> #endif +/* This structure is required in the rare case that a process creates + * a connection to services, but before closing the file descriptor, + * does a fork(). This fork() will duplicate the file descriptor in the + * child process. If the parent process dies before the child, this can + * cause the PVRSRVRelease() method to be called in a different process + * context than the original PVRSRVOpen(). This is bad because we need + * to update the per-process data reference count and/or free the + * per-process data. So we must keep a record of which PID's per-process + * data to inspect during ->release(). + */ + typedef struct { - + /* PID that created this services connection */ IMG_UINT32 ui32OpenPID; - + /* Global kernel MemInfo handle */ #if defined (SUPPORT_SID_INTERFACE) IMG_SID hKernelMemInfo; #else @@ -45,22 +72,22 @@ typedef struct #endif #if defined(SUPPORT_DRI_DRM) && defined(PVR_SECURE_DRM_AUTH_EXPORT) - + /* The private data is on a list in the per-process data structure */ struct list_head sDRMAuthListItem; struct drm_file *psDRMFile; #endif #if defined(SUPPORT_MEMINFO_IDS) - + /* Globally unique "stamp" for kernel MemInfo */ IMG_UINT64 ui64Stamp; -#endif +#endif /* defined(SUPPORT_MEMINFO_IDS) */ - + /* Accounting for OSAllocMem */ IMG_HANDLE hBlockAlloc; #if defined(SUPPORT_DRI_DRM_EXT) - IMG_PVOID pPriv; + IMG_PVOID pPriv; /*private data for extending this struct*/ #endif } PVRSRV_FILE_PRIVATE_DATA; @@ -97,5 +124,5 @@ static inline void set_private(struct file *file, PVRSRV_FILE_PRIVATE_DATA *priv #endif -#endif +#endif /* __INCLUDED_PRIVATE_DATA_H_ */ diff --git a/sgx/services4/srvkm/env/linux/proc.c b/sgx/services4/srvkm/env/linux/proc.c index 1df8aff..3b48c9e 100644 --- a/sgx/services4/srvkm/env/linux/proc.c +++ b/sgx/services4/srvkm/env/linux/proc.c @@ -1,28 +1,47 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Proc files implementation. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Functions for creating and reading proc filesystem entries. + Proc filesystem support must be built into the kernel for + these functions to be any use. +@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 <linux/version.h> @@ -52,6 +71,7 @@ #include "lists.h" +// The proc entry for our /proc/pvr directory static struct proc_dir_entry * dir; static const IMG_CHAR PVRProcDirRoot[] = "pvr"; @@ -98,6 +118,28 @@ static void ProcSeqShowVersion(struct seq_file *sfile,void* el); static void ProcSeqShowSysNodes(struct seq_file *sfile,void* el); static void* ProcSeqOff2ElementSysNodes(struct seq_file * sfile, loff_t off); +/*! +****************************************************************************** + + @Function : printAppend + + @Description + + Print into the supplied buffer at the specified offset remaining within + the specified total buffer size. + + @Input size : the total size of the buffer + + @Input off : the offset into the buffer to start printing + + @Input format : the printf format string + + @Input ... : format args + + @Return : The number of chars now in the buffer (original value of 'off' + plus number of chars added); 'size' if full. + +*****************************************************************************/ off_t printAppend(IMG_CHAR * buffer, size_t size, off_t off, const IMG_CHAR * format, ...) { IMG_INT n; @@ -109,10 +151,13 @@ off_t printAppend(IMG_CHAR * buffer, size_t size, off_t off, const IMG_CHAR * fo n = vsnprintf (buffer+off, space, format, ap); va_end (ap); - + /* According to POSIX, n is greater than or equal to the size available if + * the print would have overflowed the buffer. Other platforms may + * return -1 if printing was truncated. + */ if (n >= (IMG_INT)space || n < 0) { - + /* Ensure final string is terminated */ buffer[size - 1] = 0; return (off_t)(size - 1); } @@ -123,16 +168,50 @@ off_t printAppend(IMG_CHAR * buffer, size_t size, off_t off, const IMG_CHAR * fo } +/*! +****************************************************************************** + + @Function : ProcSeq1ElementOff2Element + + @Description + + Heleper Offset -> Element function for /proc files with only one entry + without header. + + @Input sfile : seq_file object related to /proc/ file + + @Input off : the offset into the buffer (id of object) + + @Return : Pointer to element to be shown. + +*****************************************************************************/ void* ProcSeq1ElementOff2Element(struct seq_file *sfile, loff_t off) { PVR_UNREFERENCED_PARAMETER(sfile); - + // Return anything that is not PVR_RPOC_SEQ_START_TOKEN and NULL if(!off) return (void*)2; return NULL; } +/*! +****************************************************************************** + + @Function : ProcSeq1ElementHeaderOff2Element + + @Description + + Heleper Offset -> Element function for /proc files with only one entry + with header. + + @Input sfile : seq_file object related to /proc/ file + + @Input off : the offset into the buffer (id of object) + + @Return : Pointer to element to be shown. + +*****************************************************************************/ void* ProcSeq1ElementHeaderOff2Element(struct seq_file *sfile, loff_t off) { PVR_UNREFERENCED_PARAMETER(sfile); @@ -142,7 +221,7 @@ void* ProcSeq1ElementHeaderOff2Element(struct seq_file *sfile, loff_t off) return PVR_PROC_SEQ_START_TOKEN; } - + // Return anything that is not PVR_RPOC_SEQ_START_TOKEN and NULL if(off == 1) return (void*)2; @@ -150,6 +229,22 @@ void* ProcSeq1ElementHeaderOff2Element(struct seq_file *sfile, loff_t off) } +/*! +****************************************************************************** + + @Function : pvr_proc_open + + @Description + File opening function passed to proc_dir_entry->proc_fops for /proc entries + created by CreateProcReadEntrySeq. + + @Input inode : inode entry of opened /proc file + + @Input file : file entry of opened /proc file + + @Return : 0 if no errors + +*****************************************************************************/ static IMG_INT pvr_proc_open(struct inode *inode,struct file *file) { IMG_INT ret = seq_open(file, &pvr_proc_seq_operations); @@ -157,11 +252,22 @@ static IMG_INT pvr_proc_open(struct inode *inode,struct file *file) struct seq_file *seq = (struct seq_file*)file->private_data; struct proc_dir_entry* pvr_proc_entry = PDE(inode); - + /* Add pointer to handlers to seq_file structure */ seq->private = pvr_proc_entry->data; return ret; } +/*! +****************************************************************************** + + @Function : pvr_proc_write + + @Description + File writing function passed to proc_dir_entry->proc_fops for /proc files. + It's exacly the same function that is used as default one (->fs/proc/generic.c), + it calls proc_dir_entry->write_proc for writing procedure. + +*****************************************************************************/ static ssize_t pvr_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { @@ -178,6 +284,23 @@ static ssize_t pvr_proc_write(struct file *file, const char __user *buffer, } +/*! +****************************************************************************** + + @Function : pvr_proc_seq_start + + @Description + Seq_file start function. Detailed description of seq_file workflow can + be found here: http://tldp.org/LDP/lkmpg/2.6/html/x861.html. + This function ises off2element handler. + + @Input proc_seq_file : sequence file entry + + @Input pos : offset within file (id of entry) + + @Return : Pointer to element from we start enumeration (0 ends it) + +*****************************************************************************/ static void *pvr_proc_seq_start (struct seq_file *proc_seq_file, loff_t *pos) { PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)proc_seq_file->private; @@ -186,6 +309,20 @@ static void *pvr_proc_seq_start (struct seq_file *proc_seq_file, loff_t *pos) return handlers->off2element(proc_seq_file, *pos); } +/*! +****************************************************************************** + + @Function : pvr_proc_seq_stop + + @Description + Seq_file stop function. Detailed description of seq_file workflow can + be found here: http://tldp.org/LDP/lkmpg/2.6/html/x861.html. + + @Input proc_seq_file : sequence file entry + + @Input v : current element pointer + +*****************************************************************************/ static void pvr_proc_seq_stop (struct seq_file *proc_seq_file, void *v) { PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)proc_seq_file->private; @@ -195,6 +332,25 @@ static void pvr_proc_seq_stop (struct seq_file *proc_seq_file, void *v) handlers->startstop(proc_seq_file, IMG_FALSE); } +/*! +****************************************************************************** + + @Function : pvr_proc_seq_next + + @Description + Seq_file next element function. Detailed description of seq_file workflow can + be found here: http://tldp.org/LDP/lkmpg/2.6/html/x861.html. + It uses supplied 'next' handler for fetching next element (or 0 if there is no one) + + @Input proc_seq_file : sequence file entry + + @Input pos : offset within file (id of entry) + + @Input v : current element pointer + + @Return : next element pointer (or 0 if end) + +*****************************************************************************/ static void *pvr_proc_seq_next (struct seq_file *proc_seq_file, void *v, loff_t *pos) { PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)proc_seq_file->private; @@ -204,6 +360,23 @@ static void *pvr_proc_seq_next (struct seq_file *proc_seq_file, void *v, loff_t return handlers->off2element(proc_seq_file, *pos); } +/*! +****************************************************************************** + + @Function : pvr_proc_seq_show + + @Description + Seq_file show element function. Detailed description of seq_file workflow can + be found here: http://tldp.org/LDP/lkmpg/2.6/html/x861.html. + It call proper 'show' handler to show (dump) current element using seq_* functions + + @Input proc_seq_file : sequence file entry + + @Input v : current element pointer + + @Return : 0 if everything is OK + +*****************************************************************************/ static int pvr_proc_seq_show (struct seq_file *proc_seq_file, void *v) { PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)proc_seq_file->private; @@ -213,6 +386,38 @@ static int pvr_proc_seq_show (struct seq_file *proc_seq_file, void *v) +/*! +****************************************************************************** + + @Function : CreateProcEntryInDirSeq + + @Description + + Create a file under the given directory. These dynamic files can be used at + runtime to get or set information about the device. Whis version uses seq_file + interface + + @Input pdir : parent directory + + @Input name : the name of the file to create + + @Input data : aditional data that will be passed to handlers + + @Input next_handler : the function to call to provide the next element. OPTIONAL, if not + supplied, then off2element function is used instead + + @Input show_handler : the function to call to show element + + @Input off2element_handler : the function to call when it is needed to translate offest to element + + @Input startstop_handler : the function to call when output memory page starts or stops. OPTIONAL. + + @Input whandler : the function to interpret writes from the user + + @Return Ptr to proc entry , 0 for failure + + +*****************************************************************************/ static struct proc_dir_entry* CreateProcEntryInDirSeq( struct proc_dir_entry *pdir, const IMG_CHAR * name, @@ -259,7 +464,7 @@ static struct proc_dir_entry* CreateProcEntryInDirSeq( file->proc_fops = &pvr_proc_operations; file->write_proc = whandler; - + /* Pass the handlers */ file->data = kmalloc(sizeof(PVR_PROC_SEQ_HANDLERS), GFP_KERNEL); if(file->data) { @@ -279,6 +484,35 @@ static struct proc_dir_entry* CreateProcEntryInDirSeq( } +/*! +****************************************************************************** + + @Function : CreateProcReadEntrySeq + + @Description + + Create a file under /proc/pvr. These dynamic files can be used at runtime + to get information about the device. Creation WILL fail if proc support is + not compiled into the kernel. That said, the Linux kernel is not even happy + to build without /proc support these days. This version uses seq_file structure + for handling content generation. + + @Input name : the name of the file to create + + @Input data : aditional data that will be passed to handlers + + @Input next_handler : the function to call to provide the next element. OPTIONAL, if not + supplied, then off2element function is used instead + + @Input show_handler : the function to call to show element + + @Input off2element_handler : the function to call when it is needed to translate offest to element + + @Input startstop_handler : the function to call when output memory page starts or stops. OPTIONAL. + + @Return Ptr to proc entry , 0 for failure + +*****************************************************************************/ struct proc_dir_entry* CreateProcReadEntrySeq ( const IMG_CHAR * name, IMG_VOID* data, @@ -297,6 +531,40 @@ struct proc_dir_entry* CreateProcReadEntrySeq ( NULL); } +/*! +****************************************************************************** + + @Function : CreateProcEntrySeq + + @Description + + @Description + + Create a file under /proc/pvr. These dynamic files can be used at runtime + to get information about the device. Creation WILL fail if proc support is + not compiled into the kernel. That said, the Linux kernel is not even happy + to build without /proc support these days. This version uses seq_file structure + for handling content generation and is fuller than CreateProcReadEntrySeq (it + supports write access); + + @Input name : the name of the file to create + + @Input data : aditional data that will be passed to handlers + + @Input next_handler : the function to call to provide the next element. OPTIONAL, if not + supplied, then off2element function is used instead + + @Input show_handler : the function to call to show element + + @Input off2element_handler : the function to call when it is needed to translate offest to element + + @Input startstop_handler : the function to call when output memory page starts or stops. OPTIONAL. + + @Input whandler : the function to interpret writes from the user + + @Return Ptr to proc entry , 0 for failure + +*****************************************************************************/ struct proc_dir_entry* CreateProcEntrySeq ( const IMG_CHAR * name, IMG_VOID* data, @@ -321,6 +589,37 @@ struct proc_dir_entry* CreateProcEntrySeq ( +/*! +****************************************************************************** + + @Function : CreatePerProcessProcEntrySeq + + @Description + + Create a file under /proc/pvr/<current process ID>. Apart from the + directory where the file is created, this works the same way as + CreateProcEntry. It's seq_file version. + + + + @Input name : the name of the file to create + + @Input data : aditional data that will be passed to handlers + + @Input next_handler : the function to call to provide the next element. OPTIONAL, if not + supplied, then off2element function is used instead + + @Input show_handler : the function to call to show element + + @Input off2element_handler : the function to call when it is needed to translate offest to element + + @Input startstop_handler : the function to call when output memory page starts or stops. OPTIONAL. + + @Input whandler : the function to interpret writes from the user + + @Return Ptr to proc entry , 0 for failure + +*****************************************************************************/ struct proc_dir_entry* CreatePerProcessProcEntrySeq ( const IMG_CHAR * name, IMG_VOID* data, @@ -379,6 +678,20 @@ struct proc_dir_entry* CreatePerProcessProcEntrySeq ( } +/*! +****************************************************************************** + + @Function : RemoveProcEntrySeq + + @Description + + Remove a single node (created using *Seq function) under /proc/pvr. + + @Input proc_entry : structure returned by Create function. + + @Return nothing + +*****************************************************************************/ IMG_VOID RemoveProcEntrySeq( struct proc_dir_entry* proc_entry ) { if (dir) @@ -393,6 +706,22 @@ IMG_VOID RemoveProcEntrySeq( struct proc_dir_entry* proc_entry ) } } +/*! +****************************************************************************** + + @Function : RemovePerProcessProcEntry Seq + + @Description + + Remove a single node under the per process proc directory (created by *Seq function). + + Remove a single node (created using *Seq function) under /proc/pvr. + + @Input proc_entry : structure returned by Create function. + + @Return nothing + +*****************************************************************************/ IMG_VOID RemovePerProcessProcEntrySeq(struct proc_dir_entry* proc_entry) { PVRSRV_ENV_PER_PROCESS_DATA *psPerProc; @@ -420,10 +749,46 @@ IMG_VOID RemovePerProcessProcEntrySeq(struct proc_dir_entry* proc_entry) } } +/*! +****************************************************************************** + + @Function : pvr_read_proc_vm + + @Description + + When the user accesses the proc filesystem entry for the device, we are + called here to create the content for the 'file'. We can print anything we + want here. If the info we want to return is too big for one page ('count' + chars), we return successive chunks on each call. For a number of ways of + achieving this, refer to proc_file_read() in linux/fs/proc/generic.c. + + Here, as we are accessing lists of information, we output '1' in '*start' to + instruct proc to advance 'off' by 1 on each call. The number of chars placed + in the buffer is returned. Multiple calls are made here by the proc + filesystem until we set *eof. We can return zero without setting eof to + instruct proc to flush 'page' (causing it to be printed) if there is not + enough space left (eg for a complete line). + + @Input page : where to write the output + + @Input start : memory location into which should be written next offset + to read from. + + @Input off : the offset into the /proc file being read + + @Input count : the size of the buffer 'page' + + @Input eof : memory location into which 1 should be written when at EOF + + @Input data : data specific to this /proc file entry + + @Return : length of string written to page + +*****************************************************************************/ static IMG_INT pvr_read_proc(IMG_CHAR *page, IMG_CHAR **start, off_t off, IMG_INT count, IMG_INT *eof, IMG_VOID *data) { - + /* PRQA S 0307 1 */ /* ignore warning about casting to different pointer type */ pvr_read_proc_t *pprn = (pvr_read_proc_t *)data; off_t len = pprn (page, (size_t)count, off); @@ -433,9 +798,9 @@ static IMG_INT pvr_read_proc(IMG_CHAR *page, IMG_CHAR **start, off_t off, len = 0; *eof = 1; } - else if (!len) + else if (!len) /* not enough space in the buffer */ { - *start = (IMG_CHAR *) 0; + *start = (IMG_CHAR *) 0; /* don't advance the offset */ } else { @@ -446,6 +811,27 @@ static IMG_INT pvr_read_proc(IMG_CHAR *page, IMG_CHAR **start, off_t off, } +/*! +****************************************************************************** + + @Function : CreateProcEntryInDir + + @Description + + Create a file under the given directory. These dynamic files can be used at + runtime to get or set information about the device. + + @Input pdir : parent directory + + @Input name : the name of the file to create + + @Input rhandler : the function to supply the content + + @Input whandler : the function to interpret writes from the user + + @Return success code : 0 or -errno. + +*****************************************************************************/ static IMG_INT CreateProcEntryInDir(struct proc_dir_entry *pdir, const IMG_CHAR * name, read_proc_t rhandler, write_proc_t whandler, IMG_VOID *data) { struct proc_dir_entry * file; @@ -492,12 +878,54 @@ static IMG_INT CreateProcEntryInDir(struct proc_dir_entry *pdir, const IMG_CHAR } +/*! +****************************************************************************** + + @Function : CreateProcEntry + + @Description + + Create a file under /proc/pvr. These dynamic files can be used at runtime + to get or set information about the device. + + This interface is fuller than CreateProcReadEntry, and supports write access; + it is really just a wrapper for the native linux functions. + + @Input name : the name of the file to create under /proc/pvr + + @Input rhandler : the function to supply the content + + @Input whandler : the function to interpret writes from the user + + @Return success code : 0 or -errno. + +*****************************************************************************/ IMG_INT CreateProcEntry(const IMG_CHAR * name, read_proc_t rhandler, write_proc_t whandler, IMG_VOID *data) { return CreateProcEntryInDir(dir, name, rhandler, whandler, data); } +/*! +****************************************************************************** + + @Function : CreatePerProcessProcEntry + + @Description + + Create a file under /proc/pvr/<current process ID>. Apart from the + directory where the file is created, this works the same way as + CreateProcEntry. + + @Input name : the name of the file to create under the per process /proc directory + + @Input rhandler : the function to supply the content + + @Input whandler : the function to interpret writes from the user + + @Return success code : 0 or -errno. + +*****************************************************************************/ IMG_INT CreatePerProcessProcEntry(const IMG_CHAR * name, read_proc_t rhandler, write_proc_t whandler, IMG_VOID *data) { PVRSRV_ENV_PER_PROCESS_DATA *psPerProc; @@ -549,6 +977,25 @@ IMG_INT CreatePerProcessProcEntry(const IMG_CHAR * name, read_proc_t rhandler, w } +/*! +****************************************************************************** + + @Function : CreateProcReadEntry + + @Description + + Create a file under /proc/pvr. These dynamic files can be used at runtime + to get information about the device. Creation WILL fail if proc support is + not compiled into the kernel. That said, the Linux kernel is not even happy + to build without /proc support these days. + + @Input name : the name of the file to create + + @Input handler : the function to call to provide the content + + @Return 0 for success, -errno for failure + +*****************************************************************************/ IMG_INT CreateProcReadEntry(const IMG_CHAR * name, pvr_read_proc_t handler) { struct proc_dir_entry * file; @@ -560,7 +1007,7 @@ IMG_INT CreateProcReadEntry(const IMG_CHAR * name, pvr_read_proc_t handler) return -ENOMEM; } - + /* PRQA S 0307 1 */ /* ignore warning about casting to different pointer type */ file = create_proc_read_entry (name, S_IFREG | S_IRUGO, dir, pvr_read_proc, (IMG_VOID *)handler); if (file) @@ -577,6 +1024,23 @@ IMG_INT CreateProcReadEntry(const IMG_CHAR * name, pvr_read_proc_t handler) } +/*! +****************************************************************************** + + @Function : CreateProcEntries + + @Description + + Create a directory /proc/pvr and the necessary entries within it. These + dynamic files can be used at runtime to get information about the device. + Creation might fail if proc support is not compiled into the kernel or if + there is no memory + + @Input none + + @Return nothing + +*****************************************************************************/ IMG_INT CreateProcEntries(IMG_VOID) { dir = proc_mkdir (PVRProcDirRoot, NULL); @@ -631,6 +1095,20 @@ IMG_INT CreateProcEntries(IMG_VOID) } +/*! +****************************************************************************** + + @Function : RemoveProcEntry + + @Description + + Remove a single node under /proc/pvr. + + @Input name : the name of the node to remove + + @Return nothing + +*****************************************************************************/ IMG_VOID RemoveProcEntry(const IMG_CHAR * name) { if (dir) @@ -641,6 +1119,20 @@ IMG_VOID RemoveProcEntry(const IMG_CHAR * name) } +/*! +****************************************************************************** + + @Function : RemovePerProcessProcEntry + + @Description + + Remove a single node under the per process proc directory. + + @Input name : the name of the node to remove + + @Return nothing + +*****************************************************************************/ IMG_VOID RemovePerProcessProcEntry(const IMG_CHAR *name) { PVRSRV_ENV_PER_PROCESS_DATA *psPerProc; @@ -666,6 +1158,20 @@ IMG_VOID RemovePerProcessProcEntry(const IMG_CHAR *name) } +/*! +****************************************************************************** + + @Function : RemovePerProcessProcDir + + @Description + + Remove the per process directorty under /proc/pvr. + + @Input psPerProc : environment specific per process data + + @Return nothing + +*****************************************************************************/ IMG_VOID RemovePerProcessProcDir(PVRSRV_ENV_PER_PROCESS_DATA *psPerProc) { if (psPerProc->psProcDir) @@ -680,13 +1186,28 @@ IMG_VOID RemovePerProcessProcDir(PVRSRV_ENV_PER_PROCESS_DATA *psPerProc) } } +/*! +****************************************************************************** + + @Function : RemoveProcEntries + + Description + + Proc filesystem entry deletion - Remove all proc filesystem entries for + the driver. + + @Input none + + @Return nothing + +*****************************************************************************/ IMG_VOID RemoveProcEntries(IMG_VOID) { #ifdef DEBUG RemoveProcEntrySeq( g_pProcDebugLevel ); #ifdef PVR_MANUAL_POWER_CONTROL RemoveProcEntrySeq( g_pProcPowerLevel ); -#endif +#endif /* PVR_MANUAL_POWER_CONTROL */ #endif RemoveProcEntrySeq(g_pProcQueue); @@ -703,6 +1224,14 @@ IMG_VOID RemoveProcEntries(IMG_VOID) remove_proc_entry(PVRProcDirRoot, NULL); } +/***************************************************************************** + FUNCTION : ProcSeqShowVersion + + PURPOSE : Print the content of version to /proc file + + PARAMETERS : sfile - /proc seq_file + el - Element to print +*****************************************************************************/ static void ProcSeqShowVersion(struct seq_file *sfile,void* el) { SYS_DATA *psSysData; @@ -726,6 +1255,24 @@ static void ProcSeqShowVersion(struct seq_file *sfile,void* el) seq_printf( sfile, "System Version String: %s\n", pszSystemVersionString); } +/*! +****************************************************************************** + + @Function procDumpSysNodes (plus deviceTypeToString and deviceClassToString) + + @Description + + Format the contents of /proc/pvr/nodes + + @Input buf : where to place format contents data. + + @Input size : the size of the buffer into which to place data + + @Input off : how far into the file we are. + + @Return amount of data placed in buffer, 0, or END_OF_FILE : + +******************************************************************************/ static const IMG_CHAR *deviceTypeToString(PVRSRV_DEVICE_TYPE deviceType) { switch (deviceType) @@ -781,6 +1328,14 @@ static IMG_VOID* DecOffPsDev_AnyVaCb(PVRSRV_DEVICE_NODE *psNode, va_list va) } } +/***************************************************************************** + FUNCTION : ProcSeqShowSysNodes + + PURPOSE : Print the content of version to /proc file + + PARAMETERS : sfile - /proc seq_file + el - Element to print +*****************************************************************************/ static void ProcSeqShowSysNodes(struct seq_file *sfile,void* el) { PVRSRV_DEVICE_NODE *psDevNode; @@ -807,6 +1362,16 @@ static void ProcSeqShowSysNodes(struct seq_file *sfile,void* el) psDevNode->hResManContext); } +/***************************************************************************** + FUNCTION : ProcSeqOff2ElementSysNodes + + PURPOSE : Transale offset to element (/proc stuff) + + PARAMETERS : sfile - /proc seq_file + off - the offset into the buffer + + RETURNS : element to print +*****************************************************************************/ static void* ProcSeqOff2ElementSysNodes(struct seq_file * sfile, loff_t off) { SYS_DATA *psSysData; @@ -822,14 +1387,17 @@ static void* ProcSeqOff2ElementSysNodes(struct seq_file * sfile, loff_t off) psSysData = SysAcquireDataNoCheck(); if (psSysData != IMG_NULL) { - + /* Find Dev Node */ psDevNode = (PVRSRV_DEVICE_NODE*) List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, DecOffPsDev_AnyVaCb, &off); } - + /* Return anything that is not PVR_RPOC_SEQ_START_TOKEN and NULL */ return (void*)psDevNode; } +/***************************************************************************** + End of file (proc.c) +*****************************************************************************/ diff --git a/sgx/services4/srvkm/env/linux/proc.h b/sgx/services4/srvkm/env/linux/proc.h index 2066d71..67cded7 100644 --- a/sgx/services4/srvkm/env/linux/proc.h +++ b/sgx/services4/srvkm/env/linux/proc.h @@ -1,35 +1,53 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Proc interface definition. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Functions for creating and reading proc filesystem entries. + Refer to proc.c +@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. + +*/ /**************************************************************************/ #ifndef __SERVICES_PROC_H__ #define __SERVICES_PROC_H__ -#include <asm/system.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> +#include <asm/system.h> // va_list etc +#include <linux/proc_fs.h> // read_proc_t etc +#include <linux/seq_file.h> // seq_file #define END_OF_FILE (off_t) -1 @@ -51,8 +69,10 @@ typedef struct _PVR_PROC_SEQ_HANDLERS_ { } PVR_PROC_SEQ_HANDLERS; +/** off2element function for elements with only ONE element (no header) */ void* ProcSeq1ElementOff2Element(struct seq_file *sfile, loff_t off); +/** off2element function for elements with only ONE element (+ header) */ void* ProcSeq1ElementHeaderOff2Element(struct seq_file *sfile, loff_t off); off_t printAppend(IMG_CHAR * buffer, size_t size, off_t off, const IMG_CHAR * format, ...) diff --git a/sgx/services4/srvkm/env/linux/pvr_bridge_k.c b/sgx/services4/srvkm/env/linux/pvr_bridge_k.c index 373b586..037b4c9 100644 --- a/sgx/services4/srvkm/env/linux/pvr_bridge_k.c +++ b/sgx/services4/srvkm/env/linux/pvr_bridge_k.c @@ -1,28 +1,46 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title PVR Bridge Module (kernel side) +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Receives calls from the user portion of services and + despatches them to functions in the kernel portion. +@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 "img_defs.h" #include "services.h" @@ -36,6 +54,8 @@ #include "linkage.h" #include "pvr_bridge_km.h" #include "pvr_uaccess.h" +#include "refcount.h" +#include "buffer_manager.h" #if defined(SUPPORT_DRI_DRM) #include <drm/drmP.h> @@ -45,10 +65,12 @@ #endif #endif +/* VGX: */ #if defined(SUPPORT_VGX) #include "vgx_bridge.h" #endif +/* SGX: */ #if defined(SUPPORT_SGX) #include "sgx_bridge.h" #endif @@ -69,7 +91,7 @@ extern PVRSRV_LINUX_MUTEX gPVRSRVLock; #if defined(SUPPORT_MEMINFO_IDS) static IMG_UINT64 ui64Stamp; -#endif +#endif /* defined(SUPPORT_MEMINFO_IDS) */ PVRSRV_ERROR LinuxBridgeInit(IMG_VOID) @@ -103,6 +125,13 @@ LinuxBridgeDeInit(IMG_VOID) #if defined(DEBUG_BRIDGE_KM) +/* + * Lock MMap regions list (called on page start/stop while reading /proc/mmap) + * + * sfile : seq_file that handles /proc file + * start : TRUE if it's start, FALSE if it's stop + * + */ static void ProcSeqStartstopBridgeStats(struct seq_file *sfile,IMG_BOOL start) { if(start) @@ -116,6 +145,16 @@ static void ProcSeqStartstopBridgeStats(struct seq_file *sfile,IMG_BOOL start) } +/* + * Convert offset (index from KVOffsetTable) to element + * (called when reading /proc/mmap file) + + * sfile : seq_file that handles /proc file + * off : index into the KVOffsetTable from which to print + * + * returns void* : Pointer to element that will be dumped + * +*/ static void* ProcSeqOff2ElementBridgeStats(struct seq_file *sfile, loff_t off) { if(!off) @@ -132,12 +171,28 @@ static void* ProcSeqOff2ElementBridgeStats(struct seq_file *sfile, loff_t off) return (void*)&g_BridgeDispatchTable[off-1]; } +/* + * Gets next MMap element to show. (called when reading /proc/mmap file) + + * sfile : seq_file that handles /proc file + * el : actual element + * off : index into the KVOffsetTable from which to print + * + * returns void* : Pointer to element to show (0 ends iteration) +*/ static void* ProcSeqNextBridgeStats(struct seq_file *sfile,void* el,loff_t off) { return ProcSeqOff2ElementBridgeStats(sfile,off); } +/* + * Show MMap element (called when reading /proc/mmap file) + + * sfile : seq_file that handles /proc file + * el : actual element + * +*/ static void ProcSeqShowBridgeStats(struct seq_file *sfile,void* el) { PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY *psEntry = ( PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY*)el; @@ -172,7 +227,7 @@ static void ProcSeqShowBridgeStats(struct seq_file *sfile,void* el) psEntry->ui32CopyToUserTotalBytes); } -#endif +#endif /* DEBUG_BRIDGE_KM */ #if defined(SUPPORT_DRI_DRM) @@ -211,7 +266,9 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig goto unlock_and_return; } - + /* FIXME - Currently the CopyFromUserWrapper which collects stats about + * how much data is shifted to/from userspace isn't available to us + * here. */ if(OSCopyFromUser(IMG_NULL, psBridgePackageKM, psBridgePackageUM, @@ -249,7 +306,7 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig } else { - + /* lookup per-process data for this process */ psPerProc = PVRSRVPerProcessData(ui32PID); if(psPerProc == IMG_NULL) { @@ -328,7 +385,13 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig break; } - + /* + * The DRM file structure we are using for Services + * is not one that DRI authentication was done on. + * Look for an authenticated file structure for + * this process, making sure the DRM master is the + * same as ours. + */ psEnvPerProc = (PVRSRV_ENV_PER_PROCESS_DATA *)PVRSRVProcessPrivateData(psPerProc); if (psEnvPerProc == IMG_NULL) { @@ -362,7 +425,7 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig default: break; } -#endif +#endif /* defined(SUPPORT_DRI_DRM) && defined(PVR_SECURE_DRM_AUTH_EXPORT) */ #if defined(SUPPORT_DRI_DRM_EXTERNAL) { @@ -384,15 +447,40 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig PVRSRV_BRIDGE_OUT_EXPORTDEVICEMEM *psExportDeviceMemOUT = (PVRSRV_BRIDGE_OUT_EXPORTDEVICEMEM *)psBridgePackageKM->pvParamOut; PVRSRV_FILE_PRIVATE_DATA *psPrivateData = get_private(pFile); + IMG_HANDLE hMemInfo; + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; - if (pvr_get_user(psPrivateData->hKernelMemInfo, &psExportDeviceMemOUT->hMemInfo) != 0) + if (pvr_get_user(hMemInfo, &psExportDeviceMemOUT->hMemInfo) != 0) { err = -EFAULT; goto unlock_and_return; } + + /* Look up the meminfo we just exported */ + if(PVRSRVLookupHandle(KERNEL_HANDLE_BASE, + (IMG_PVOID *)&psKernelMemInfo, + hMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "%s: Failed to look up export handle", __FUNCTION__)); + err = -EFAULT; + goto unlock_and_return; + } + + /* Bump the refcount; decremented on release of the fd */ + PVRSRVKernelMemInfoIncRef(psKernelMemInfo); + + /* Tell the XProc about the export if required */ + if (psKernelMemInfo->sShareMemWorkaround.bInUse) + { + BM_XProcIndexAcquire(psKernelMemInfo->sShareMemWorkaround.ui32ShareIndex); + } + + psPrivateData->hKernelMemInfo = hMemInfo; #if defined(SUPPORT_MEMINFO_IDS) psPrivateData->ui64Stamp = ++ui64Stamp; + psKernelMemInfo->ui64Stamp = psPrivateData->ui64Stamp; if (pvr_put_user(psPrivateData->ui64Stamp, &psExportDeviceMemOUT->ui64Stamp) != 0) { err = -EFAULT; @@ -404,6 +492,7 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig #if defined(SUPPORT_MEMINFO_IDS) case PVRSRV_BRIDGE_MAP_DEV_MEMORY: + case PVRSRV_BRIDGE_MAP_DEV_MEMORY_2: { PVRSRV_BRIDGE_OUT_MAP_DEV_MEMORY *psMapDeviceMemoryOUT = (PVRSRV_BRIDGE_OUT_MAP_DEV_MEMORY *)psBridgePackageKM->pvParamOut; @@ -427,7 +516,7 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig } break; } -#endif +#endif /* defined(SUPPORT_MEMINFO_IDS) */ default: break; diff --git a/sgx/services4/srvkm/env/linux/pvr_debug.c b/sgx/services4/srvkm/env/linux/pvr_debug.c index 7690875..ad3e32b 100644 --- a/sgx/services4/srvkm/env/linux/pvr_debug.c +++ b/sgx/services4/srvkm/env/linux/pvr_debug.c @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Debug Functionality +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Provides kernel side Debug Functionality +@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 <linux/version.h> @@ -38,7 +55,7 @@ #include <linux/hardirq.h> #include <linux/module.h> #include <linux/spinlock.h> -#include <linux/string.h> +#include <linux/string.h> // strncpy, strlen #include <stdarg.h> #include "img_types.h" #include "servicesext.h" @@ -49,6 +66,10 @@ #include "linkage.h" #include "pvr_uaccess.h" +#if !defined(CONFIG_PREEMPT) +#define PVR_DEBUG_ALWAYS_USE_SPINLOCK +#endif + static IMG_BOOL VBAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR* pszFormat, va_list VArgs) IMG_FORMAT_PRINTF(3, 0); @@ -62,67 +83,96 @@ static IMG_BOOL BAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR *pszFormat, ...) IMG_FORMAT_PRINTF(3, 4); +/* NOTE: Must NOT be static! Used in module.c.. */ IMG_UINT32 gPVRDebugLevel = (DBGPRIV_FATAL | DBGPRIV_ERROR | DBGPRIV_WARNING); -#endif +#endif /* defined(PVRSRV_NEED_PVR_DPF) || defined(PVRSRV_NEED_PVR_TRACE) */ #define PVR_MAX_MSG_LEN PVR_MAX_DEBUG_MESSAGE_LEN +#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK) +/* Message buffer for non-IRQ messages */ static IMG_CHAR gszBufferNonIRQ[PVR_MAX_MSG_LEN + 1]; +#endif +/* Message buffer for IRQ messages */ static IMG_CHAR gszBufferIRQ[PVR_MAX_MSG_LEN + 1]; +#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK) +/* The lock is used to control access to gszBufferNonIRQ */ static PVRSRV_LINUX_MUTEX gsDebugMutexNonIRQ; +#endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)) +/* The lock is used to control access to gszBufferIRQ */ +/* PRQA S 0671,0685 1 */ /* ignore warnings about C99 style initialisation */ static spinlock_t gsDebugLockIRQ = SPIN_LOCK_UNLOCKED; #else -static spinlock_t gsDebugLockIRQ = __SPIN_LOCK_UNLOCKED(gsDebugLockIRQ); +static DEFINE_SPINLOCK(gsDebugLockIRQ); #endif -#if !defined (USE_SPIN_LOCK) +#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK) +#if !defined (USE_SPIN_LOCK) /* to keep QAC happy */ #define USE_SPIN_LOCK (in_interrupt() || !preemptible()) #endif +#endif static inline void GetBufferLock(unsigned long *pulLockFlags) { +#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK) if (USE_SPIN_LOCK) +#endif { spin_lock_irqsave(&gsDebugLockIRQ, *pulLockFlags); } +#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK) else { LinuxLockMutex(&gsDebugMutexNonIRQ); } +#endif } static inline void ReleaseBufferLock(unsigned long ulLockFlags) { +#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK) if (USE_SPIN_LOCK) +#endif { spin_unlock_irqrestore(&gsDebugLockIRQ, ulLockFlags); } +#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK) else { LinuxUnLockMutex(&gsDebugMutexNonIRQ); } +#endif } static inline void SelectBuffer(IMG_CHAR **ppszBuf, IMG_UINT32 *pui32BufSiz) { +#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK) if (USE_SPIN_LOCK) +#endif { *ppszBuf = gszBufferIRQ; *pui32BufSiz = sizeof(gszBufferIRQ); } +#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK) else { *ppszBuf = gszBufferNonIRQ; *pui32BufSiz = sizeof(gszBufferNonIRQ); } +#endif } +/* + * Append a string to a buffer using formatted conversion. + * The function takes a variable number of arguments, pointed + * to by the var args list. + */ static IMG_BOOL VBAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR* pszFormat, va_list VArgs) { IMG_UINT32 ui32Used; @@ -136,15 +186,27 @@ static IMG_BOOL VBAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR i32Len = vsnprintf(&pszBuf[ui32Used], ui32Space, pszFormat, VArgs); pszBuf[ui32BufSiz - 1] = 0; - + /* Return true if string was truncated */ return (i32Len < 0 || i32Len >= (IMG_INT32)ui32Space) ? IMG_TRUE : IMG_FALSE; } +/* Actually required for ReleasePrintf too */ + IMG_VOID PVRDPFInit(IMG_VOID) { +#if !defined(PVR_DEBUG_ALWAYS_USE_SPINLOCK) LinuxInitMutex(&gsDebugMutexNonIRQ); +#endif } +/*! +****************************************************************************** + @Function PVRSRVReleasePrintf + @Description To output an important message to the user in release builds + @Input pszFormat - The message format string + @Input ... - Zero or more arguments for use by the format string + @Return None + ******************************************************************************/ IMG_VOID PVRSRVReleasePrintf(const IMG_CHAR *pszFormat, ...) { va_list vaArgs; @@ -173,18 +235,16 @@ IMG_VOID PVRSRVReleasePrintf(const IMG_CHAR *pszFormat, ...) } -#if defined(PVRSRV_NEED_PVR_ASSERT) - -IMG_VOID PVRSRVDebugAssertFail(const IMG_CHAR* pszFile, IMG_UINT32 uLine) -{ - PVRSRVDebugPrintf(DBGPRIV_FATAL, pszFile, uLine, "Debug assertion failed!"); - BUG(); -} - -#endif - #if defined(PVRSRV_NEED_PVR_TRACE) +/*! +****************************************************************************** + @Function PVRTrace + @Description To output a debug message to the user + @Input pszFormat - The message format string + @Input ... - Zero or more arguments for use by the format string + @Return None + ******************************************************************************/ IMG_VOID PVRSRVTrace(const IMG_CHAR* pszFormat, ...) { va_list VArgs; @@ -214,10 +274,15 @@ IMG_VOID PVRSRVTrace(const IMG_CHAR* pszFormat, ...) va_end(VArgs); } -#endif +#endif /* defined(PVRSRV_NEED_PVR_TRACE) */ #if defined(PVRSRV_NEED_PVR_DPF) +/* + * Append a string to a buffer using formatted conversion. + * The function takes a variable number of arguments, calling + * VBAppend to do the actual work. + */ static IMG_BOOL BAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR *pszFormat, ...) { va_list VArgs; @@ -232,6 +297,17 @@ static IMG_BOOL BAppend(IMG_CHAR *pszBuf, IMG_UINT32 ui32BufSiz, const IMG_CHAR return bTrunc; } +/*! +****************************************************************************** + @Function PVRSRVDebugPrintf + @Description To output a debug message to the user + @Input uDebugLevel - The current debug level + @Input pszFile - The source file generating the message + @Input uLine - The line of the source file + @Input pszFormat - The message format string + @Input ... - Zero or more arguments for use by the format string + @Return None + ******************************************************************************/ IMG_VOID PVRSRVDebugPrintf ( IMG_UINT32 ui32DebugLevel, const IMG_CHAR* pszFullFileName, @@ -260,7 +336,7 @@ IMG_VOID PVRSRVDebugPrintf ( GetBufferLock(&ulLockFlags); - + /* Add in the level of warning */ if (bTrace == IMG_FALSE) { switch(ui32DebugLevel) @@ -308,21 +384,22 @@ IMG_VOID PVRSRVDebugPrintf ( } else { - + /* Traces don't need a location */ if (bTrace == IMG_FALSE) { #ifdef DEBUG_LOG_PATH_TRUNCATE - + /* Buffer for rewriting filepath in log messages */ static IMG_CHAR szFileNameRewrite[PVR_MAX_FILEPATH_LEN]; IMG_CHAR* pszTruncIter; IMG_CHAR* pszTruncBackInter; - + /* Truncate path (DEBUG_LOG_PATH_TRUNCATE shoud be set to EURASIA env var)*/ if (strlen(pszFullFileName) > strlen(DEBUG_LOG_PATH_TRUNCATE)+1) pszFileName = pszFullFileName + strlen(DEBUG_LOG_PATH_TRUNCATE)+1; - + /* Try to find '/../' entries and remove it together with + previous entry. Repeat unit all removed */ strncpy(szFileNameRewrite, pszFileName,PVR_MAX_FILEPATH_LEN); if(strlen(szFileNameRewrite) == PVR_MAX_FILEPATH_LEN-1) { @@ -334,7 +411,7 @@ IMG_VOID PVRSRVDebugPrintf ( while(*pszTruncIter++ != 0) { IMG_CHAR* pszNextStartPoint; - + /* Find '/../' pattern */ if( !( ( *pszTruncIter == '/' && (pszTruncIter-4 >= szFileNameRewrite) ) && ( *(pszTruncIter-1) == '.') && @@ -342,7 +419,7 @@ IMG_VOID PVRSRVDebugPrintf ( ( *(pszTruncIter-3) == '/') ) ) continue; - + /* Find previous '/' */ pszTruncBackInter = pszTruncIter - 3; while(*(--pszTruncBackInter) != '/') { @@ -350,19 +427,19 @@ IMG_VOID PVRSRVDebugPrintf ( } pszNextStartPoint = pszTruncBackInter; - + /* Remove found region */ while(*pszTruncIter != 0) { *pszTruncBackInter++ = *pszTruncIter++; } *pszTruncBackInter = 0; - + /* Start again */ pszTruncIter = pszNextStartPoint; } pszFileName = szFileNameRewrite; - + /* Remove first '/' if exist (it's always relative path */ if(*pszFileName == '/') pszFileName++; #endif @@ -373,7 +450,7 @@ IMG_VOID PVRSRVDebugPrintf ( { pszFileName = pszLeafName; } -#endif +#endif /* __sh__ */ if (BAppend(pszBuf, ui32BufSiz, " [%u, %s]", ui32Line, pszFileName)) { @@ -396,16 +473,16 @@ IMG_VOID PVRSRVDebugPrintf ( } } -#endif +#endif /* PVRSRV_NEED_PVR_DPF */ #if defined(DEBUG) IMG_INT PVRDebugProcSetLevel(struct file *file, const IMG_CHAR *buffer, IMG_UINT32 count, IMG_VOID *data) { -#define _PROC_SET_BUFFER_SZ 2 +#define _PROC_SET_BUFFER_SZ 6 IMG_CHAR data_buffer[_PROC_SET_BUFFER_SZ]; - if (count != _PROC_SET_BUFFER_SZ) + if (count > _PROC_SET_BUFFER_SZ) { return -EINVAL; } @@ -415,7 +492,9 @@ IMG_INT PVRDebugProcSetLevel(struct file *file, const IMG_CHAR *buffer, IMG_UINT return -EINVAL; if (data_buffer[count - 1] != '\n') return -EINVAL; - gPVRDebugLevel = data_buffer[0] - '0'; + if (sscanf(data_buffer, "%i", &gPVRDebugLevel) == 0) + return -EINVAL; + gPVRDebugLevel &= (1 << DBGPRIV_DBGLEVEL_COUNT) - 1; } return (count); } @@ -425,4 +504,4 @@ void ProcSeqShowDebugLevel(struct seq_file *sfile,void* el) seq_printf(sfile, "%u\n", gPVRDebugLevel); } -#endif +#endif /* defined(DEBUG) */ diff --git a/sgx/services4/srvkm/env/linux/pvr_drm.c b/sgx/services4/srvkm/env/linux/pvr_drm.c index 620c158..c955bcf 100644 --- a/sgx/services4/srvkm/env/linux/pvr_drm.c +++ b/sgx/services4/srvkm/env/linux/pvr_drm.c @@ -1,29 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ - +/*************************************************************************/ /*! +@Title PowerVR drm driver +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description linux module setup +@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. + +*/ /**************************************************************************/ #if defined(SUPPORT_DRI_DRM) #include <linux/version.h> @@ -44,8 +60,9 @@ #include <drm/drmP.h> #include <drm/drm.h> -#ifdef SUPPORT_DRI_DRM_EXTERNAL +#if defined(SUPPORT_DRI_DRM_EXTERNAL) # include <linux/omap_drm.h> +# include <linux/omap_drv.h> #endif #include "img_defs.h" @@ -107,20 +124,20 @@ static struct platform_device_id asPlatIdList[] = { {} }; #endif -#else +#else /* defined(PVR_DRI_DRM_PLATFORM_DEV) */ static struct pci_device_id asPciIdList[] = { #if defined(PVR_DRI_DRM_NOT_PCI) {1, 1, 1, 1, 0, 0, 0}, -#else +#else /* defined(PVR_DRI_DRM_NOT_PCI) */ {SYS_SGX_DEV_VENDOR_ID, SYS_SGX_DEV_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, #if defined(SYS_SGX_DEV1_DEVICE_ID) {SYS_SGX_DEV_VENDOR_ID, SYS_SGX_DEV1_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#endif +#endif /* defined(SYS_SGX_DEV1_DEVICE_ID) */ +#endif /* defined(PVR_DRI_DRM_NOT_PCI) */ {0} }; -#endif -#endif +#endif /* defined(PVR_DRI_DRM_PLATFORM_DEV) */ +#endif /* !defined(SUPPORT_DRI_DRM_EXT) */ DRI_DRM_STATIC int PVRSRVDrmLoad(struct drm_device *dev, unsigned long flags) @@ -145,7 +162,7 @@ PVRSRVDrmLoad(struct drm_device *dev, unsigned long flags) goto exit; } #endif - + /* Module initialisation */ iRes = PVRCore_Init(); if (iRes != 0) { @@ -268,7 +285,10 @@ PVRSRVDrmRelease(struct inode *inode, struct file *filp) if (ret != 0) { - + /* + * An error means drm_release didn't call drm_lastclose, + * but it will have freed file_priv. + */ PVR_DPF((PVR_DBG_ERROR, "%s : drm_release failed: %d", __FUNCTION__, ret)); } @@ -352,13 +372,6 @@ PVRDRM_Display_ioctl(struct drm_device *dev, void *arg, struct drm_file *pFile) #endif #if !defined(SUPPORT_DRI_DRM_EXT) - -#if defined(DRM_IOCTL_DEF) -#define PVR_DRM_IOCTL_DEF(ioctl, _func, _flags) DRM_IOCTL_DEF(DRM_##ioctl, _func, _flags) -#else -#define PVR_DRM_IOCTL_DEF(ioctl, _func, _flags) DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) -#endif - struct drm_ioctl_desc sPVRDrmIoctls[] = { #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35)) DRM_IOCTL_DEF(PVR_DRM_SRVKM_IOCTL, PVRSRV_BridgeDispatchKM, PVR_DRM_UNLOCKED), @@ -403,7 +416,7 @@ static struct omap_drm_plugin plugin = { .num_ioctls = ARRAY_SIZE(sPVRDrmIoctls), .ioctl_base = 0, /* initialized when plugin is registered */ }; -#else +#else /* defined(SUPPORT_DRI_DRM_EXTERNAL) */ static struct drm_driver sPVRDrmDriver = { #if defined(PVR_DRI_DRM_PLATFORM_DEV) @@ -419,10 +432,8 @@ static struct drm_driver sPVRDrmDriver = .suspend = PVRSRVDriverSuspend, .resume = PVRSRVDriverResume, #endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)) .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, -#endif .ioctls = sPVRDrmIoctls, .fops = { @@ -482,7 +493,7 @@ PVRSRVDrmRemove(struct platform_device *pDevice) return 0; } -#endif +#endif static int __init PVRSRVDrmInit(void) { @@ -491,7 +502,7 @@ static int __init PVRSRVDrmInit(void) #if !defined(SUPPORT_DRI_DRM_EXTERNAL) sPVRDrmDriver.num_ioctls = pvr_max_ioctl; #endif - + PVRDPFInit(); #if defined(PVR_DRI_DRM_NOT_PCI) @@ -533,9 +544,14 @@ static void __exit PVRSRVDrmExit(void) #endif } +/* + * These macro calls define the initialisation and removal functions of the + * driver. Although they are prefixed `module_', they apply when compiling + * statically as well; in both cases they define the function the kernel will + * run to start/stop the driver. +*/ module_init(PVRSRVDrmInit); module_exit(PVRSRVDrmExit); -#endif -#endif - +#endif +#endif diff --git a/sgx/services4/srvkm/env/linux/pvr_drm.h b/sgx/services4/srvkm/env/linux/pvr_drm.h index 9d79602..5418c6d 100644 --- a/sgx/services4/srvkm/env/linux/pvr_drm.h +++ b/sgx/services4/srvkm/env/linux/pvr_drm.h @@ -1,29 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title PowerVR drm driver +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description drm module +@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. + +*/ /**************************************************************************/ #if !defined(__PVR_DRM_H__) #define __PVR_DRM_H__ @@ -57,6 +73,7 @@ int PVRSRV_BridgeDispatchKM(struct drm_device *dev, void *arg, struct drm_file * #if defined(SUPPORT_DRI_DRM_EXT) #define DRI_DRM_STATIC +/*Exported functions to common drm layer*/ int PVRSRVDrmLoad(struct drm_device *dev, unsigned long flags); int PVRSRVDrmUnload(struct drm_device *dev); int PVRSRVDrmOpen(struct drm_device *dev, struct drm_file *file); @@ -70,7 +87,7 @@ int PVRDRMUnprivCmd(struct drm_device *dev, IMG_VOID *arg, struct drm_file *pFil int PVRDRM_Dummy_ioctl(struct drm_device *dev, IMG_VOID *arg, struct drm_file *pFile); #else #define DRI_DRM_STATIC static -#endif +#endif /* defined(SUPPORT_DRI_DRM_EXT) */ #if defined(DISPLAY_CONTROLLER) extern int PVR_DRM_MAKENAME(DISPLAY_CONTROLLER, _Init)(struct drm_device *); @@ -102,6 +119,7 @@ IMG_INT dbgdrv_ioctl(struct drm_device *dev, IMG_VOID *arg, struct drm_file *pFi #define DRM_IOCTL_PVR_UNPRIV DRM_IO(DRM_COMMAND_BASE + DRM_PVR_UNPRIV) #define DRM_IOCTL_PVR_DBGDRV DRM_IO(DRM_COMMAND_BASE + DRM_PVR_DBGDRV) #endif + #endif #endif diff --git a/sgx/services4/srvkm/env/linux/pvr_uaccess.h b/sgx/services4/srvkm/env/linux/pvr_uaccess.h index 6e7f1d3..31c218b 100644 --- a/sgx/services4/srvkm/env/linux/pvr_uaccess.h +++ b/sgx/services4/srvkm/env/linux/pvr_uaccess.h @@ -1,29 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Utility functions for user space access +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #ifndef __PVR_UACCESS_H__ #define __PVR_UACCESS_H__ @@ -53,7 +68,10 @@ static inline unsigned long pvr_copy_to_user(void __user *pvTo, const void *pvFr static inline unsigned long pvr_copy_from_user(void *pvTo, const void __user *pvFrom, unsigned long ulBytes) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) - + /* + * The compile time correctness checking introduced for copy_from_user in + * Linux 2.6.33 isn't fully comaptible with our usage of the function. + */ if (access_ok(VERIFY_READ, pvFrom, ulBytes)) { return __copy_from_user(pvTo, pvFrom, ulBytes); @@ -67,5 +85,5 @@ static inline unsigned long pvr_copy_from_user(void *pvTo, const void __user *pv #define pvr_put_user put_user #define pvr_get_user get_user -#endif +#endif /* __PVR_UACCESS_H__ */ diff --git a/sgx/services4/srvkm/hwdefs/ocpdefs.h b/sgx/services4/srvkm/hwdefs/ocpdefs.h index 3bbab7b..cc4d54e 100644 --- a/sgx/services4/srvkm/hwdefs/ocpdefs.h +++ b/sgx/services4/srvkm/hwdefs/ocpdefs.h @@ -1,37 +1,55 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title OCP HW definitions. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #ifndef _OCPDEFS_H_ #define _OCPDEFS_H_ +/* Register EUR_CR_OCP_REVISION */ #define EUR_CR_OCP_REVISION 0xFE00 #define EUR_CR_OCP_REVISION_REV_MASK 0xFFFFFFFFUL #define EUR_CR_OCP_REVISION_REV_SHIFT 0 #define EUR_CR_OCP_REVISION_REV_SIGNED 0 +/* Register EUR_CR_OCP_HWINFO */ #define EUR_CR_OCP_HWINFO 0xFE04 #define EUR_CR_OCP_HWINFO_SYS_BUS_WIDTH_MASK 0x00000003UL #define EUR_CR_OCP_HWINFO_SYS_BUS_WIDTH_SHIFT 0 @@ -41,6 +59,7 @@ #define EUR_CR_OCP_HWINFO_MEM_BUS_WIDTH_SHIFT 2 #define EUR_CR_OCP_HWINFO_MEM_BUS_WIDTH_SIGNED 0 +/* Register EUR_CR_OCP_SYSCONFIG */ #define EUR_CR_OCP_SYSCONFIG 0xFE10 #define EUR_CR_OCP_SYSCONFIG_IDLE_MODE_MASK 0x0000000CUL #define EUR_CR_OCP_SYSCONFIG_IDLE_MODE_SHIFT 2 @@ -50,66 +69,79 @@ #define EUR_CR_OCP_SYSCONFIG_STANDBY_MODE_SHIFT 4 #define EUR_CR_OCP_SYSCONFIG_STANDBY_MODE_SIGNED 0 +/* Register EUR_CR_OCP_IRQSTATUS_RAW_0 */ #define EUR_CR_OCP_IRQSTATUS_RAW_0 0xFE24 #define EUR_CR_OCP_IRQSTATUS_RAW_0_INIT_MASK 0x00000001UL #define EUR_CR_OCP_IRQSTATUS_RAW_0_INIT_SHIFT 0 #define EUR_CR_OCP_IRQSTATUS_RAW_0_INIT_SIGNED 0 +/* Register EUR_CR_OCP_IRQSTATUS_RAW_1 */ #define EUR_CR_OCP_IRQSTATUS_RAW_1 0xFE28 #define EUR_CR_OCP_IRQSTATUS_RAW_1_TARGET_MASK 0x00000001UL #define EUR_CR_OCP_IRQSTATUS_RAW_1_TARGET_SHIFT 0 #define EUR_CR_OCP_IRQSTATUS_RAW_1_TARGET_SIGNED 0 +/* Register EUR_CR_OCP_IRQSTATUS_RAW_2 */ #define EUR_CR_OCP_IRQSTATUS_RAW_2 0xFE2C #define EUR_CR_OCP_IRQSTATUS_RAW_2_SGXCORE_MASK 0x00000001UL #define EUR_CR_OCP_IRQSTATUS_RAW_2_SGXCORE_SHIFT 0 #define EUR_CR_OCP_IRQSTATUS_RAW_2_SGXCORE_SIGNED 0 +/* Register EUR_CR_OCP_IRQSTATUS_0 */ #define EUR_CR_OCP_IRQSTATUS_0 0xFE30 #define EUR_CR_OCP_IRQSTATUS_0_INIT_MASK 0x00000001UL #define EUR_CR_OCP_IRQSTATUS_0_INIT_SHIFT 0 #define EUR_CR_OCP_IRQSTATUS_0_INIT_SIGNED 0 +/* Register EUR_CR_OCP_IRQSTATUS_1 */ #define EUR_CR_OCP_IRQSTATUS_1 0xFE34 #define EUR_CR_OCP_IRQSTATUS_1_TARGET_MASK 0x00000001UL #define EUR_CR_OCP_IRQSTATUS_1_TARGET_SHIFT 0 #define EUR_CR_OCP_IRQSTATUS_1_TARGET_SIGNED 0 +/* Register EUR_CR_OCP_IRQSTATUS_2 */ #define EUR_CR_OCP_IRQSTATUS_2 0xFE38 #define EUR_CR_OCP_IRQSTATUS_2_SGXCORE_MASK 0x00000001UL #define EUR_CR_OCP_IRQSTATUS_2_SGXCORE_SHIFT 0 #define EUR_CR_OCP_IRQSTATUS_2_SGXCORE_SIGNED 0 +/* Register EUR_CR_OCP_IRQENABLE_SET_0 */ #define EUR_CR_OCP_IRQENABLE_SET_0 0xFE3C #define EUR_CR_OCP_IRQENABLE_SET_0_INIT_MASK 0x00000001UL #define EUR_CR_OCP_IRQENABLE_SET_0_INIT_SHIFT 0 #define EUR_CR_OCP_IRQENABLE_SET_0_INIT_SIGNED 0 +/* Register EUR_CR_OCP_IRQENABLE_SET_1 */ #define EUR_CR_OCP_IRQENABLE_SET_1 0xFE40 #define EUR_CR_OCP_IRQENABLE_SET_1_TARGET_MASK 0x00000001UL #define EUR_CR_OCP_IRQENABLE_SET_1_TARGET_SHIFT 0 #define EUR_CR_OCP_IRQENABLE_SET_1_TARGET_SIGNED 0 +/* Register EUR_CR_OCP_IRQENABLE_SET_2 */ #define EUR_CR_OCP_IRQENABLE_SET_2 0xFE44 #define EUR_CR_OCP_IRQENABLE_SET_2_SGXCORE_MASK 0x00000001UL #define EUR_CR_OCP_IRQENABLE_SET_2_SGXCORE_SHIFT 0 #define EUR_CR_OCP_IRQENABLE_SET_2_SGXCORE_SIGNED 0 +/* Register EUR_CR_OCP_IRQENABLE_CLR_0 */ #define EUR_CR_OCP_IRQENABLE_CLR_0 0xFE48 #define EUR_CR_OCP_IRQENABLE_CLR_0_INIT_MASK 0x00000001UL #define EUR_CR_OCP_IRQENABLE_CLR_0_INIT_SHIFT 0 #define EUR_CR_OCP_IRQENABLE_CLR_0_INIT_SIGNED 0 +/* Register EUR_CR_OCP_IRQENABLE_CLR_1 */ #define EUR_CR_OCP_IRQENABLE_CLR_1 0xFE4C #define EUR_CR_OCP_IRQENABLE_CLR_1_TARGET_MASK 0x00000001UL #define EUR_CR_OCP_IRQENABLE_CLR_1_TARGET_SHIFT 0 #define EUR_CR_OCP_IRQENABLE_CLR_1_TARGET_SIGNED 0 +/* Register EUR_CR_OCP_IRQENABLE_CLR_2 */ #define EUR_CR_OCP_IRQENABLE_CLR_2 0xFE50 #define EUR_CR_OCP_IRQENABLE_CLR_2_SGXCORE_MASK 0x00000001UL #define EUR_CR_OCP_IRQENABLE_CLR_2_SGXCORE_SHIFT 0 #define EUR_CR_OCP_IRQENABLE_CLR_2_SGXCORE_SIGNED 0 +/* Register EUR_CR_OCP_PAGE_CONFIG */ #define EUR_CR_OCP_PAGE_CONFIG 0xFF00 #define EUR_CR_OCP_PAGE_CONFIG_MEM_PAGE_SIZE_MASK 0x00000001UL #define EUR_CR_OCP_PAGE_CONFIG_MEM_PAGE_SIZE_SHIFT 0 @@ -123,6 +155,7 @@ #define EUR_CR_OCP_PAGE_CONFIG_SIZE_SHIFT 3 #define EUR_CR_OCP_PAGE_CONFIG_SIZE_SIGNED 0 +/* Register EUR_CR_OCP_INTERRUPT_EVENT */ #define EUR_CR_OCP_INTERRUPT_EVENT 0xFF04 #define EUR_CR_OCP_INTERRUPT_EVENT_INIT_RESP_UNEXPECTED_MASK 0x00000001UL #define EUR_CR_OCP_INTERRUPT_EVENT_INIT_RESP_UNEXPECTED_SHIFT 0 @@ -160,6 +193,7 @@ #define EUR_CR_OCP_INTERRUPT_EVENT_TARGET_INVALID_OCP_CMD_SHIFT 10 #define EUR_CR_OCP_INTERRUPT_EVENT_TARGET_INVALID_OCP_CMD_SIGNED 0 +/* Register EUR_CR_OCP_DEBUG_CONFIG */ #define EUR_CR_OCP_DEBUG_CONFIG 0xFF08 #define EUR_CR_OCP_DEBUG_CONFIG_FORCE_TARGET_IDLE_MASK 0x00000003UL #define EUR_CR_OCP_DEBUG_CONFIG_FORCE_TARGET_IDLE_SHIFT 0 @@ -181,6 +215,7 @@ #define EUR_CR_OCP_DEBUG_CONFIG_THALIA_INT_BYPASS_SHIFT 31 #define EUR_CR_OCP_DEBUG_CONFIG_THALIA_INT_BYPASS_SIGNED 0 +/* Register EUR_CR_OCP_DEBUG_STATUS */ #define EUR_CR_OCP_DEBUG_STATUS 0xFF0C #define EUR_CR_OCP_DEBUG_STATUS_TARGET_MCONNECT_MASK 0x00000003UL #define EUR_CR_OCP_DEBUG_STATUS_TARGET_MCONNECT_SHIFT 0 @@ -267,5 +302,8 @@ #define EUR_CR_OCP_DEBUG_STATUS_CMD_DEBUG_STATE_SIGNED 0 -#endif +#endif /* _OCPDEFS_H_ */ +/***************************************************************************** + End of file (ocpdefs.h) +*****************************************************************************/ diff --git a/sgx/services4/srvkm/hwdefs/sgx530defs.h b/sgx/services4/srvkm/hwdefs/sgx530defs.h index 810cb81..d4ec16f 100644 --- a/sgx/services4/srvkm/hwdefs/sgx530defs.h +++ b/sgx/services4/srvkm/hwdefs/sgx530defs.h @@ -1,32 +1,49 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Hardware defs for SGX530. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #ifndef _SGX530DEFS_KM_H_ #define _SGX530DEFS_KM_H_ +/* Register EUR_CR_CLKGATECTL */ #define EUR_CR_CLKGATECTL 0x0000 #define EUR_CR_CLKGATECTL_2D_CLKG_MASK 0x00000003U #define EUR_CR_CLKGATECTL_2D_CLKG_SHIFT 0 @@ -42,6 +59,7 @@ #define EUR_CR_CLKGATECTL_USE_CLKG_SHIFT 20 #define EUR_CR_CLKGATECTL_AUTO_MAN_REG_MASK 0x01000000U #define EUR_CR_CLKGATECTL_AUTO_MAN_REG_SHIFT 24 +/* Register EUR_CR_CLKGATESTATUS */ #define EUR_CR_CLKGATESTATUS 0x0004 #define EUR_CR_CLKGATESTATUS_2D_CLKS_MASK 0x00000001U #define EUR_CR_CLKGATESTATUS_2D_CLKS_SHIFT 0 @@ -55,6 +73,7 @@ #define EUR_CR_CLKGATESTATUS_DPM_CLKS_SHIFT 16 #define EUR_CR_CLKGATESTATUS_USE_CLKS_MASK 0x00100000U #define EUR_CR_CLKGATESTATUS_USE_CLKS_SHIFT 20 +/* Register EUR_CR_CLKGATECTLOVR */ #define EUR_CR_CLKGATECTLOVR 0x0008 #define EUR_CR_CLKGATECTLOVR_2D_CLKO_MASK 0x00000003U #define EUR_CR_CLKGATECTLOVR_2D_CLKO_SHIFT 0 @@ -68,11 +87,13 @@ #define EUR_CR_CLKGATECTLOVR_DPM_CLKO_SHIFT 16 #define EUR_CR_CLKGATECTLOVR_USE_CLKO_MASK 0x00300000U #define EUR_CR_CLKGATECTLOVR_USE_CLKO_SHIFT 20 +/* Register EUR_CR_CORE_ID */ #define EUR_CR_CORE_ID 0x0010 #define EUR_CR_CORE_ID_CONFIG_MASK 0x0000FFFFU #define EUR_CR_CORE_ID_CONFIG_SHIFT 0 #define EUR_CR_CORE_ID_ID_MASK 0xFFFF0000U #define EUR_CR_CORE_ID_ID_SHIFT 16 +/* Register EUR_CR_CORE_REVISION */ #define EUR_CR_CORE_REVISION 0x0014 #define EUR_CR_CORE_REVISION_MAINTENANCE_MASK 0x000000FFU #define EUR_CR_CORE_REVISION_MAINTENANCE_SHIFT 0 @@ -82,12 +103,15 @@ #define EUR_CR_CORE_REVISION_MAJOR_SHIFT 16 #define EUR_CR_CORE_REVISION_DESIGNER_MASK 0xFF000000U #define EUR_CR_CORE_REVISION_DESIGNER_SHIFT 24 +/* Register EUR_CR_DESIGNER_REV_FIELD1 */ #define EUR_CR_DESIGNER_REV_FIELD1 0x0018 #define EUR_CR_DESIGNER_REV_FIELD1_DESIGNER_REV_FIELD1_MASK 0xFFFFFFFFU #define EUR_CR_DESIGNER_REV_FIELD1_DESIGNER_REV_FIELD1_SHIFT 0 +/* Register EUR_CR_DESIGNER_REV_FIELD2 */ #define EUR_CR_DESIGNER_REV_FIELD2 0x001C #define EUR_CR_DESIGNER_REV_FIELD2_DESIGNER_REV_FIELD2_MASK 0xFFFFFFFFU #define EUR_CR_DESIGNER_REV_FIELD2_DESIGNER_REV_FIELD2_SHIFT 0 +/* Register EUR_CR_SOFT_RESET */ #define EUR_CR_SOFT_RESET 0x0080 #define EUR_CR_SOFT_RESET_BIF_RESET_MASK 0x00000001U #define EUR_CR_SOFT_RESET_BIF_RESET_SHIFT 0 @@ -103,6 +127,7 @@ #define EUR_CR_SOFT_RESET_ISP_RESET_SHIFT 5 #define EUR_CR_SOFT_RESET_TSP_RESET_MASK 0x00000040U #define EUR_CR_SOFT_RESET_TSP_RESET_SHIFT 6 +/* Register EUR_CR_EVENT_HOST_ENABLE2 */ #define EUR_CR_EVENT_HOST_ENABLE2 0x0110 #define EUR_CR_EVENT_HOST_ENABLE2_TRIG_TA_MASK 0x00000010U #define EUR_CR_EVENT_HOST_ENABLE2_TRIG_TA_SHIFT 4 @@ -114,6 +139,7 @@ #define EUR_CR_EVENT_HOST_ENABLE2_DPM_3D_FREE_LOAD_SHIFT 1 #define EUR_CR_EVENT_HOST_ENABLE2_DPM_TA_FREE_LOAD_MASK 0x00000001U #define EUR_CR_EVENT_HOST_ENABLE2_DPM_TA_FREE_LOAD_SHIFT 0 +/* Register EUR_CR_EVENT_HOST_CLEAR2 */ #define EUR_CR_EVENT_HOST_CLEAR2 0x0114 #define EUR_CR_EVENT_HOST_CLEAR2_TRIG_TA_MASK 0x00000010U #define EUR_CR_EVENT_HOST_CLEAR2_TRIG_TA_SHIFT 4 @@ -125,6 +151,7 @@ #define EUR_CR_EVENT_HOST_CLEAR2_DPM_3D_FREE_LOAD_SHIFT 1 #define EUR_CR_EVENT_HOST_CLEAR2_DPM_TA_FREE_LOAD_MASK 0x00000001U #define EUR_CR_EVENT_HOST_CLEAR2_DPM_TA_FREE_LOAD_SHIFT 0 +/* Register EUR_CR_EVENT_STATUS2 */ #define EUR_CR_EVENT_STATUS2 0x0118 #define EUR_CR_EVENT_STATUS2_TRIG_TA_MASK 0x00000010U #define EUR_CR_EVENT_STATUS2_TRIG_TA_SHIFT 4 @@ -136,6 +163,7 @@ #define EUR_CR_EVENT_STATUS2_DPM_3D_FREE_LOAD_SHIFT 1 #define EUR_CR_EVENT_STATUS2_DPM_TA_FREE_LOAD_MASK 0x00000001U #define EUR_CR_EVENT_STATUS2_DPM_TA_FREE_LOAD_SHIFT 0 +/* Register EUR_CR_EVENT_STATUS */ #define EUR_CR_EVENT_STATUS 0x012CU #define EUR_CR_EVENT_STATUS_MASTER_INTERRUPT_MASK 0x80000000U #define EUR_CR_EVENT_STATUS_MASTER_INTERRUPT_SHIFT 31 @@ -199,6 +227,7 @@ #define EUR_CR_EVENT_STATUS_DPM_OUT_OF_MEMORY_MT_SHIFT 1 #define EUR_CR_EVENT_STATUS_DPM_3D_MEM_FREE_MASK 0x00000001U #define EUR_CR_EVENT_STATUS_DPM_3D_MEM_FREE_SHIFT 0 +/* Register EUR_CR_EVENT_HOST_ENABLE */ #define EUR_CR_EVENT_HOST_ENABLE 0x0130 #define EUR_CR_EVENT_HOST_ENABLE_MASTER_INTERRUPT_MASK 0x80000000U #define EUR_CR_EVENT_HOST_ENABLE_MASTER_INTERRUPT_SHIFT 31 @@ -262,6 +291,7 @@ #define EUR_CR_EVENT_HOST_ENABLE_DPM_OUT_OF_MEMORY_MT_SHIFT 1 #define EUR_CR_EVENT_HOST_ENABLE_DPM_3D_MEM_FREE_MASK 0x00000001U #define EUR_CR_EVENT_HOST_ENABLE_DPM_3D_MEM_FREE_SHIFT 0 +/* Register EUR_CR_EVENT_HOST_CLEAR */ #define EUR_CR_EVENT_HOST_CLEAR 0x0134 #define EUR_CR_EVENT_HOST_CLEAR_MASTER_INTERRUPT_MASK 0x80000000U #define EUR_CR_EVENT_HOST_CLEAR_MASTER_INTERRUPT_SHIFT 31 @@ -325,38 +355,49 @@ #define EUR_CR_EVENT_HOST_CLEAR_DPM_OUT_OF_MEMORY_MT_SHIFT 1 #define EUR_CR_EVENT_HOST_CLEAR_DPM_3D_MEM_FREE_MASK 0x00000001U #define EUR_CR_EVENT_HOST_CLEAR_DPM_3D_MEM_FREE_SHIFT 0 +/* Register EUR_CR_PDS_EXEC_BASE */ #define EUR_CR_PDS_EXEC_BASE 0x0AB8 #define EUR_CR_PDS_EXEC_BASE_ADDR_MASK 0x0FF00000U #define EUR_CR_PDS_EXEC_BASE_ADDR_SHIFT 20 +/* Register EUR_CR_EVENT_KICKER */ #define EUR_CR_EVENT_KICKER 0x0AC4 #define EUR_CR_EVENT_KICKER_ADDRESS_MASK 0x0FFFFFF0U #define EUR_CR_EVENT_KICKER_ADDRESS_SHIFT 4 +/* Register EUR_CR_EVENT_KICK */ #define EUR_CR_EVENT_KICK 0x0AC8 #define EUR_CR_EVENT_KICK_NOW_MASK 0x00000001U #define EUR_CR_EVENT_KICK_NOW_SHIFT 0 +/* Register EUR_CR_EVENT_TIMER */ #define EUR_CR_EVENT_TIMER 0x0ACC #define EUR_CR_EVENT_TIMER_ENABLE_MASK 0x01000000U #define EUR_CR_EVENT_TIMER_ENABLE_SHIFT 24 #define EUR_CR_EVENT_TIMER_VALUE_MASK 0x00FFFFFFU #define EUR_CR_EVENT_TIMER_VALUE_SHIFT 0 +/* Register EUR_CR_PDS_INV0 */ #define EUR_CR_PDS_INV0 0x0AD0 #define EUR_CR_PDS_INV0_DSC_MASK 0x00000001U #define EUR_CR_PDS_INV0_DSC_SHIFT 0 +/* Register EUR_CR_PDS_INV1 */ #define EUR_CR_PDS_INV1 0x0AD4 #define EUR_CR_PDS_INV1_DSC_MASK 0x00000001U #define EUR_CR_PDS_INV1_DSC_SHIFT 0 +/* Register EUR_CR_PDS_INV2 */ #define EUR_CR_PDS_INV2 0x0AD8 #define EUR_CR_PDS_INV2_DSC_MASK 0x00000001U #define EUR_CR_PDS_INV2_DSC_SHIFT 0 +/* Register EUR_CR_PDS_INV3 */ #define EUR_CR_PDS_INV3 0x0ADC #define EUR_CR_PDS_INV3_DSC_MASK 0x00000001U #define EUR_CR_PDS_INV3_DSC_SHIFT 0 +/* Register EUR_CR_PDS_INV_CSC */ #define EUR_CR_PDS_INV_CSC 0x0AE0 #define EUR_CR_PDS_INV_CSC_KICK_MASK 0x00000001U #define EUR_CR_PDS_INV_CSC_KICK_SHIFT 0 +/* Register EUR_CR_PDS_PC_BASE */ #define EUR_CR_PDS_PC_BASE 0x0B2C #define EUR_CR_PDS_PC_BASE_ADDRESS_MASK 0x3FFFFFFFU #define EUR_CR_PDS_PC_BASE_ADDRESS_SHIFT 0 +/* Register EUR_CR_BIF_CTRL */ #define EUR_CR_BIF_CTRL 0x0C00 #define EUR_CR_BIF_CTRL_NOREORDER_MASK 0x00000001U #define EUR_CR_BIF_CTRL_NOREORDER_SHIFT 0 @@ -384,6 +425,7 @@ #define EUR_CR_BIF_CTRL_MMU_BYPASS_ISP_SHIFT 14 #define EUR_CR_BIF_CTRL_MMU_BYPASS_USE_MASK 0x00008000U #define EUR_CR_BIF_CTRL_MMU_BYPASS_USE_SHIFT 15 +/* Register EUR_CR_BIF_INT_STAT */ #define EUR_CR_BIF_INT_STAT 0x0C04 #define EUR_CR_BIF_INT_STAT_FAULT_MASK 0x00003FFFU #define EUR_CR_BIF_INT_STAT_FAULT_SHIFT 0 @@ -391,32 +433,41 @@ #define EUR_CR_BIF_INT_STAT_PF_N_RW_SHIFT 14 #define EUR_CR_BIF_INT_STAT_FLUSH_COMPLETE_MASK 0x00008000U #define EUR_CR_BIF_INT_STAT_FLUSH_COMPLETE_SHIFT 15 +/* Register EUR_CR_BIF_FAULT */ #define EUR_CR_BIF_FAULT 0x0C08 #define EUR_CR_BIF_FAULT_ADDR_MASK 0x0FFFF000U #define EUR_CR_BIF_FAULT_ADDR_SHIFT 12 +/* Register EUR_CR_BIF_DIR_LIST_BASE0 */ #define EUR_CR_BIF_DIR_LIST_BASE0 0x0C84 #define EUR_CR_BIF_DIR_LIST_BASE0_ADDR_MASK 0xFFFFF000U #define EUR_CR_BIF_DIR_LIST_BASE0_ADDR_SHIFT 12 +/* Register EUR_CR_BIF_TWOD_REQ_BASE */ #define EUR_CR_BIF_TWOD_REQ_BASE 0x0C88 #define EUR_CR_BIF_TWOD_REQ_BASE_ADDR_MASK 0x0FF00000U #define EUR_CR_BIF_TWOD_REQ_BASE_ADDR_SHIFT 20 +/* Register EUR_CR_BIF_TA_REQ_BASE */ #define EUR_CR_BIF_TA_REQ_BASE 0x0C90 #define EUR_CR_BIF_TA_REQ_BASE_ADDR_MASK 0x0FF00000U #define EUR_CR_BIF_TA_REQ_BASE_ADDR_SHIFT 20 +/* Register EUR_CR_BIF_MEM_REQ_STAT */ #define EUR_CR_BIF_MEM_REQ_STAT 0x0CA8 #define EUR_CR_BIF_MEM_REQ_STAT_READS_MASK 0x000000FFU #define EUR_CR_BIF_MEM_REQ_STAT_READS_SHIFT 0 +/* Register EUR_CR_BIF_3D_REQ_BASE */ #define EUR_CR_BIF_3D_REQ_BASE 0x0CAC #define EUR_CR_BIF_3D_REQ_BASE_ADDR_MASK 0x0FF00000U #define EUR_CR_BIF_3D_REQ_BASE_ADDR_SHIFT 20 +/* Register EUR_CR_BIF_ZLS_REQ_BASE */ #define EUR_CR_BIF_ZLS_REQ_BASE 0x0CB0 #define EUR_CR_BIF_ZLS_REQ_BASE_ADDR_MASK 0x0FF00000U #define EUR_CR_BIF_ZLS_REQ_BASE_ADDR_SHIFT 20 +/* Register EUR_CR_2D_BLIT_STATUS */ #define EUR_CR_2D_BLIT_STATUS 0x0E04 #define EUR_CR_2D_BLIT_STATUS_COMPLETE_MASK 0x00FFFFFFU #define EUR_CR_2D_BLIT_STATUS_COMPLETE_SHIFT 0 #define EUR_CR_2D_BLIT_STATUS_BUSY_MASK 0x01000000U #define EUR_CR_2D_BLIT_STATUS_BUSY_SHIFT 24 +/* Register EUR_CR_2D_VIRTUAL_FIFO_0 */ #define EUR_CR_2D_VIRTUAL_FIFO_0 0x0E10 #define EUR_CR_2D_VIRTUAL_FIFO_0_ENABLE_MASK 0x00000001U #define EUR_CR_2D_VIRTUAL_FIFO_0_ENABLE_SHIFT 0 @@ -426,6 +477,7 @@ #define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_DIV_SHIFT 4 #define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_MUL_MASK 0x0000F000U #define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_MUL_SHIFT 12 +/* Register EUR_CR_2D_VIRTUAL_FIFO_1 */ #define EUR_CR_2D_VIRTUAL_FIFO_1 0x0E14 #define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_ACC_MASK 0x00000FFFU #define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_ACC_SHIFT 0 @@ -433,11 +485,14 @@ #define EUR_CR_2D_VIRTUAL_FIFO_1_MAX_ACC_SHIFT 12 #define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_METRIC_MASK 0xFF000000U #define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_METRIC_SHIFT 24 +/* Table EUR_CR_USE_CODE_BASE */ +/* Register EUR_CR_USE_CODE_BASE */ #define EUR_CR_USE_CODE_BASE(X) (0x0A0C + (4 * (X))) #define EUR_CR_USE_CODE_BASE_ADDR_MASK 0x00FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_SHIFT 0 #define EUR_CR_USE_CODE_BASE_DM_MASK 0x03000000U #define EUR_CR_USE_CODE_BASE_DM_SHIFT 24 +/* Number of entries in table EUR_CR_USE_CODE_BASE */ #define EUR_CR_USE_CODE_BASE_SIZE_UINT32 16 #define EUR_CR_USE_CODE_BASE_NUM_ENTRIES 16 #define EUR_CR_MNE_CR_CTRL 0x0D00 @@ -484,5 +539,5 @@ #define EUR_CR_MNE_CR_EVENT_CLEAR_INVAL_SHIFT 0 #define EUR_CR_MNE_CR_CTRL_INVAL 0x0D20 -#endif +#endif /* _SGX530DEFS_KM_H_ */ diff --git a/sgx/services4/srvkm/hwdefs/sgx540defs.h b/sgx/services4/srvkm/hwdefs/sgx540defs.h index c09aa26..25f9ec1 100644 --- a/sgx/services4/srvkm/hwdefs/sgx540defs.h +++ b/sgx/services4/srvkm/hwdefs/sgx540defs.h @@ -1,32 +1,49 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Hardware defs for SGX540. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #ifndef _SGX540DEFS_KM_H_ #define _SGX540DEFS_KM_H_ +/* Register EUR_CR_CLKGATECTL */ #define EUR_CR_CLKGATECTL 0x0000 #define EUR_CR_CLKGATECTL_ISP_CLKG_MASK 0x00000003U #define EUR_CR_CLKGATECTL_ISP_CLKG_SHIFT 0 @@ -52,6 +69,7 @@ #define EUR_CR_CLKGATECTL_AUTO_MAN_REG_SHIFT 24 #define EUR_CR_CLKGATECTL_SYSTEM_CLKG_MASK 0x10000000U #define EUR_CR_CLKGATECTL_SYSTEM_CLKG_SHIFT 28 +/* Register EUR_CR_CLKGATECTL2 */ #define EUR_CR_CLKGATECTL2 0x0004 #define EUR_CR_CLKGATECTL2_PBE_CLKG_MASK 0x00000003U #define EUR_CR_CLKGATECTL2_PBE_CLKG_SHIFT 0 @@ -75,6 +93,7 @@ #define EUR_CR_CLKGATECTL2_TEX1_CLKG_SHIFT 18 #define EUR_CR_CLKGATECTL2_MADD1_CLKG_MASK 0x00300000U #define EUR_CR_CLKGATECTL2_MADD1_CLKG_SHIFT 20 +/* Register EUR_CR_CLKGATESTATUS */ #define EUR_CR_CLKGATESTATUS 0x0008 #define EUR_CR_CLKGATESTATUS_ISP_CLKS_MASK 0x00000001U #define EUR_CR_CLKGATESTATUS_ISP_CLKS_SHIFT 0 @@ -118,6 +137,7 @@ #define EUR_CR_CLKGATESTATUS_IDXFIFO_CLKS_SHIFT 19 #define EUR_CR_CLKGATESTATUS_TA_CLKS_MASK 0x00100000U #define EUR_CR_CLKGATESTATUS_TA_CLKS_SHIFT 20 +/* Register EUR_CR_CLKGATECTLOVR */ #define EUR_CR_CLKGATECTLOVR 0x000C #define EUR_CR_CLKGATECTLOVR_ISP_CLKO_MASK 0x00000003U #define EUR_CR_CLKGATECTLOVR_ISP_CLKO_SHIFT 0 @@ -139,14 +159,17 @@ #define EUR_CR_CLKGATECTLOVR_IDXFIFO_CLKO_SHIFT 16 #define EUR_CR_CLKGATECTLOVR_TA_CLKO_MASK 0x000C0000U #define EUR_CR_CLKGATECTLOVR_TA_CLKO_SHIFT 18 +/* Register EUR_CR_POWER */ #define EUR_CR_POWER 0x001C #define EUR_CR_POWER_PIPE_DISABLE_MASK 0x00000001U #define EUR_CR_POWER_PIPE_DISABLE_SHIFT 0 +/* Register EUR_CR_CORE_ID */ #define EUR_CR_CORE_ID 0x0020 #define EUR_CR_CORE_ID_CONFIG_MASK 0x0000FFFFU #define EUR_CR_CORE_ID_CONFIG_SHIFT 0 #define EUR_CR_CORE_ID_ID_MASK 0xFFFF0000U #define EUR_CR_CORE_ID_ID_SHIFT 16 +/* Register EUR_CR_CORE_REVISION */ #define EUR_CR_CORE_REVISION 0x0024 #define EUR_CR_CORE_REVISION_MAINTENANCE_MASK 0x000000FFU #define EUR_CR_CORE_REVISION_MAINTENANCE_SHIFT 0 @@ -156,12 +179,15 @@ #define EUR_CR_CORE_REVISION_MAJOR_SHIFT 16 #define EUR_CR_CORE_REVISION_DESIGNER_MASK 0xFF000000U #define EUR_CR_CORE_REVISION_DESIGNER_SHIFT 24 +/* Register EUR_CR_DESIGNER_REV_FIELD1 */ #define EUR_CR_DESIGNER_REV_FIELD1 0x0028 #define EUR_CR_DESIGNER_REV_FIELD1_DESIGNER_REV_FIELD1_MASK 0xFFFFFFFFU #define EUR_CR_DESIGNER_REV_FIELD1_DESIGNER_REV_FIELD1_SHIFT 0 +/* Register EUR_CR_DESIGNER_REV_FIELD2 */ #define EUR_CR_DESIGNER_REV_FIELD2 0x002C #define EUR_CR_DESIGNER_REV_FIELD2_DESIGNER_REV_FIELD2_MASK 0xFFFFFFFFU #define EUR_CR_DESIGNER_REV_FIELD2_DESIGNER_REV_FIELD2_SHIFT 0 +/* Register EUR_CR_SOFT_RESET */ #define EUR_CR_SOFT_RESET 0x0080 #define EUR_CR_SOFT_RESET_BIF_RESET_MASK 0x00000001U #define EUR_CR_SOFT_RESET_BIF_RESET_SHIFT 0 @@ -199,6 +225,7 @@ #define EUR_CR_SOFT_RESET_IDXFIFO_RESET_SHIFT 16 #define EUR_CR_SOFT_RESET_TA_RESET_MASK 0x00020000U #define EUR_CR_SOFT_RESET_TA_RESET_SHIFT 17 +/* Register EUR_CR_EVENT_HOST_ENABLE2 */ #define EUR_CR_EVENT_HOST_ENABLE2 0x0110 #define EUR_CR_EVENT_HOST_ENABLE2_TRIG_TA_MASK 0x00000010U #define EUR_CR_EVENT_HOST_ENABLE2_TRIG_TA_SHIFT 4 @@ -210,6 +237,7 @@ #define EUR_CR_EVENT_HOST_ENABLE2_DPM_3D_FREE_LOAD_SHIFT 1 #define EUR_CR_EVENT_HOST_ENABLE2_DPM_TA_FREE_LOAD_MASK 0x00000001U #define EUR_CR_EVENT_HOST_ENABLE2_DPM_TA_FREE_LOAD_SHIFT 0 +/* Register EUR_CR_EVENT_HOST_CLEAR2 */ #define EUR_CR_EVENT_HOST_CLEAR2 0x0114 #define EUR_CR_EVENT_HOST_CLEAR2_TRIG_TA_MASK 0x00000010U #define EUR_CR_EVENT_HOST_CLEAR2_TRIG_TA_SHIFT 4 @@ -221,6 +249,7 @@ #define EUR_CR_EVENT_HOST_CLEAR2_DPM_3D_FREE_LOAD_SHIFT 1 #define EUR_CR_EVENT_HOST_CLEAR2_DPM_TA_FREE_LOAD_MASK 0x00000001U #define EUR_CR_EVENT_HOST_CLEAR2_DPM_TA_FREE_LOAD_SHIFT 0 +/* Register EUR_CR_EVENT_STATUS2 */ #define EUR_CR_EVENT_STATUS2 0x0118 #define EUR_CR_EVENT_STATUS2_TRIG_TA_MASK 0x00000010U #define EUR_CR_EVENT_STATUS2_TRIG_TA_SHIFT 4 @@ -232,6 +261,7 @@ #define EUR_CR_EVENT_STATUS2_DPM_3D_FREE_LOAD_SHIFT 1 #define EUR_CR_EVENT_STATUS2_DPM_TA_FREE_LOAD_MASK 0x00000001U #define EUR_CR_EVENT_STATUS2_DPM_TA_FREE_LOAD_SHIFT 0 +/* Register EUR_CR_EVENT_STATUS */ #define EUR_CR_EVENT_STATUS 0x012CU #define EUR_CR_EVENT_STATUS_MASTER_INTERRUPT_MASK 0x80000000U #define EUR_CR_EVENT_STATUS_MASTER_INTERRUPT_SHIFT 31 @@ -295,6 +325,7 @@ #define EUR_CR_EVENT_STATUS_DPM_OUT_OF_MEMORY_MT_SHIFT 1 #define EUR_CR_EVENT_STATUS_DPM_3D_MEM_FREE_MASK 0x00000001U #define EUR_CR_EVENT_STATUS_DPM_3D_MEM_FREE_SHIFT 0 +/* Register EUR_CR_EVENT_HOST_ENABLE */ #define EUR_CR_EVENT_HOST_ENABLE 0x0130 #define EUR_CR_EVENT_HOST_ENABLE_MASTER_INTERRUPT_MASK 0x80000000U #define EUR_CR_EVENT_HOST_ENABLE_MASTER_INTERRUPT_SHIFT 31 @@ -358,6 +389,7 @@ #define EUR_CR_EVENT_HOST_ENABLE_DPM_OUT_OF_MEMORY_MT_SHIFT 1 #define EUR_CR_EVENT_HOST_ENABLE_DPM_3D_MEM_FREE_MASK 0x00000001U #define EUR_CR_EVENT_HOST_ENABLE_DPM_3D_MEM_FREE_SHIFT 0 +/* Register EUR_CR_EVENT_HOST_CLEAR */ #define EUR_CR_EVENT_HOST_CLEAR 0x0134 #define EUR_CR_EVENT_HOST_CLEAR_MASTER_INTERRUPT_MASK 0x80000000U #define EUR_CR_EVENT_HOST_CLEAR_MASTER_INTERRUPT_SHIFT 31 @@ -421,47 +453,61 @@ #define EUR_CR_EVENT_HOST_CLEAR_DPM_OUT_OF_MEMORY_MT_SHIFT 1 #define EUR_CR_EVENT_HOST_CLEAR_DPM_3D_MEM_FREE_MASK 0x00000001U #define EUR_CR_EVENT_HOST_CLEAR_DPM_3D_MEM_FREE_SHIFT 0 +/* Register EUR_CR_TIMER */ #define EUR_CR_TIMER 0x0144 #define EUR_CR_TIMER_VALUE_MASK 0xFFFFFFFFU #define EUR_CR_TIMER_VALUE_SHIFT 0 +/* Register EUR_CR_EVENT_KICK1 */ #define EUR_CR_EVENT_KICK1 0x0AB0 #define EUR_CR_EVENT_KICK1_NOW_MASK 0x000000FFU #define EUR_CR_EVENT_KICK1_NOW_SHIFT 0 +/* Register EUR_CR_PDS_EXEC_BASE */ #define EUR_CR_PDS_EXEC_BASE 0x0AB8 #define EUR_CR_PDS_EXEC_BASE_ADDR_MASK 0x0FF00000U #define EUR_CR_PDS_EXEC_BASE_ADDR_SHIFT 20 +/* Register EUR_CR_EVENT_KICK2 */ #define EUR_CR_EVENT_KICK2 0x0AC0 #define EUR_CR_EVENT_KICK2_NOW_MASK 0x00000001U #define EUR_CR_EVENT_KICK2_NOW_SHIFT 0 +/* Register EUR_CR_EVENT_KICKER */ #define EUR_CR_EVENT_KICKER 0x0AC4 #define EUR_CR_EVENT_KICKER_ADDRESS_MASK 0x0FFFFFF0U #define EUR_CR_EVENT_KICKER_ADDRESS_SHIFT 4 +/* Register EUR_CR_EVENT_KICK */ #define EUR_CR_EVENT_KICK 0x0AC8 #define EUR_CR_EVENT_KICK_NOW_MASK 0x00000001U #define EUR_CR_EVENT_KICK_NOW_SHIFT 0 +/* Register EUR_CR_EVENT_TIMER */ #define EUR_CR_EVENT_TIMER 0x0ACC #define EUR_CR_EVENT_TIMER_ENABLE_MASK 0x01000000U #define EUR_CR_EVENT_TIMER_ENABLE_SHIFT 24 #define EUR_CR_EVENT_TIMER_VALUE_MASK 0x00FFFFFFU #define EUR_CR_EVENT_TIMER_VALUE_SHIFT 0 +/* Register EUR_CR_PDS_INV0 */ #define EUR_CR_PDS_INV0 0x0AD0 #define EUR_CR_PDS_INV0_DSC_MASK 0x00000001U #define EUR_CR_PDS_INV0_DSC_SHIFT 0 +/* Register EUR_CR_PDS_INV1 */ #define EUR_CR_PDS_INV1 0x0AD4 #define EUR_CR_PDS_INV1_DSC_MASK 0x00000001U #define EUR_CR_PDS_INV1_DSC_SHIFT 0 +/* Register EUR_CR_EVENT_KICK3 */ #define EUR_CR_EVENT_KICK3 0x0AD8 #define EUR_CR_EVENT_KICK3_NOW_MASK 0x00000001U #define EUR_CR_EVENT_KICK3_NOW_SHIFT 0 +/* Register EUR_CR_PDS_INV3 */ #define EUR_CR_PDS_INV3 0x0ADC #define EUR_CR_PDS_INV3_DSC_MASK 0x00000001U #define EUR_CR_PDS_INV3_DSC_SHIFT 0 +/* Register EUR_CR_PDS_INV_CSC */ #define EUR_CR_PDS_INV_CSC 0x0AE0 #define EUR_CR_PDS_INV_CSC_KICK_MASK 0x00000001U #define EUR_CR_PDS_INV_CSC_KICK_SHIFT 0 +/* Register EUR_CR_PDS_PC_BASE */ #define EUR_CR_PDS_PC_BASE 0x0B2C #define EUR_CR_PDS_PC_BASE_ADDRESS_MASK 0x00FFFFFFU #define EUR_CR_PDS_PC_BASE_ADDRESS_SHIFT 0 +/* Register EUR_CR_BIF_CTRL */ #define EUR_CR_BIF_CTRL 0x0C00 #define EUR_CR_BIF_CTRL_NOREORDER_MASK 0x00000001U #define EUR_CR_BIF_CTRL_NOREORDER_SHIFT 0 @@ -487,6 +533,7 @@ #define EUR_CR_BIF_CTRL_MMU_BYPASS_ISP_SHIFT 14 #define EUR_CR_BIF_CTRL_MMU_BYPASS_USE_MASK 0x00008000U #define EUR_CR_BIF_CTRL_MMU_BYPASS_USE_SHIFT 15 +/* Register EUR_CR_BIF_INT_STAT */ #define EUR_CR_BIF_INT_STAT 0x0C04 #define EUR_CR_BIF_INT_STAT_FAULT_MASK 0x00003FFFU #define EUR_CR_BIF_INT_STAT_FAULT_SHIFT 0 @@ -494,31 +541,39 @@ #define EUR_CR_BIF_INT_STAT_PF_N_RW_SHIFT 14 #define EUR_CR_BIF_INT_STAT_FLUSH_COMPLETE_MASK 0x00008000U #define EUR_CR_BIF_INT_STAT_FLUSH_COMPLETE_SHIFT 15 +/* Register EUR_CR_BIF_FAULT */ #define EUR_CR_BIF_FAULT 0x0C08 #define EUR_CR_BIF_FAULT_SB_MASK 0x000001F0U #define EUR_CR_BIF_FAULT_SB_SHIFT 4 #define EUR_CR_BIF_FAULT_ADDR_MASK 0x0FFFF000U #define EUR_CR_BIF_FAULT_ADDR_SHIFT 12 +/* Register EUR_CR_BIF_DIR_LIST_BASE0 */ #define EUR_CR_BIF_DIR_LIST_BASE0 0x0C84 #define EUR_CR_BIF_DIR_LIST_BASE0_ADDR_MASK 0xFFFFF000U #define EUR_CR_BIF_DIR_LIST_BASE0_ADDR_SHIFT 12 +/* Register EUR_CR_BIF_TA_REQ_BASE */ #define EUR_CR_BIF_TA_REQ_BASE 0x0C90 #define EUR_CR_BIF_TA_REQ_BASE_ADDR_MASK 0x0FF00000U #define EUR_CR_BIF_TA_REQ_BASE_ADDR_SHIFT 20 +/* Register EUR_CR_BIF_MEM_REQ_STAT */ #define EUR_CR_BIF_MEM_REQ_STAT 0x0CA8 #define EUR_CR_BIF_MEM_REQ_STAT_READS_MASK 0x000000FFU #define EUR_CR_BIF_MEM_REQ_STAT_READS_SHIFT 0 +/* Register EUR_CR_BIF_3D_REQ_BASE */ #define EUR_CR_BIF_3D_REQ_BASE 0x0CAC #define EUR_CR_BIF_3D_REQ_BASE_ADDR_MASK 0x0FF00000U #define EUR_CR_BIF_3D_REQ_BASE_ADDR_SHIFT 20 +/* Register EUR_CR_BIF_ZLS_REQ_BASE */ #define EUR_CR_BIF_ZLS_REQ_BASE 0x0CB0 #define EUR_CR_BIF_ZLS_REQ_BASE_ADDR_MASK 0x0FF00000U #define EUR_CR_BIF_ZLS_REQ_BASE_ADDR_SHIFT 20 +/* Register EUR_CR_2D_BLIT_STATUS */ #define EUR_CR_2D_BLIT_STATUS 0x0E04 #define EUR_CR_2D_BLIT_STATUS_COMPLETE_MASK 0x00FFFFFFU #define EUR_CR_2D_BLIT_STATUS_COMPLETE_SHIFT 0 #define EUR_CR_2D_BLIT_STATUS_BUSY_MASK 0x01000000U #define EUR_CR_2D_BLIT_STATUS_BUSY_SHIFT 24 +/* Register EUR_CR_2D_VIRTUAL_FIFO_0 */ #define EUR_CR_2D_VIRTUAL_FIFO_0 0x0E10 #define EUR_CR_2D_VIRTUAL_FIFO_0_ENABLE_MASK 0x00000001U #define EUR_CR_2D_VIRTUAL_FIFO_0_ENABLE_SHIFT 0 @@ -528,6 +583,7 @@ #define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_DIV_SHIFT 4 #define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_MUL_MASK 0x0000F000U #define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_MUL_SHIFT 12 +/* Register EUR_CR_2D_VIRTUAL_FIFO_1 */ #define EUR_CR_2D_VIRTUAL_FIFO_1 0x0E14 #define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_ACC_MASK 0x00000FFFU #define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_ACC_SHIFT 0 @@ -535,13 +591,16 @@ #define EUR_CR_2D_VIRTUAL_FIFO_1_MAX_ACC_SHIFT 12 #define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_METRIC_MASK 0xFF000000U #define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_METRIC_SHIFT 24 +/* Table EUR_CR_USE_CODE_BASE */ +/* Register EUR_CR_USE_CODE_BASE */ #define EUR_CR_USE_CODE_BASE(X) (0x0A0C + (4 * (X))) #define EUR_CR_USE_CODE_BASE_ADDR_MASK 0x00FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_SHIFT 0 #define EUR_CR_USE_CODE_BASE_DM_MASK 0x03000000U #define EUR_CR_USE_CODE_BASE_DM_SHIFT 24 +/* Number of entries in table EUR_CR_USE_CODE_BASE */ #define EUR_CR_USE_CODE_BASE_SIZE_UINT32 16 #define EUR_CR_USE_CODE_BASE_NUM_ENTRIES 16 -#endif +#endif /* _SGX540DEFS_KM_H_ */ diff --git a/sgx/services4/srvkm/hwdefs/sgx544defs.h b/sgx/services4/srvkm/hwdefs/sgx544defs.h index c18b8ad..c35a259 100644 --- a/sgx/services4/srvkm/hwdefs/sgx544defs.h +++ b/sgx/services4/srvkm/hwdefs/sgx544defs.h @@ -1,32 +1,49 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Hardware defs for SGX544. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #ifndef _SGX544DEFS_KM_H_ #define _SGX544DEFS_KM_H_ +/* Register EUR_CR_CLKGATECTL */ #define EUR_CR_CLKGATECTL 0x0000 #define EUR_CR_CLKGATECTL_ISP_CLKG_MASK 0x00000003U #define EUR_CR_CLKGATECTL_ISP_CLKG_SHIFT 0 @@ -67,6 +84,7 @@ #define EUR_CR_CLKGATECTL_SYSTEM_CLKG_MASK 0x10000000U #define EUR_CR_CLKGATECTL_SYSTEM_CLKG_SHIFT 28 #define EUR_CR_CLKGATECTL_SYSTEM_CLKG_SIGNED 0 +/* Register EUR_CR_CLKGATECTL2 */ #define EUR_CR_CLKGATECTL2 0x0004 #define EUR_CR_CLKGATECTL2_PBE_CLKG_MASK 0x00000003U #define EUR_CR_CLKGATECTL2_PBE_CLKG_SHIFT 0 @@ -104,6 +122,7 @@ #define EUR_CR_CLKGATECTL2_DCU0_L0L1_CLKG_MASK 0x0C000000U #define EUR_CR_CLKGATECTL2_DCU0_L0L1_CLKG_SHIFT 26 #define EUR_CR_CLKGATECTL2_DCU0_L0L1_CLKG_SIGNED 0 +/* Register EUR_CR_CLKGATESTATUS */ #define EUR_CR_CLKGATESTATUS 0x0008 #define EUR_CR_CLKGATESTATUS_ISP_CLKS_MASK 0x00000001U #define EUR_CR_CLKGATESTATUS_ISP_CLKS_SHIFT 0 @@ -174,6 +193,7 @@ #define EUR_CR_CLKGATESTATUS_BIF_CORE_CLKS_MASK 0x01000000U #define EUR_CR_CLKGATESTATUS_BIF_CORE_CLKS_SHIFT 24 #define EUR_CR_CLKGATESTATUS_BIF_CORE_CLKS_SIGNED 0 +/* Register EUR_CR_CLKGATECTLOVR */ #define EUR_CR_CLKGATECTLOVR 0x000C #define EUR_CR_CLKGATECTLOVR_ISP_CLKO_MASK 0x00000003U #define EUR_CR_CLKGATECTLOVR_ISP_CLKO_SHIFT 0 @@ -208,10 +228,12 @@ #define EUR_CR_CLKGATECTLOVR_BIF_CORE_CLKO_MASK 0x00300000U #define EUR_CR_CLKGATECTLOVR_BIF_CORE_CLKO_SHIFT 20 #define EUR_CR_CLKGATECTLOVR_BIF_CORE_CLKO_SIGNED 0 +/* Register EUR_CR_POWER */ #define EUR_CR_POWER 0x001C #define EUR_CR_POWER_PIPE_DISABLE_MASK 0x00000001U #define EUR_CR_POWER_PIPE_DISABLE_SHIFT 0 #define EUR_CR_POWER_PIPE_DISABLE_SIGNED 0 +/* Register EUR_CR_CORE_ID */ #define EUR_CR_CORE_ID 0x0020 #define EUR_CR_CORE_ID_CONFIG_MULTI_MASK 0x00000001U #define EUR_CR_CORE_ID_CONFIG_MULTI_SHIFT 0 @@ -231,6 +253,7 @@ #define EUR_CR_CORE_ID_ID_MASK 0xFFFF0000U #define EUR_CR_CORE_ID_ID_SHIFT 16 #define EUR_CR_CORE_ID_ID_SIGNED 0 +/* Register EUR_CR_CORE_REVISION */ #define EUR_CR_CORE_REVISION 0x0024 #define EUR_CR_CORE_REVISION_MAINTENANCE_MASK 0x000000FFU #define EUR_CR_CORE_REVISION_MAINTENANCE_SHIFT 0 @@ -244,14 +267,17 @@ #define EUR_CR_CORE_REVISION_DESIGNER_MASK 0xFF000000U #define EUR_CR_CORE_REVISION_DESIGNER_SHIFT 24 #define EUR_CR_CORE_REVISION_DESIGNER_SIGNED 0 +/* Register EUR_CR_DESIGNER_REV_FIELD1 */ #define EUR_CR_DESIGNER_REV_FIELD1 0x0028 #define EUR_CR_DESIGNER_REV_FIELD1_DESIGNER_REV_FIELD1_MASK 0xFFFFFFFFU #define EUR_CR_DESIGNER_REV_FIELD1_DESIGNER_REV_FIELD1_SHIFT 0 #define EUR_CR_DESIGNER_REV_FIELD1_DESIGNER_REV_FIELD1_SIGNED 0 +/* Register EUR_CR_DESIGNER_REV_FIELD2 */ #define EUR_CR_DESIGNER_REV_FIELD2 0x002C #define EUR_CR_DESIGNER_REV_FIELD2_DESIGNER_REV_FIELD2_MASK 0xFFFFFFFFU #define EUR_CR_DESIGNER_REV_FIELD2_DESIGNER_REV_FIELD2_SHIFT 0 #define EUR_CR_DESIGNER_REV_FIELD2_DESIGNER_REV_FIELD2_SIGNED 0 +/* Register EUR_CR_SOFT_RESET */ #define EUR_CR_SOFT_RESET 0x0080 #define EUR_CR_SOFT_RESET_BIF_RESET_MASK 0x00000001U #define EUR_CR_SOFT_RESET_BIF_RESET_SHIFT 0 @@ -310,6 +336,7 @@ #define EUR_CR_SOFT_RESET_DCU_L0L1_RESET_MASK 0x00080000U #define EUR_CR_SOFT_RESET_DCU_L0L1_RESET_SHIFT 19 #define EUR_CR_SOFT_RESET_DCU_L0L1_RESET_SIGNED 0 +/* Register EUR_CR_EVENT_HOST_ENABLE2 */ #define EUR_CR_EVENT_HOST_ENABLE2 0x0110 #define EUR_CR_EVENT_HOST_ENABLE2_DATA_BREAKPOINT_UNTRAPPED_MASK 0x00000800U #define EUR_CR_EVENT_HOST_ENABLE2_DATA_BREAKPOINT_UNTRAPPED_SHIFT 11 @@ -347,6 +374,7 @@ #define EUR_CR_EVENT_HOST_ENABLE2_DPM_TA_FREE_LOAD_MASK 0x00000001U #define EUR_CR_EVENT_HOST_ENABLE2_DPM_TA_FREE_LOAD_SHIFT 0 #define EUR_CR_EVENT_HOST_ENABLE2_DPM_TA_FREE_LOAD_SIGNED 0 +/* Register EUR_CR_EVENT_HOST_CLEAR2 */ #define EUR_CR_EVENT_HOST_CLEAR2 0x0114 #define EUR_CR_EVENT_HOST_CLEAR2_DATA_BREAKPOINT_UNTRAPPED_MASK 0x00000800U #define EUR_CR_EVENT_HOST_CLEAR2_DATA_BREAKPOINT_UNTRAPPED_SHIFT 11 @@ -384,6 +412,7 @@ #define EUR_CR_EVENT_HOST_CLEAR2_DPM_TA_FREE_LOAD_MASK 0x00000001U #define EUR_CR_EVENT_HOST_CLEAR2_DPM_TA_FREE_LOAD_SHIFT 0 #define EUR_CR_EVENT_HOST_CLEAR2_DPM_TA_FREE_LOAD_SIGNED 0 +/* Register EUR_CR_EVENT_STATUS2 */ #define EUR_CR_EVENT_STATUS2 0x0118 #define EUR_CR_EVENT_STATUS2_DATA_BREAKPOINT_UNTRAPPED_MASK 0x00000800U #define EUR_CR_EVENT_STATUS2_DATA_BREAKPOINT_UNTRAPPED_SHIFT 11 @@ -421,6 +450,7 @@ #define EUR_CR_EVENT_STATUS2_DPM_TA_FREE_LOAD_MASK 0x00000001U #define EUR_CR_EVENT_STATUS2_DPM_TA_FREE_LOAD_SHIFT 0 #define EUR_CR_EVENT_STATUS2_DPM_TA_FREE_LOAD_SIGNED 0 +/* Register EUR_CR_EVENT_STATUS */ #define EUR_CR_EVENT_STATUS 0x012C #define EUR_CR_EVENT_STATUS_MASTER_INTERRUPT_MASK 0x80000000U #define EUR_CR_EVENT_STATUS_MASTER_INTERRUPT_SHIFT 31 @@ -506,6 +536,7 @@ #define EUR_CR_EVENT_STATUS_DPM_3D_MEM_FREE_MASK 0x00000001U #define EUR_CR_EVENT_STATUS_DPM_3D_MEM_FREE_SHIFT 0 #define EUR_CR_EVENT_STATUS_DPM_3D_MEM_FREE_SIGNED 0 +/* Register EUR_CR_EVENT_HOST_ENABLE */ #define EUR_CR_EVENT_HOST_ENABLE 0x0130 #define EUR_CR_EVENT_HOST_ENABLE_MASTER_INTERRUPT_MASK 0x80000000U #define EUR_CR_EVENT_HOST_ENABLE_MASTER_INTERRUPT_SHIFT 31 @@ -591,6 +622,7 @@ #define EUR_CR_EVENT_HOST_ENABLE_DPM_3D_MEM_FREE_MASK 0x00000001U #define EUR_CR_EVENT_HOST_ENABLE_DPM_3D_MEM_FREE_SHIFT 0 #define EUR_CR_EVENT_HOST_ENABLE_DPM_3D_MEM_FREE_SIGNED 0 +/* Register EUR_CR_EVENT_HOST_CLEAR */ #define EUR_CR_EVENT_HOST_CLEAR 0x0134 #define EUR_CR_EVENT_HOST_CLEAR_MASTER_INTERRUPT_MASK 0x80000000U #define EUR_CR_EVENT_HOST_CLEAR_MASTER_INTERRUPT_SHIFT 31 @@ -676,26 +708,32 @@ #define EUR_CR_EVENT_HOST_CLEAR_DPM_3D_MEM_FREE_MASK 0x00000001U #define EUR_CR_EVENT_HOST_CLEAR_DPM_3D_MEM_FREE_SHIFT 0 #define EUR_CR_EVENT_HOST_CLEAR_DPM_3D_MEM_FREE_SIGNED 0 +/* Register EUR_CR_TIMER */ #define EUR_CR_TIMER 0x0144 #define EUR_CR_TIMER_VALUE_MASK 0xFFFFFFFFU #define EUR_CR_TIMER_VALUE_SHIFT 0 #define EUR_CR_TIMER_VALUE_SIGNED 0 +/* Register EUR_CR_EVENT_KICK1 */ #define EUR_CR_EVENT_KICK1 0x0AB0 #define EUR_CR_EVENT_KICK1_NOW_MASK 0x000000FFU #define EUR_CR_EVENT_KICK1_NOW_SHIFT 0 #define EUR_CR_EVENT_KICK1_NOW_SIGNED 0 +/* Register EUR_CR_EVENT_KICK2 */ #define EUR_CR_EVENT_KICK2 0x0AC0 #define EUR_CR_EVENT_KICK2_NOW_MASK 0x00000001U #define EUR_CR_EVENT_KICK2_NOW_SHIFT 0 #define EUR_CR_EVENT_KICK2_NOW_SIGNED 0 +/* Register EUR_CR_EVENT_KICKER */ #define EUR_CR_EVENT_KICKER 0x0AC4 #define EUR_CR_EVENT_KICKER_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_EVENT_KICKER_ADDRESS_SHIFT 4 #define EUR_CR_EVENT_KICKER_ADDRESS_SIGNED 0 +/* Register EUR_CR_EVENT_KICK */ #define EUR_CR_EVENT_KICK 0x0AC8 #define EUR_CR_EVENT_KICK_NOW_MASK 0x00000001U #define EUR_CR_EVENT_KICK_NOW_SHIFT 0 #define EUR_CR_EVENT_KICK_NOW_SIGNED 0 +/* Register EUR_CR_EVENT_TIMER */ #define EUR_CR_EVENT_TIMER 0x0ACC #define EUR_CR_EVENT_TIMER_ENABLE_MASK 0x01000000U #define EUR_CR_EVENT_TIMER_ENABLE_SHIFT 24 @@ -703,26 +741,32 @@ #define EUR_CR_EVENT_TIMER_VALUE_MASK 0x00FFFFFFU #define EUR_CR_EVENT_TIMER_VALUE_SHIFT 0 #define EUR_CR_EVENT_TIMER_VALUE_SIGNED 0 +/* Register EUR_CR_PDS_INV0 */ #define EUR_CR_PDS_INV0 0x0AD0 #define EUR_CR_PDS_INV0_DSC_MASK 0x00000001U #define EUR_CR_PDS_INV0_DSC_SHIFT 0 #define EUR_CR_PDS_INV0_DSC_SIGNED 0 +/* Register EUR_CR_PDS_INV1 */ #define EUR_CR_PDS_INV1 0x0AD4 #define EUR_CR_PDS_INV1_DSC_MASK 0x00000001U #define EUR_CR_PDS_INV1_DSC_SHIFT 0 #define EUR_CR_PDS_INV1_DSC_SIGNED 0 +/* Register EUR_CR_EVENT_KICK3 */ #define EUR_CR_EVENT_KICK3 0x0AD8 #define EUR_CR_EVENT_KICK3_NOW_MASK 0x00000001U #define EUR_CR_EVENT_KICK3_NOW_SHIFT 0 #define EUR_CR_EVENT_KICK3_NOW_SIGNED 0 +/* Register EUR_CR_PDS_INV3 */ #define EUR_CR_PDS_INV3 0x0ADC #define EUR_CR_PDS_INV3_DSC_MASK 0x00000001U #define EUR_CR_PDS_INV3_DSC_SHIFT 0 #define EUR_CR_PDS_INV3_DSC_SIGNED 0 +/* Register EUR_CR_PDS_INV_CSC */ #define EUR_CR_PDS_INV_CSC 0x0AE0 #define EUR_CR_PDS_INV_CSC_KICK_MASK 0x00000001U #define EUR_CR_PDS_INV_CSC_KICK_SHIFT 0 #define EUR_CR_PDS_INV_CSC_KICK_SIGNED 0 +/* Register EUR_CR_BIF_CTRL */ #define EUR_CR_BIF_CTRL 0x0C00 #define EUR_CR_BIF_CTRL_NOREORDER_MASK 0x00000001U #define EUR_CR_BIF_CTRL_NOREORDER_SHIFT 0 @@ -763,6 +807,7 @@ #define EUR_CR_BIF_CTRL_MMU_BYPASS_MASTER_DPM_MASK 0x00080000U #define EUR_CR_BIF_CTRL_MMU_BYPASS_MASTER_DPM_SHIFT 19 #define EUR_CR_BIF_CTRL_MMU_BYPASS_MASTER_DPM_SIGNED 0 +/* Register EUR_CR_BIF_INT_STAT */ #define EUR_CR_BIF_INT_STAT 0x0C04 #define EUR_CR_BIF_INT_STAT_FAULT_REQ_MASK 0x00003FFFU #define EUR_CR_BIF_INT_STAT_FAULT_REQ_SHIFT 0 @@ -773,6 +818,7 @@ #define EUR_CR_BIF_INT_STAT_FLUSH_COMPLETE_MASK 0x00080000U #define EUR_CR_BIF_INT_STAT_FLUSH_COMPLETE_SHIFT 19 #define EUR_CR_BIF_INT_STAT_FLUSH_COMPLETE_SIGNED 0 +/* Register EUR_CR_BIF_FAULT */ #define EUR_CR_BIF_FAULT 0x0C08 #define EUR_CR_BIF_FAULT_CID_MASK 0x0000000FU #define EUR_CR_BIF_FAULT_CID_SHIFT 0 @@ -783,6 +829,7 @@ #define EUR_CR_BIF_FAULT_ADDR_MASK 0xFFFFF000U #define EUR_CR_BIF_FAULT_ADDR_SHIFT 12 #define EUR_CR_BIF_FAULT_ADDR_SIGNED 0 +/* Register EUR_CR_BIF_TILE0 */ #define EUR_CR_BIF_TILE0 0x0C0C #define EUR_CR_BIF_TILE0_MIN_ADDRESS_MASK 0x00000FFFU #define EUR_CR_BIF_TILE0_MIN_ADDRESS_SHIFT 0 @@ -793,6 +840,7 @@ #define EUR_CR_BIF_TILE0_CFG_MASK 0x0F000000U #define EUR_CR_BIF_TILE0_CFG_SHIFT 24 #define EUR_CR_BIF_TILE0_CFG_SIGNED 0 +/* Register EUR_CR_BIF_TILE1 */ #define EUR_CR_BIF_TILE1 0x0C10 #define EUR_CR_BIF_TILE1_MIN_ADDRESS_MASK 0x00000FFFU #define EUR_CR_BIF_TILE1_MIN_ADDRESS_SHIFT 0 @@ -803,6 +851,7 @@ #define EUR_CR_BIF_TILE1_CFG_MASK 0x0F000000U #define EUR_CR_BIF_TILE1_CFG_SHIFT 24 #define EUR_CR_BIF_TILE1_CFG_SIGNED 0 +/* Register EUR_CR_BIF_TILE2 */ #define EUR_CR_BIF_TILE2 0x0C14 #define EUR_CR_BIF_TILE2_MIN_ADDRESS_MASK 0x00000FFFU #define EUR_CR_BIF_TILE2_MIN_ADDRESS_SHIFT 0 @@ -813,6 +862,7 @@ #define EUR_CR_BIF_TILE2_CFG_MASK 0x0F000000U #define EUR_CR_BIF_TILE2_CFG_SHIFT 24 #define EUR_CR_BIF_TILE2_CFG_SIGNED 0 +/* Register EUR_CR_BIF_TILE3 */ #define EUR_CR_BIF_TILE3 0x0C18 #define EUR_CR_BIF_TILE3_MIN_ADDRESS_MASK 0x00000FFFU #define EUR_CR_BIF_TILE3_MIN_ADDRESS_SHIFT 0 @@ -823,6 +873,7 @@ #define EUR_CR_BIF_TILE3_CFG_MASK 0x0F000000U #define EUR_CR_BIF_TILE3_CFG_SHIFT 24 #define EUR_CR_BIF_TILE3_CFG_SIGNED 0 +/* Register EUR_CR_BIF_TILE4 */ #define EUR_CR_BIF_TILE4 0x0C1C #define EUR_CR_BIF_TILE4_MIN_ADDRESS_MASK 0x00000FFFU #define EUR_CR_BIF_TILE4_MIN_ADDRESS_SHIFT 0 @@ -833,6 +884,7 @@ #define EUR_CR_BIF_TILE4_CFG_MASK 0x0F000000U #define EUR_CR_BIF_TILE4_CFG_SHIFT 24 #define EUR_CR_BIF_TILE4_CFG_SIGNED 0 +/* Register EUR_CR_BIF_TILE5 */ #define EUR_CR_BIF_TILE5 0x0C20 #define EUR_CR_BIF_TILE5_MIN_ADDRESS_MASK 0x00000FFFU #define EUR_CR_BIF_TILE5_MIN_ADDRESS_SHIFT 0 @@ -843,6 +895,7 @@ #define EUR_CR_BIF_TILE5_CFG_MASK 0x0F000000U #define EUR_CR_BIF_TILE5_CFG_SHIFT 24 #define EUR_CR_BIF_TILE5_CFG_SIGNED 0 +/* Register EUR_CR_BIF_TILE6 */ #define EUR_CR_BIF_TILE6 0x0C24 #define EUR_CR_BIF_TILE6_MIN_ADDRESS_MASK 0x00000FFFU #define EUR_CR_BIF_TILE6_MIN_ADDRESS_SHIFT 0 @@ -853,6 +906,7 @@ #define EUR_CR_BIF_TILE6_CFG_MASK 0x0F000000U #define EUR_CR_BIF_TILE6_CFG_SHIFT 24 #define EUR_CR_BIF_TILE6_CFG_SIGNED 0 +/* Register EUR_CR_BIF_TILE7 */ #define EUR_CR_BIF_TILE7 0x0C28 #define EUR_CR_BIF_TILE7_MIN_ADDRESS_MASK 0x00000FFFU #define EUR_CR_BIF_TILE7_MIN_ADDRESS_SHIFT 0 @@ -863,6 +917,7 @@ #define EUR_CR_BIF_TILE7_CFG_MASK 0x0F000000U #define EUR_CR_BIF_TILE7_CFG_SHIFT 24 #define EUR_CR_BIF_TILE7_CFG_SIGNED 0 +/* Register EUR_CR_BIF_TILE8 */ #define EUR_CR_BIF_TILE8 0x0C2C #define EUR_CR_BIF_TILE8_MIN_ADDRESS_MASK 0x00000FFFU #define EUR_CR_BIF_TILE8_MIN_ADDRESS_SHIFT 0 @@ -873,6 +928,7 @@ #define EUR_CR_BIF_TILE8_CFG_MASK 0x0F000000U #define EUR_CR_BIF_TILE8_CFG_SHIFT 24 #define EUR_CR_BIF_TILE8_CFG_SIGNED 0 +/* Register EUR_CR_BIF_TILE9 */ #define EUR_CR_BIF_TILE9 0x0C30 #define EUR_CR_BIF_TILE9_MIN_ADDRESS_MASK 0x00000FFFU #define EUR_CR_BIF_TILE9_MIN_ADDRESS_SHIFT 0 @@ -883,6 +939,7 @@ #define EUR_CR_BIF_TILE9_CFG_MASK 0x0F000000U #define EUR_CR_BIF_TILE9_CFG_SHIFT 24 #define EUR_CR_BIF_TILE9_CFG_SIGNED 0 +/* Register EUR_CR_BIF_CTRL_INVAL */ #define EUR_CR_BIF_CTRL_INVAL 0x0C34 #define EUR_CR_BIF_CTRL_INVAL_PTE_MASK 0x00000004U #define EUR_CR_BIF_CTRL_INVAL_PTE_SHIFT 2 @@ -890,34 +947,42 @@ #define EUR_CR_BIF_CTRL_INVAL_ALL_MASK 0x00000008U #define EUR_CR_BIF_CTRL_INVAL_ALL_SHIFT 3 #define EUR_CR_BIF_CTRL_INVAL_ALL_SIGNED 0 +/* Register EUR_CR_BIF_DIR_LIST_BASE1 */ #define EUR_CR_BIF_DIR_LIST_BASE1 0x0C38 #define EUR_CR_BIF_DIR_LIST_BASE1_ADDR_MASK 0xFFFFF000U #define EUR_CR_BIF_DIR_LIST_BASE1_ADDR_SHIFT 12 #define EUR_CR_BIF_DIR_LIST_BASE1_ADDR_SIGNED 0 +/* Register EUR_CR_BIF_DIR_LIST_BASE2 */ #define EUR_CR_BIF_DIR_LIST_BASE2 0x0C3C #define EUR_CR_BIF_DIR_LIST_BASE2_ADDR_MASK 0xFFFFF000U #define EUR_CR_BIF_DIR_LIST_BASE2_ADDR_SHIFT 12 #define EUR_CR_BIF_DIR_LIST_BASE2_ADDR_SIGNED 0 +/* Register EUR_CR_BIF_DIR_LIST_BASE3 */ #define EUR_CR_BIF_DIR_LIST_BASE3 0x0C40 #define EUR_CR_BIF_DIR_LIST_BASE3_ADDR_MASK 0xFFFFF000U #define EUR_CR_BIF_DIR_LIST_BASE3_ADDR_SHIFT 12 #define EUR_CR_BIF_DIR_LIST_BASE3_ADDR_SIGNED 0 +/* Register EUR_CR_BIF_DIR_LIST_BASE4 */ #define EUR_CR_BIF_DIR_LIST_BASE4 0x0C44 #define EUR_CR_BIF_DIR_LIST_BASE4_ADDR_MASK 0xFFFFF000U #define EUR_CR_BIF_DIR_LIST_BASE4_ADDR_SHIFT 12 #define EUR_CR_BIF_DIR_LIST_BASE4_ADDR_SIGNED 0 +/* Register EUR_CR_BIF_DIR_LIST_BASE5 */ #define EUR_CR_BIF_DIR_LIST_BASE5 0x0C48 #define EUR_CR_BIF_DIR_LIST_BASE5_ADDR_MASK 0xFFFFF000U #define EUR_CR_BIF_DIR_LIST_BASE5_ADDR_SHIFT 12 #define EUR_CR_BIF_DIR_LIST_BASE5_ADDR_SIGNED 0 +/* Register EUR_CR_BIF_DIR_LIST_BASE6 */ #define EUR_CR_BIF_DIR_LIST_BASE6 0x0C4C #define EUR_CR_BIF_DIR_LIST_BASE6_ADDR_MASK 0xFFFFF000U #define EUR_CR_BIF_DIR_LIST_BASE6_ADDR_SHIFT 12 #define EUR_CR_BIF_DIR_LIST_BASE6_ADDR_SIGNED 0 +/* Register EUR_CR_BIF_DIR_LIST_BASE7 */ #define EUR_CR_BIF_DIR_LIST_BASE7 0x0C50 #define EUR_CR_BIF_DIR_LIST_BASE7_ADDR_MASK 0xFFFFF000U #define EUR_CR_BIF_DIR_LIST_BASE7_ADDR_SHIFT 12 #define EUR_CR_BIF_DIR_LIST_BASE7_ADDR_SIGNED 0 +/* Register EUR_CR_BIF_BANK_SET */ #define EUR_CR_BIF_BANK_SET 0x0C74 #define EUR_CR_BIF_BANK_SET_SELECT_2D_MASK 0x00000001U #define EUR_CR_BIF_BANK_SET_SELECT_2D_SHIFT 0 @@ -937,6 +1002,7 @@ #define EUR_CR_BIF_BANK_SET_SELECT_DPM_LSS_MASK 0x00000200U #define EUR_CR_BIF_BANK_SET_SELECT_DPM_LSS_SHIFT 9 #define EUR_CR_BIF_BANK_SET_SELECT_DPM_LSS_SIGNED 0 +/* Register EUR_CR_BIF_BANK0 */ #define EUR_CR_BIF_BANK0 0x0C78 #define EUR_CR_BIF_BANK0_INDEX_EDM_MASK 0x0000000FU #define EUR_CR_BIF_BANK0_INDEX_EDM_SHIFT 0 @@ -950,6 +1016,7 @@ #define EUR_CR_BIF_BANK0_INDEX_PTLA_MASK 0x000F0000U #define EUR_CR_BIF_BANK0_INDEX_PTLA_SHIFT 16 #define EUR_CR_BIF_BANK0_INDEX_PTLA_SIGNED 0 +/* Register EUR_CR_BIF_BANK1 */ #define EUR_CR_BIF_BANK1 0x0C7C #define EUR_CR_BIF_BANK1_INDEX_EDM_MASK 0x0000000FU #define EUR_CR_BIF_BANK1_INDEX_EDM_SHIFT 0 @@ -960,26 +1027,32 @@ #define EUR_CR_BIF_BANK1_INDEX_3D_MASK 0x0000F000U #define EUR_CR_BIF_BANK1_INDEX_3D_SHIFT 12 #define EUR_CR_BIF_BANK1_INDEX_3D_SIGNED 0 +/* Register EUR_CR_BIF_DIR_LIST_BASE0 */ #define EUR_CR_BIF_DIR_LIST_BASE0 0x0C84 #define EUR_CR_BIF_DIR_LIST_BASE0_ADDR_MASK 0xFFFFF000U #define EUR_CR_BIF_DIR_LIST_BASE0_ADDR_SHIFT 12 #define EUR_CR_BIF_DIR_LIST_BASE0_ADDR_SIGNED 0 +/* Register EUR_CR_BIF_TA_REQ_BASE */ #define EUR_CR_BIF_TA_REQ_BASE 0x0C90 #define EUR_CR_BIF_TA_REQ_BASE_ADDR_MASK 0xFFF00000U #define EUR_CR_BIF_TA_REQ_BASE_ADDR_SHIFT 20 #define EUR_CR_BIF_TA_REQ_BASE_ADDR_SIGNED 0 +/* Register EUR_CR_BIF_MEM_REQ_STAT */ #define EUR_CR_BIF_MEM_REQ_STAT 0x0CA8 #define EUR_CR_BIF_MEM_REQ_STAT_READS_MASK 0x000000FFU #define EUR_CR_BIF_MEM_REQ_STAT_READS_SHIFT 0 #define EUR_CR_BIF_MEM_REQ_STAT_READS_SIGNED 0 +/* Register EUR_CR_BIF_3D_REQ_BASE */ #define EUR_CR_BIF_3D_REQ_BASE 0x0CAC #define EUR_CR_BIF_3D_REQ_BASE_ADDR_MASK 0xFFF00000U #define EUR_CR_BIF_3D_REQ_BASE_ADDR_SHIFT 20 #define EUR_CR_BIF_3D_REQ_BASE_ADDR_SIGNED 0 +/* Register EUR_CR_BIF_ZLS_REQ_BASE */ #define EUR_CR_BIF_ZLS_REQ_BASE 0x0CB0 #define EUR_CR_BIF_ZLS_REQ_BASE_ADDR_MASK 0xFFF00000U #define EUR_CR_BIF_ZLS_REQ_BASE_ADDR_SHIFT 20 #define EUR_CR_BIF_ZLS_REQ_BASE_ADDR_SIGNED 0 +/* Register EUR_CR_BIF_BANK_STATUS */ #define EUR_CR_BIF_BANK_STATUS 0x0CB4 #define EUR_CR_BIF_BANK_STATUS_3D_CURRENT_BANK_MASK 0x00000001U #define EUR_CR_BIF_BANK_STATUS_3D_CURRENT_BANK_SHIFT 0 @@ -987,6 +1060,7 @@ #define EUR_CR_BIF_BANK_STATUS_TA_CURRENT_BANK_MASK 0x00000002U #define EUR_CR_BIF_BANK_STATUS_TA_CURRENT_BANK_SHIFT 1 #define EUR_CR_BIF_BANK_STATUS_TA_CURRENT_BANK_SIGNED 0 +/* Register EUR_CR_BIF_MMU_CTRL */ #define EUR_CR_BIF_MMU_CTRL 0x0CD0 #define EUR_CR_BIF_MMU_CTRL_PREFETCHING_ON_MASK 0x00000001U #define EUR_CR_BIF_MMU_CTRL_PREFETCHING_ON_SHIFT 0 @@ -1003,6 +1077,7 @@ #define EUR_CR_BIF_MMU_CTRL_DISABLE_BURST_EXP_MASK 0x00000020U #define EUR_CR_BIF_MMU_CTRL_DISABLE_BURST_EXP_SHIFT 5 #define EUR_CR_BIF_MMU_CTRL_DISABLE_BURST_EXP_SIGNED 0 +/* Register EUR_CR_2D_BLIT_STATUS */ #define EUR_CR_2D_BLIT_STATUS 0x0E04 #define EUR_CR_2D_BLIT_STATUS_COMPLETE_MASK 0x00FFFFFFU #define EUR_CR_2D_BLIT_STATUS_COMPLETE_SHIFT 0 @@ -1010,6 +1085,7 @@ #define EUR_CR_2D_BLIT_STATUS_BUSY_MASK 0x01000000U #define EUR_CR_2D_BLIT_STATUS_BUSY_SHIFT 24 #define EUR_CR_2D_BLIT_STATUS_BUSY_SIGNED 0 +/* Register EUR_CR_2D_VIRTUAL_FIFO_0 */ #define EUR_CR_2D_VIRTUAL_FIFO_0 0x0E10 #define EUR_CR_2D_VIRTUAL_FIFO_0_ENABLE_MASK 0x00000001U #define EUR_CR_2D_VIRTUAL_FIFO_0_ENABLE_SHIFT 0 @@ -1023,6 +1099,7 @@ #define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_MUL_MASK 0x0000F000U #define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_MUL_SHIFT 12 #define EUR_CR_2D_VIRTUAL_FIFO_0_FLOWRATE_MUL_SIGNED 0 +/* Register EUR_CR_2D_VIRTUAL_FIFO_1 */ #define EUR_CR_2D_VIRTUAL_FIFO_1 0x0E14 #define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_ACC_MASK 0x00000FFFU #define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_ACC_SHIFT 0 @@ -1033,14 +1110,17 @@ #define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_METRIC_MASK 0xFF000000U #define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_METRIC_SHIFT 24 #define EUR_CR_2D_VIRTUAL_FIFO_1_MIN_METRIC_SIGNED 0 +/* Register EUR_CR_BREAKPOINT0_START */ #define EUR_CR_BREAKPOINT0_START 0x0F44 #define EUR_CR_BREAKPOINT0_START_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_BREAKPOINT0_START_ADDRESS_SHIFT 4 #define EUR_CR_BREAKPOINT0_START_ADDRESS_SIGNED 0 +/* Register EUR_CR_BREAKPOINT0_END */ #define EUR_CR_BREAKPOINT0_END 0x0F48 #define EUR_CR_BREAKPOINT0_END_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_BREAKPOINT0_END_ADDRESS_SHIFT 4 #define EUR_CR_BREAKPOINT0_END_ADDRESS_SIGNED 0 +/* Register EUR_CR_BREAKPOINT0 */ #define EUR_CR_BREAKPOINT0 0x0F4C #define EUR_CR_BREAKPOINT0_MASK_DM_MASK 0x00000038U #define EUR_CR_BREAKPOINT0_MASK_DM_SHIFT 3 @@ -1054,14 +1134,17 @@ #define EUR_CR_BREAKPOINT0_CTRL_RENABLE_MASK 0x00000001U #define EUR_CR_BREAKPOINT0_CTRL_RENABLE_SHIFT 0 #define EUR_CR_BREAKPOINT0_CTRL_RENABLE_SIGNED 0 +/* Register EUR_CR_BREAKPOINT1_START */ #define EUR_CR_BREAKPOINT1_START 0x0F50 #define EUR_CR_BREAKPOINT1_START_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_BREAKPOINT1_START_ADDRESS_SHIFT 4 #define EUR_CR_BREAKPOINT1_START_ADDRESS_SIGNED 0 +/* Register EUR_CR_BREAKPOINT1_END */ #define EUR_CR_BREAKPOINT1_END 0x0F54 #define EUR_CR_BREAKPOINT1_END_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_BREAKPOINT1_END_ADDRESS_SHIFT 4 #define EUR_CR_BREAKPOINT1_END_ADDRESS_SIGNED 0 +/* Register EUR_CR_BREAKPOINT1 */ #define EUR_CR_BREAKPOINT1 0x0F58 #define EUR_CR_BREAKPOINT1_MASK_DM_MASK 0x00000038U #define EUR_CR_BREAKPOINT1_MASK_DM_SHIFT 3 @@ -1075,14 +1158,17 @@ #define EUR_CR_BREAKPOINT1_CTRL_RENABLE_MASK 0x00000001U #define EUR_CR_BREAKPOINT1_CTRL_RENABLE_SHIFT 0 #define EUR_CR_BREAKPOINT1_CTRL_RENABLE_SIGNED 0 +/* Register EUR_CR_BREAKPOINT2_START */ #define EUR_CR_BREAKPOINT2_START 0x0F5C #define EUR_CR_BREAKPOINT2_START_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_BREAKPOINT2_START_ADDRESS_SHIFT 4 #define EUR_CR_BREAKPOINT2_START_ADDRESS_SIGNED 0 +/* Register EUR_CR_BREAKPOINT2_END */ #define EUR_CR_BREAKPOINT2_END 0x0F60 #define EUR_CR_BREAKPOINT2_END_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_BREAKPOINT2_END_ADDRESS_SHIFT 4 #define EUR_CR_BREAKPOINT2_END_ADDRESS_SIGNED 0 +/* Register EUR_CR_BREAKPOINT2 */ #define EUR_CR_BREAKPOINT2 0x0F64 #define EUR_CR_BREAKPOINT2_MASK_DM_MASK 0x00000038U #define EUR_CR_BREAKPOINT2_MASK_DM_SHIFT 3 @@ -1096,14 +1182,17 @@ #define EUR_CR_BREAKPOINT2_CTRL_RENABLE_MASK 0x00000001U #define EUR_CR_BREAKPOINT2_CTRL_RENABLE_SHIFT 0 #define EUR_CR_BREAKPOINT2_CTRL_RENABLE_SIGNED 0 +/* Register EUR_CR_BREAKPOINT3_START */ #define EUR_CR_BREAKPOINT3_START 0x0F68 #define EUR_CR_BREAKPOINT3_START_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_BREAKPOINT3_START_ADDRESS_SHIFT 4 #define EUR_CR_BREAKPOINT3_START_ADDRESS_SIGNED 0 +/* Register EUR_CR_BREAKPOINT3_END */ #define EUR_CR_BREAKPOINT3_END 0x0F6C #define EUR_CR_BREAKPOINT3_END_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_BREAKPOINT3_END_ADDRESS_SHIFT 4 #define EUR_CR_BREAKPOINT3_END_ADDRESS_SIGNED 0 +/* Register EUR_CR_BREAKPOINT3 */ #define EUR_CR_BREAKPOINT3 0x0F70 #define EUR_CR_BREAKPOINT3_MASK_DM_MASK 0x00000038U #define EUR_CR_BREAKPOINT3_MASK_DM_SHIFT 3 @@ -1117,10 +1206,12 @@ #define EUR_CR_BREAKPOINT3_CTRL_RENABLE_MASK 0x00000001U #define EUR_CR_BREAKPOINT3_CTRL_RENABLE_SHIFT 0 #define EUR_CR_BREAKPOINT3_CTRL_RENABLE_SIGNED 0 +/* Register EUR_CR_BREAKPOINT_READ */ #define EUR_CR_BREAKPOINT_READ 0x0F74 #define EUR_CR_BREAKPOINT_READ_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_BREAKPOINT_READ_ADDRESS_SHIFT 4 #define EUR_CR_BREAKPOINT_READ_ADDRESS_SIGNED 0 +/* Register EUR_CR_PARTITION_BREAKPOINT_TRAP */ #define EUR_CR_PARTITION_BREAKPOINT_TRAP 0x0F78 #define EUR_CR_PARTITION_BREAKPOINT_TRAP_CONTINUE_MASK 0x00000002U #define EUR_CR_PARTITION_BREAKPOINT_TRAP_CONTINUE_SHIFT 1 @@ -1128,6 +1219,7 @@ #define EUR_CR_PARTITION_BREAKPOINT_TRAP_WRNOTIFY_MASK 0x00000001U #define EUR_CR_PARTITION_BREAKPOINT_TRAP_WRNOTIFY_SHIFT 0 #define EUR_CR_PARTITION_BREAKPOINT_TRAP_WRNOTIFY_SIGNED 0 +/* Register EUR_CR_PARTITION_BREAKPOINT */ #define EUR_CR_PARTITION_BREAKPOINT 0x0F7C #define EUR_CR_PARTITION_BREAKPOINT_MODULE_ID_MASK 0x000003C0U #define EUR_CR_PARTITION_BREAKPOINT_MODULE_ID_SHIFT 6 @@ -1141,10 +1233,12 @@ #define EUR_CR_PARTITION_BREAKPOINT_TRAPPED_MASK 0x00000004U #define EUR_CR_PARTITION_BREAKPOINT_TRAPPED_SHIFT 2 #define EUR_CR_PARTITION_BREAKPOINT_TRAPPED_SIGNED 0 +/* Register EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO0 */ #define EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO0 0x0F80 #define EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO0_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO0_ADDRESS_SHIFT 4 #define EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO0_ADDRESS_SIGNED 0 +/* Register EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1 */ #define EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1 0x0F84 #define EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_SIZE_MASK 0x00007C00U #define EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_SIZE_SHIFT 10 @@ -1161,6 +1255,7 @@ #define EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_RNW_MASK 0x00000001U #define EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_RNW_SHIFT 0 #define EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_RNW_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_0 */ #define EUR_CR_USE_CODE_BASE_0 0x0A0C #define EUR_CR_USE_CODE_BASE_ADDR_00_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_00_SHIFT 0 @@ -1168,6 +1263,7 @@ #define EUR_CR_USE_CODE_BASE_DM_00_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_00_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_00_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_1 */ #define EUR_CR_USE_CODE_BASE_1 0x0A10 #define EUR_CR_USE_CODE_BASE_ADDR_01_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_01_SHIFT 0 @@ -1175,6 +1271,7 @@ #define EUR_CR_USE_CODE_BASE_DM_01_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_01_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_01_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_2 */ #define EUR_CR_USE_CODE_BASE_2 0x0A14 #define EUR_CR_USE_CODE_BASE_ADDR_02_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_02_SHIFT 0 @@ -1182,6 +1279,7 @@ #define EUR_CR_USE_CODE_BASE_DM_02_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_02_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_02_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_3 */ #define EUR_CR_USE_CODE_BASE_3 0x0A18 #define EUR_CR_USE_CODE_BASE_ADDR_03_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_03_SHIFT 0 @@ -1189,6 +1287,7 @@ #define EUR_CR_USE_CODE_BASE_DM_03_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_03_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_03_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_4 */ #define EUR_CR_USE_CODE_BASE_4 0x0A1C #define EUR_CR_USE_CODE_BASE_ADDR_04_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_04_SHIFT 0 @@ -1196,6 +1295,7 @@ #define EUR_CR_USE_CODE_BASE_DM_04_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_04_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_04_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_5 */ #define EUR_CR_USE_CODE_BASE_5 0x0A20 #define EUR_CR_USE_CODE_BASE_ADDR_05_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_05_SHIFT 0 @@ -1203,6 +1303,7 @@ #define EUR_CR_USE_CODE_BASE_DM_05_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_05_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_05_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_6 */ #define EUR_CR_USE_CODE_BASE_6 0x0A24 #define EUR_CR_USE_CODE_BASE_ADDR_06_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_06_SHIFT 0 @@ -1210,6 +1311,7 @@ #define EUR_CR_USE_CODE_BASE_DM_06_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_06_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_06_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_7 */ #define EUR_CR_USE_CODE_BASE_7 0x0A28 #define EUR_CR_USE_CODE_BASE_ADDR_07_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_07_SHIFT 0 @@ -1217,6 +1319,7 @@ #define EUR_CR_USE_CODE_BASE_DM_07_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_07_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_07_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_8 */ #define EUR_CR_USE_CODE_BASE_8 0x0A2C #define EUR_CR_USE_CODE_BASE_ADDR_08_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_08_SHIFT 0 @@ -1224,6 +1327,7 @@ #define EUR_CR_USE_CODE_BASE_DM_08_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_08_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_08_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_9 */ #define EUR_CR_USE_CODE_BASE_9 0x0A30 #define EUR_CR_USE_CODE_BASE_ADDR_09_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_09_SHIFT 0 @@ -1231,6 +1335,7 @@ #define EUR_CR_USE_CODE_BASE_DM_09_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_09_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_09_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_10 */ #define EUR_CR_USE_CODE_BASE_10 0x0A34 #define EUR_CR_USE_CODE_BASE_ADDR_10_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_10_SHIFT 0 @@ -1238,6 +1343,7 @@ #define EUR_CR_USE_CODE_BASE_DM_10_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_10_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_10_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_11 */ #define EUR_CR_USE_CODE_BASE_11 0x0A38 #define EUR_CR_USE_CODE_BASE_ADDR_11_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_11_SHIFT 0 @@ -1245,6 +1351,7 @@ #define EUR_CR_USE_CODE_BASE_DM_11_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_11_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_11_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_12 */ #define EUR_CR_USE_CODE_BASE_12 0x0A3C #define EUR_CR_USE_CODE_BASE_ADDR_12_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_12_SHIFT 0 @@ -1252,6 +1359,7 @@ #define EUR_CR_USE_CODE_BASE_DM_12_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_12_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_12_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_13 */ #define EUR_CR_USE_CODE_BASE_13 0x0A40 #define EUR_CR_USE_CODE_BASE_ADDR_13_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_13_SHIFT 0 @@ -1259,6 +1367,7 @@ #define EUR_CR_USE_CODE_BASE_DM_13_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_13_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_13_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_14 */ #define EUR_CR_USE_CODE_BASE_14 0x0A44 #define EUR_CR_USE_CODE_BASE_ADDR_14_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_14_SHIFT 0 @@ -1266,6 +1375,7 @@ #define EUR_CR_USE_CODE_BASE_DM_14_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_14_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_14_SIGNED 0 +/* Register EUR_CR_USE_CODE_BASE_15 */ #define EUR_CR_USE_CODE_BASE_15 0x0A48 #define EUR_CR_USE_CODE_BASE_ADDR_15_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_15_SHIFT 0 @@ -1273,6 +1383,7 @@ #define EUR_CR_USE_CODE_BASE_DM_15_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_15_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_15_SIGNED 0 +/* Register EUR_CR_PIPE0_BREAKPOINT_TRAP */ #define EUR_CR_PIPE0_BREAKPOINT_TRAP 0x0F88 #define EUR_CR_PIPE0_BREAKPOINT_TRAP_CONTINUE_MASK 0x00000002U #define EUR_CR_PIPE0_BREAKPOINT_TRAP_CONTINUE_SHIFT 1 @@ -1280,6 +1391,7 @@ #define EUR_CR_PIPE0_BREAKPOINT_TRAP_WRNOTIFY_MASK 0x00000001U #define EUR_CR_PIPE0_BREAKPOINT_TRAP_WRNOTIFY_SHIFT 0 #define EUR_CR_PIPE0_BREAKPOINT_TRAP_WRNOTIFY_SIGNED 0 +/* Register EUR_CR_PIPE0_BREAKPOINT */ #define EUR_CR_PIPE0_BREAKPOINT 0x0F8C #define EUR_CR_PIPE0_BREAKPOINT_MODULE_ID_MASK 0x000003C0U #define EUR_CR_PIPE0_BREAKPOINT_MODULE_ID_SHIFT 6 @@ -1293,10 +1405,12 @@ #define EUR_CR_PIPE0_BREAKPOINT_TRAPPED_MASK 0x00000004U #define EUR_CR_PIPE0_BREAKPOINT_TRAPPED_SHIFT 2 #define EUR_CR_PIPE0_BREAKPOINT_TRAPPED_SIGNED 0 +/* Register EUR_CR_PIPE0_BREAKPOINT_TRAP_INFO0 */ #define EUR_CR_PIPE0_BREAKPOINT_TRAP_INFO0 0x0F90 #define EUR_CR_PIPE0_BREAKPOINT_TRAP_INFO0_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_PIPE0_BREAKPOINT_TRAP_INFO0_ADDRESS_SHIFT 4 #define EUR_CR_PIPE0_BREAKPOINT_TRAP_INFO0_ADDRESS_SIGNED 0 +/* Register EUR_CR_PIPE0_BREAKPOINT_TRAP_INFO1 */ #define EUR_CR_PIPE0_BREAKPOINT_TRAP_INFO1 0x0F94 #define EUR_CR_PIPE0_BREAKPOINT_TRAP_INFO1_SIZE_MASK 0x00007C00U #define EUR_CR_PIPE0_BREAKPOINT_TRAP_INFO1_SIZE_SHIFT 10 @@ -1313,6 +1427,7 @@ #define EUR_CR_PIPE0_BREAKPOINT_TRAP_INFO1_RNW_MASK 0x00000001U #define EUR_CR_PIPE0_BREAKPOINT_TRAP_INFO1_RNW_SHIFT 0 #define EUR_CR_PIPE0_BREAKPOINT_TRAP_INFO1_RNW_SIGNED 0 +/* Register EUR_CR_PIPE1_BREAKPOINT_TRAP */ #define EUR_CR_PIPE1_BREAKPOINT_TRAP 0x0F98 #define EUR_CR_PIPE1_BREAKPOINT_TRAP_CONTINUE_MASK 0x00000002U #define EUR_CR_PIPE1_BREAKPOINT_TRAP_CONTINUE_SHIFT 1 @@ -1320,6 +1435,7 @@ #define EUR_CR_PIPE1_BREAKPOINT_TRAP_WRNOTIFY_MASK 0x00000001U #define EUR_CR_PIPE1_BREAKPOINT_TRAP_WRNOTIFY_SHIFT 0 #define EUR_CR_PIPE1_BREAKPOINT_TRAP_WRNOTIFY_SIGNED 0 +/* Register EUR_CR_PIPE1_BREAKPOINT */ #define EUR_CR_PIPE1_BREAKPOINT 0x0F9C #define EUR_CR_PIPE1_BREAKPOINT_MODULE_ID_MASK 0x000003C0U #define EUR_CR_PIPE1_BREAKPOINT_MODULE_ID_SHIFT 6 @@ -1333,10 +1449,12 @@ #define EUR_CR_PIPE1_BREAKPOINT_TRAPPED_MASK 0x00000004U #define EUR_CR_PIPE1_BREAKPOINT_TRAPPED_SHIFT 2 #define EUR_CR_PIPE1_BREAKPOINT_TRAPPED_SIGNED 0 +/* Register EUR_CR_PIPE1_BREAKPOINT_TRAP_INFO0 */ #define EUR_CR_PIPE1_BREAKPOINT_TRAP_INFO0 0x0FA0 #define EUR_CR_PIPE1_BREAKPOINT_TRAP_INFO0_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_PIPE1_BREAKPOINT_TRAP_INFO0_ADDRESS_SHIFT 4 #define EUR_CR_PIPE1_BREAKPOINT_TRAP_INFO0_ADDRESS_SIGNED 0 +/* Register EUR_CR_PIPE1_BREAKPOINT_TRAP_INFO1 */ #define EUR_CR_PIPE1_BREAKPOINT_TRAP_INFO1 0x0FA4 #define EUR_CR_PIPE1_BREAKPOINT_TRAP_INFO1_SIZE_MASK 0x00007C00U #define EUR_CR_PIPE1_BREAKPOINT_TRAP_INFO1_SIZE_SHIFT 10 @@ -1353,6 +1471,8 @@ #define EUR_CR_PIPE1_BREAKPOINT_TRAP_INFO1_RNW_MASK 0x00000001U #define EUR_CR_PIPE1_BREAKPOINT_TRAP_INFO1_RNW_SHIFT 0 #define EUR_CR_PIPE1_BREAKPOINT_TRAP_INFO1_RNW_SIGNED 0 +/* Table EUR_CR_USE_CODE_BASE */ +/* Register EUR_CR_USE_CODE_BASE */ #define EUR_CR_USE_CODE_BASE(X) (0x0A0C + (4 * (X))) #define EUR_CR_USE_CODE_BASE_ADDR_MASK 0x03FFFFFFU #define EUR_CR_USE_CODE_BASE_ADDR_SHIFT 0 @@ -1360,8 +1480,9 @@ #define EUR_CR_USE_CODE_BASE_DM_MASK 0x0C000000U #define EUR_CR_USE_CODE_BASE_DM_SHIFT 26 #define EUR_CR_USE_CODE_BASE_DM_SIGNED 0 +/* Number of entries in table EUR_CR_USE_CODE_BASE */ #define EUR_CR_USE_CODE_BASE_SIZE_UINT32 16 #define EUR_CR_USE_CODE_BASE_NUM_ENTRIES 16 -#endif +#endif /* _SGX544DEFS_KM_H_ */ diff --git a/sgx/services4/srvkm/hwdefs/sgxdefs.h b/sgx/services4/srvkm/hwdefs/sgxdefs.h index b3a2583..dee7bce 100644 --- a/sgx/services4/srvkm/hwdefs/sgxdefs.h +++ b/sgx/services4/srvkm/hwdefs/sgxdefs.h @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title SGX hw definitions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #ifndef _SGXDEFS_H_ #define _SGXDEFS_H_ @@ -79,12 +95,19 @@ #include "sgxmpplusdefs.h" #else #include "sgxmpdefs.h" -#endif -#else +#endif /* SGX554 */ +#else /* SGX_FEATURE_MP */ #if defined(SGX_FEATURE_SYSTEM_CACHE) #include "mnemedefs.h" #endif -#endif +#endif /* SGX_FEATURE_MP */ + +/***************************************************************************** + Core specific defines. +*****************************************************************************/ -#endif +#endif /* _SGXDEFS_H_ */ +/***************************************************************************** + End of file (sgxdefs.h) +*****************************************************************************/ diff --git a/sgx/services4/srvkm/hwdefs/sgxerrata.h b/sgx/services4/srvkm/hwdefs/sgxerrata.h index ccfafd5..36d8b30 100644 --- a/sgx/services4/srvkm/hwdefs/sgxerrata.h +++ b/sgx/services4/srvkm/hwdefs/sgxerrata.h @@ -1,215 +1,200 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title SGX HW errata definitions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Specifies associations between SGX core revisions + and SW workarounds required to fix HW errata that exist + in specific core revisions +@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. + +*/ /**************************************************************************/ #ifndef _SGXERRATA_KM_H_ #define _SGXERRATA_KM_H_ +/* ignore warnings about unrecognised preprocessing directives in conditional inclusion directives */ +/* PRQA S 3115 ++ */ + #if defined(SGX520) && !defined(SGX_CORE_DEFINED) - + /* define the _current_ SGX520 RTL head revision */ #define SGX_CORE_REV_HEAD 0 #if defined(USE_SGX_CORE_REV_HEAD) - + /* build config selects Core Revision to be the Head */ #define SGX_CORE_REV SGX_CORE_REV_HEAD #endif - #if SGX_CORE_REV == 100 - #define FIX_HW_BRN_28889 - #else #if SGX_CORE_REV == 111 - #define FIX_HW_BRN_28889 #else #if SGX_CORE_REV == SGX_CORE_REV_HEAD - + /* RTL head - no BRNs to apply */ #else #error "sgxerrata.h: SGX520 Core Revision unspecified" #endif #endif - #endif - + /* signal that the Core Version has a valid definition */ #define SGX_CORE_DEFINED #endif #if defined(SGX530) && !defined(SGX_CORE_DEFINED) - + /* define the _current_ SGX530 RTL head revision */ #define SGX_CORE_REV_HEAD 0 #if defined(USE_SGX_CORE_REV_HEAD) - + /* build config selects Core Revision to be the Head */ #define SGX_CORE_REV SGX_CORE_REV_HEAD #endif - #if SGX_CORE_REV == 110 - #define FIX_HW_BRN_22934 - #define FIX_HW_BRN_28889 - #else - #if SGX_CORE_REV == 111 - #define FIX_HW_BRN_22934 - #define FIX_HW_BRN_28889 - #else - #if SGX_CORE_REV == 1111 - #define FIX_HW_BRN_22934 - #define FIX_HW_BRN_28889 - #else #if SGX_CORE_REV == 120 - #define FIX_HW_BRN_22934 - #define FIX_HW_BRN_28889 + #define FIX_HW_BRN_22934/* Workaround in sgx featuredefs */ + #define FIX_HW_BRN_28889/* Workaround in services (srvkm) */ #else #if SGX_CORE_REV == 121 - #define FIX_HW_BRN_22934 - #define FIX_HW_BRN_28889 + #define FIX_HW_BRN_22934/* Workaround in sgx featuredefs */ + #define FIX_HW_BRN_28889/* Workaround in services (srvkm) */ #else #if SGX_CORE_REV == 125 - #define FIX_HW_BRN_22934 - #define FIX_HW_BRN_28889 + #define FIX_HW_BRN_22934/* Workaround in sgx featuredefs */ + #define FIX_HW_BRN_28889/* Workaround in services (srvkm) */ #else #if SGX_CORE_REV == 130 - #define FIX_HW_BRN_22934 - #define FIX_HW_BRN_28889 + #define FIX_HW_BRN_22934/* Workaround in sgx featuredefs */ + #define FIX_HW_BRN_28889/* Workaround in services (srvkm) */ #else #if SGX_CORE_REV == SGX_CORE_REV_HEAD - + /* RTL head - no BRNs to apply */ #else #error "sgxerrata.h: SGX530 Core Revision unspecified" #endif #endif #endif - #endif - #endif - #endif #endif #endif - + /* signal that the Core Version has a valid definition */ #define SGX_CORE_DEFINED #endif #if defined(SGX531) && !defined(SGX_CORE_DEFINED) - + /* define the _current_ SGX531 RTL head revision */ #define SGX_CORE_REV_HEAD 0 #if defined(USE_SGX_CORE_REV_HEAD) - + /* build config selects Core Revision to be the Head */ #define SGX_CORE_REV SGX_CORE_REV_HEAD #endif #if SGX_CORE_REV == 101 - #define FIX_HW_BRN_26620 - #define FIX_HW_BRN_28011 - #define FIX_HW_BRN_34028 + #define FIX_HW_BRN_26620/* Workaround in services (srvkm) */ + #define FIX_HW_BRN_28011/* Workaround in services (srvkm) */ + #define FIX_HW_BRN_34028/* Workaround in services (srvkm) */ #else #if SGX_CORE_REV == 110 - #define FIX_HW_BRN_34028 + #define FIX_HW_BRN_34028/* Workaround in services (srvkm) */ #else #if SGX_CORE_REV == SGX_CORE_REV_HEAD - + /* RTL head - no BRNs to apply */ #else #error "sgxerrata.h: SGX531 Core Revision unspecified" #endif #endif #endif - + /* signal that the Core Version has a valid definition */ #define SGX_CORE_DEFINED #endif #if (defined(SGX535) || defined(SGX535_V1_1)) && !defined(SGX_CORE_DEFINED) - + /* define the _current_ SGX535 RTL head revision */ #define SGX_CORE_REV_HEAD 0 #if defined(USE_SGX_CORE_REV_HEAD) - + /* build config selects Core Revision to be the Head */ #define SGX_CORE_REV SGX_CORE_REV_HEAD #endif - #if SGX_CORE_REV == 112 - #define FIX_HW_BRN_23281 - #define FIX_HW_BRN_23410 - #define FIX_HW_BRN_22693 - #define FIX_HW_BRN_22934 - #define FIX_HW_BRN_22997 - #define FIX_HW_BRN_23030 - #else - #if SGX_CORE_REV == 113 - #define FIX_HW_BRN_22934 - #define FIX_HW_BRN_23281 - #define FIX_HW_BRN_23944 - #define FIX_HW_BRN_23410 - #else #if SGX_CORE_REV == 121 - #define FIX_HW_BRN_22934 - #define FIX_HW_BRN_23944 - #define FIX_HW_BRN_23410 + #define FIX_HW_BRN_22934/* Workaround in sgx featuredefs */ + #define FIX_HW_BRN_23944/* Workaround in code (services) */ + #define FIX_HW_BRN_23410/* Workaround in code (services) and ucode */ #else #if SGX_CORE_REV == 126 - #define FIX_HW_BRN_22934 + #define FIX_HW_BRN_22934/* Workaround in sgx featuredefs */ #else #if SGX_CORE_REV == SGX_CORE_REV_HEAD - + /* RTL head - no BRNs to apply */ #else #error "sgxerrata.h: SGX535 Core Revision unspecified" #endif #endif #endif - #endif - #endif - + /* signal that the Core Version has a valid definition */ #define SGX_CORE_DEFINED #endif #if defined(SGX540) && !defined(SGX_CORE_DEFINED) - + /* define the _current_ SGX540 RTL head revision */ #define SGX_CORE_REV_HEAD 0 #if defined(USE_SGX_CORE_REV_HEAD) - + /* build config selects Core Revision to be the Head */ #define SGX_CORE_REV SGX_CORE_REV_HEAD #endif #if SGX_CORE_REV == 101 - #define FIX_HW_BRN_25499 - #define FIX_HW_BRN_25503 - #define FIX_HW_BRN_26620 - #define FIX_HW_BRN_28011 - #define FIX_HW_BRN_34028 + #define FIX_HW_BRN_25499/* Workaround in sgx featuredefs */ + #define FIX_HW_BRN_25503/* Workaround in code (services) */ + #define FIX_HW_BRN_26620/* Workaround in services (srvkm) */ + #define FIX_HW_BRN_28011/* Workaround in services (srvkm) */ + #define FIX_HW_BRN_34028/* Workaround in services (srvkm) */ #else #if SGX_CORE_REV == 110 - #define FIX_HW_BRN_25503 - #define FIX_HW_BRN_26620 - #define FIX_HW_BRN_28011 - #define FIX_HW_BRN_34028 + #define FIX_HW_BRN_25503/* Workaround in code (services) */ + #define FIX_HW_BRN_26620/* Workaround in services (srvkm) */ + #define FIX_HW_BRN_28011/* Workaround in services (srvkm) */ + #define FIX_HW_BRN_34028/* Workaround in services (srvkm) */ #else #if SGX_CORE_REV == 120 - #define FIX_HW_BRN_26620 - #define FIX_HW_BRN_28011 - #define FIX_HW_BRN_34028 + #define FIX_HW_BRN_26620/* Workaround in services (srvkm) */ + #define FIX_HW_BRN_28011/* Workaround in services (srvkm) */ + #define FIX_HW_BRN_34028/* Workaround in services (srvkm) */ #else #if SGX_CORE_REV == 121 - #define FIX_HW_BRN_28011 - #define FIX_HW_BRN_34028 + #define FIX_HW_BRN_28011/* Workaround in services (srvkm) */ + #define FIX_HW_BRN_34028/* Workaround in services (srvkm) */ #else #if SGX_CORE_REV == 130 - #define FIX_HW_BRN_34028 + #define FIX_HW_BRN_34028/* Workaround in services (srvkm) */ #else #if SGX_CORE_REV == SGX_CORE_REV_HEAD - + /* RTL head - no BRNs to apply */ #else #error "sgxerrata.h: SGX540 Core Revision unspecified" #endif @@ -218,243 +203,145 @@ #endif #endif #endif - + /* signal that the Core Version has a valid definition */ #define SGX_CORE_DEFINED #endif -#if defined(SGX541) && !defined(SGX_CORE_DEFINED) - #if defined(SGX_FEATURE_MP) - - #define SGX_CORE_REV_HEAD 0 - #if defined(USE_SGX_CORE_REV_HEAD) - - #define SGX_CORE_REV SGX_CORE_REV_HEAD - #endif - - #if SGX_CORE_REV == 100 - #define FIX_HW_BRN_27270 - #define FIX_HW_BRN_28011 - #define FIX_HW_BRN_27510 - - #else - #if SGX_CORE_REV == SGX_CORE_REV_HEAD - - #else - #error "sgxerrata.h: SGX541 Core Revision unspecified" - #endif - #endif - - #define SGX_CORE_DEFINED - #else - #error "sgxerrata.h: SGX541 only supports MP configs (SGX_FEATURE_MP)" - #endif -#endif #if defined(SGX543) && !defined(SGX_CORE_DEFINED) - + /* define the _current_ SGX543 RTL head revision */ #define SGX_CORE_REV_HEAD 0 #if defined(USE_SGX_CORE_REV_HEAD) - + /* build config selects Core Revision to be the Head */ #define SGX_CORE_REV SGX_CORE_REV_HEAD #endif - #if SGX_CORE_REV == 113 - #define FIX_HW_BRN_29954 - #define FIX_HW_BRN_29997 - #define FIX_HW_BRN_30954 - #define FIX_HW_BRN_31093 - #define FIX_HW_BRN_31195 - #define FIX_HW_BRN_31272 - #define FIX_HW_BRN_31278 - #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 - #endif - #define FIX_HW_BRN_31620 - #define FIX_HW_BRN_31780 - #define FIX_HW_BRN_31542 - #define FIX_HW_BRN_32044 - #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 - #endif - #define FIX_HW_BRN_33920 - #else #if SGX_CORE_REV == 122 - #define FIX_HW_BRN_29954 - #define FIX_HW_BRN_29997 - #define FIX_HW_BRN_30954 - #define FIX_HW_BRN_31093 - #define FIX_HW_BRN_31195 - #define FIX_HW_BRN_31272 - #define FIX_HW_BRN_31278 + #define FIX_HW_BRN_29954/* turns off regbank split feature */ + #define FIX_HW_BRN_29997/* workaround in services */ + #define FIX_HW_BRN_30954/* workaround in services */ + #define FIX_HW_BRN_31093/* workaround in services */ + #define FIX_HW_BRN_31195/* workaround in services */ + #define FIX_HW_BRN_31272/* workaround in services (srvclient) and uKernel */ + #define FIX_HW_BRN_31278/* disabled prefetching in MMU */ #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 + #define FIX_HW_BRN_31559/* workaround in services and uKernel */ #endif - #define FIX_HW_BRN_31620 - #define FIX_HW_BRN_31780 - #define FIX_HW_BRN_31542 - #define FIX_HW_BRN_32044 - #define FIX_HW_BRN_32085 + #define FIX_HW_BRN_31620/* workaround in services */ + #define FIX_HW_BRN_31780/* workaround in uKernel */ + #define FIX_HW_BRN_31542/* workaround in uKernel and Services */ + #define FIX_HW_BRN_32044 /* workaround in uKernel, services and client drivers */ + #define FIX_HW_BRN_32085 /* workaround in services: prefetch fix applied, investigating PT based fix */ #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif - #define FIX_HW_BRN_33920 - + #define FIX_HW_BRN_33920/* workaround in ukernel */ + #define FIX_HW_BRN_36513 /* workaround in uKernel and Services */ + /* add BRNs here */ #else #if SGX_CORE_REV == 1221 - #define FIX_HW_BRN_29954 - #define FIX_HW_BRN_31195 - #define FIX_HW_BRN_31272 - #define FIX_HW_BRN_31278 - #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 - #endif - #define FIX_HW_BRN_31542 - #define FIX_HW_BRN_31671 - #define FIX_HW_BRN_31780 - #define FIX_HW_BRN_32044 - #define FIX_HW_BRN_32085 - #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 - #endif - #define FIX_HW_BRN_33920 - - #else - #if SGX_CORE_REV == 140 - #define FIX_HW_BRN_29954 - #define FIX_HW_BRN_30954 - #define FIX_HW_BRN_31093 - #define FIX_HW_BRN_31195 - #define FIX_HW_BRN_31272 - #define FIX_HW_BRN_31278 - #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 - #endif - #define FIX_HW_BRN_31620 - #define FIX_HW_BRN_31780 - #define FIX_HW_BRN_31542 - #define FIX_HW_BRN_32044 - #define FIX_HW_BRN_32085 - #define FIX_HW_BRN_33920 - #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 - #endif - - #else - #if SGX_CORE_REV == 1401 - #define FIX_HW_BRN_29954 - #define FIX_HW_BRN_30954 - #define FIX_HW_BRN_31195 - #define FIX_HW_BRN_31272 - #define FIX_HW_BRN_31278 + #define FIX_HW_BRN_29954/* turns off regbank split feature */ + #define FIX_HW_BRN_31195/* workaround in services */ + #define FIX_HW_BRN_31272/* workaround in services (srvclient) and uKernel */ + #define FIX_HW_BRN_31278/* disabled prefetching in MMU */ #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 + #define FIX_HW_BRN_31559/* workaround in services and uKernel */ #endif - #define FIX_HW_BRN_31620 - #define FIX_HW_BRN_31542 - #define FIX_HW_BRN_31780 - #define FIX_HW_BRN_32044 - #define FIX_HW_BRN_32085 - #define FIX_HW_BRN_33920 + #define FIX_HW_BRN_31542/* workaround in uKernel and Services */ + #define FIX_HW_BRN_31671/* workaround in uKernel */ + #define FIX_HW_BRN_31780/* workaround in uKernel */ + #define FIX_HW_BRN_32044/* workaround in uKernel, services and client drivers */ + #define FIX_HW_BRN_32085 /* workaround in services: prefetch fix applied, investigating PT based fix */ #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif - + #define FIX_HW_BRN_33920/* workaround in ukernel */ + #define FIX_HW_BRN_36513 /* workaround in uKernel and Services */ + /* add BRNs here */ #else #if SGX_CORE_REV == 141 - #define FIX_HW_BRN_29954 + #define FIX_HW_BRN_29954/* turns off regbank split feature */ #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 + #define FIX_HW_BRN_31559/* workaround in services and uKernel */ #endif - #define FIX_HW_BRN_31671 - #define FIX_HW_BRN_31780 + #define FIX_HW_BRN_31671 /* workaround in uKernel */ + #define FIX_HW_BRN_31780/* workaround in uKernel */ #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif - + #define FIX_HW_BRN_36513 /* workaround in uKernel and Services */ + /* add BRNs here */ #else #if SGX_CORE_REV == 142 - #define FIX_HW_BRN_29954 + #define FIX_HW_BRN_29954/* turns off regbank split feature */ #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 + #define FIX_HW_BRN_31559/* workaround in services and uKernel */ #endif - #define FIX_HW_BRN_31671 - #define FIX_HW_BRN_31780 + #define FIX_HW_BRN_31671 /* workaround in uKernel */ + #define FIX_HW_BRN_31780/* workaround in uKernel */ #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif - - #else - #if SGX_CORE_REV == 211 - #define FIX_HW_BRN_31093 - #define FIX_HW_BRN_31195 - #define FIX_HW_BRN_31272 - #define FIX_HW_BRN_31278 - #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 - #endif - #define FIX_HW_BRN_31620 - #define FIX_HW_BRN_31780 - #define FIX_HW_BRN_31542 - #define FIX_HW_BRN_32044 - #define FIX_HW_BRN_32085 - #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 - #endif - #define FIX_HW_BRN_33920 - + #define FIX_HW_BRN_36513 /* workaround in uKernel and Services */ + /* add BRNs here */ #else #if SGX_CORE_REV == 2111 - #define FIX_HW_BRN_30982 - #define FIX_HW_BRN_31093 - #define FIX_HW_BRN_31195 - #define FIX_HW_BRN_31272 - #define FIX_HW_BRN_31278 + #define FIX_HW_BRN_30982 /* workaround in uKernel and services */ + #define FIX_HW_BRN_31093/* workaround in services */ + #define FIX_HW_BRN_31195/* workaround in services */ + #define FIX_HW_BRN_31272/* workaround in services (srvclient) and uKernel */ + #define FIX_HW_BRN_31278/* disabled prefetching in MMU */ #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 + #define FIX_HW_BRN_31559/* workaround in services and uKernel */ #endif - #define FIX_HW_BRN_31620 - #define FIX_HW_BRN_31780 - #define FIX_HW_BRN_31542 - #define FIX_HW_BRN_32044 - #define FIX_HW_BRN_32085 + #define FIX_HW_BRN_31620/* workaround in services */ + #define FIX_HW_BRN_31780/* workaround in uKernel */ + #define FIX_HW_BRN_31542/* workaround in uKernel and Services */ + #define FIX_HW_BRN_32044 /* workaround in uKernel, services and client drivers */ + #define FIX_HW_BRN_32085 /* workaround in services: prefetch fix applied, investigating PT based fix */ #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif - #define FIX_HW_BRN_33920 - + #define FIX_HW_BRN_33920/* workaround in ukernel */ + #define FIX_HW_BRN_36513 /* workaround in uKernel and Services */ + /* add BRNs here */ #else #if SGX_CORE_REV == 213 - #define FIX_HW_BRN_31272 - #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 + #define FIX_HW_BRN_31272/* workaround in services (srvclient) and uKernel */ + #if defined(SGX_FEATURE_MP) + #define FIX_HW_BRN_31559/* workaround in services and uKernel */ #endif - #define FIX_HW_BRN_31671 - #define FIX_HW_BRN_31780 - #define FIX_HW_BRN_32085 + #define FIX_HW_BRN_31671 /* workaround in uKernel */ + #define FIX_HW_BRN_31780/* workaround in uKernel */ + #define FIX_HW_BRN_32085 /* workaround in services: prefetch fix applied, investigating PT based fix */ #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif - #define FIX_HW_BRN_33920 - + #define FIX_HW_BRN_33920/* workaround in ukernel */ + #define FIX_HW_BRN_36513 /* workaround in uKernel and Services */ + /* add BRNs here */ #else #if SGX_CORE_REV == 216 #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif + #define FIX_HW_BRN_36513 /* workaround in uKernel and Services */ #else #if SGX_CORE_REV == 302 #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif +// FIXME #define FIX_HW_BRN_36513 /* workaround in uKernel and Services : incomplete for CS and MP1 */ #else #if SGX_CORE_REV == 303 #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif +// FIXME #define FIX_HW_BRN_36513 /* workaround in uKernel and Services : incomplete for CS and MP1 */ #else #if SGX_CORE_REV == SGX_CORE_REV_HEAD #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif #else #error "sgxerrata.h: SGX543 Core Revision unspecified" @@ -468,124 +355,84 @@ #endif #endif #endif - #endif - #endif - #endif - #endif - + /* signal that the Core Version has a valid definition */ #define SGX_CORE_DEFINED #endif #if defined(SGX544) && !defined(SGX_CORE_DEFINED) - + /* define the _current_ SGX544 RTL head revision */ #define SGX_CORE_REV_HEAD 0 #if defined(USE_SGX_CORE_REV_HEAD) - + /* build config selects Core Revision to be the Head */ #define SGX_CORE_REV SGX_CORE_REV_HEAD #endif - #if SGX_CORE_REV == 100 - #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 - #endif - #else - #if SGX_CORE_REV == 102 - #define FIX_HW_BRN_29954 - #define FIX_HW_BRN_31272 - #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 - #endif - #define FIX_HW_BRN_31780 - #define FIX_HW_BRN_32085 - #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 - #endif - #define FIX_HW_BRN_33920 - #else - #if SGX_CORE_REV == 103 - #define FIX_HW_BRN_29954 - #define FIX_HW_BRN_31272 - #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 - #endif - #define FIX_HW_BRN_31780 - #define FIX_HW_BRN_32085 - #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 - #endif - #define FIX_HW_BRN_33920 - #else #if SGX_CORE_REV == 104 - #define FIX_HW_BRN_29954 - #define FIX_HW_BRN_31093 - #define FIX_HW_BRN_31195 - #define FIX_HW_BRN_31272 - #define FIX_HW_BRN_31278 + #define FIX_HW_BRN_29954/* turns off regbank split feature */ + #define FIX_HW_BRN_31093/* workaround in services */ + #define FIX_HW_BRN_31195/* workaround in services */ + #define FIX_HW_BRN_31272/* workaround in services (srvclient) and uKernel */ + #define FIX_HW_BRN_31278/* disabled prefetching in MMU */ #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 + #define FIX_HW_BRN_31559/* workaround in services and uKernel */ #endif - #define FIX_HW_BRN_31542 - #define FIX_HW_BRN_31620 - #define FIX_HW_BRN_31671 - #define FIX_HW_BRN_31780 - #define FIX_HW_BRN_32044 - #define FIX_HW_BRN_32085 + #define FIX_HW_BRN_31542 /* workaround in uKernel and Services */ + #define FIX_HW_BRN_31620/* workaround in services */ + #define FIX_HW_BRN_31671 /* workaround in uKernel */ + #define FIX_HW_BRN_31780/* workaround in uKernel */ + #define FIX_HW_BRN_32044 /* workaround in uKernel, services and client drivers */ + #define FIX_HW_BRN_32085 /* workaround in services: prefetch fix applied, investigating PT based fix */ #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif - #define FIX_HW_BRN_33920 + #define FIX_HW_BRN_33920/* workaround in ukernel */ + #define FIX_HW_BRN_36513 /* workaround in uKernel and Services */ #else #if SGX_CORE_REV == 105 #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 + #define FIX_HW_BRN_31559/* workaround in services and uKernel */ #endif - #define FIX_HW_BRN_31780 + #define FIX_HW_BRN_31780/* workaround in uKernel */ #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif - #define FIX_HW_BRN_33920 - #else - #if SGX_CORE_REV == 106 - #define FIX_HW_BRN_31272 - #define FIX_HW_BRN_31780 - #define FIX_HW_BRN_33920 - #else - #if SGX_CORE_REV == 110 - #define FIX_HW_BRN_31272 - #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 - #endif - #define FIX_HW_BRN_31780 - #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 - #endif - #define FIX_HW_BRN_33920 + #define FIX_HW_BRN_33920/* workaround in ukernel */ + #define FIX_HW_BRN_36513 /* workaround in uKernel and Services */ #else #if SGX_CORE_REV == 112 - #define FIX_HW_BRN_31272 - #define FIX_HW_BRN_33920 + #define FIX_HW_BRN_31272/* workaround in services (srvclient) and uKernel */ + #define FIX_HW_BRN_33920/* workaround in ukernel */ +// FIXME #define FIX_HW_BRN_36513 /* workaround in uKernel and Services : incomplete for CS and MP1 */ #else #if SGX_CORE_REV == 114 - #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 - #endif - #define FIX_HW_BRN_31780 + #define FIX_HW_BRN_31780/* workaround in uKernel */ #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif +// FIXME #define FIX_HW_BRN_36513 /* workaround in uKernel and Services : incomplete for CS and MP1 */ #else #if SGX_CORE_REV == 115 - #if defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_31425 - #endif - #define FIX_HW_BRN_31780 + #define FIX_HW_BRN_31780/* workaround in uKernel */ + #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) + #define FIX_HW_BRN_33657/* workaround in ukernel*/ + #endif +// FIXME BRN_36513 incomplete for CS and MP1 */ + #if defined(SGX_FEATURE_MP) + #if SGX_FEATURE_MP_CORE_COUNT > 1 + #define FIX_HW_BRN_36513 /* workaround in uKernel and Services : incomplete for CS and MP1 */ + #endif + #endif + #else + #if SGX_CORE_REV == 116 #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel */ #endif + #define FIX_HW_BRN_33809/* workaround in kernel (enable burst combiner) */ + #define FIX_HW_BRN_36513 /* workaround in uKernel and Services */ #else #if SGX_CORE_REV == SGX_CORE_REV_HEAD #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif #else #error "sgxerrata.h: SGX544 Core Revision unspecified" @@ -596,39 +443,22 @@ #endif #endif #endif - #endif - #endif - #endif - #endif - + /* signal that the Core Version has a valid definition */ #define SGX_CORE_DEFINED #endif #if defined(SGX545) && !defined(SGX_CORE_DEFINED) - + /* define the _current_ SGX545 RTL head revision */ #define SGX_CORE_REV_HEAD 0 #if defined(USE_SGX_CORE_REV_HEAD) - + /* build config selects Core Revision to be the Head */ #define SGX_CORE_REV SGX_CORE_REV_HEAD #endif - #if SGX_CORE_REV == 100 - #define FIX_HW_BRN_26620 - #define FIX_HW_BRN_27266 - #define FIX_HW_BRN_27456 - #define FIX_HW_BRN_29702 - #define FIX_HW_BRN_29823 - #else #if SGX_CORE_REV == 109 - #define FIX_HW_BRN_29702 - #define FIX_HW_BRN_29823 - #define FIX_HW_BRN_31939 - #else - #if SGX_CORE_REV == 1012 - #define FIX_HW_BRN_31939 - #else - #if SGX_CORE_REV == 1013 - #define FIX_HW_BRN_31939 + #define FIX_HW_BRN_29702/* Workaround in services */ + #define FIX_HW_BRN_29823/* Workaround in services */ + #define FIX_HW_BRN_31939/* workaround in uKernel */ #else #if SGX_CORE_REV == 10131 #else @@ -637,7 +467,7 @@ #if SGX_CORE_REV == 10141 #else #if SGX_CORE_REV == SGX_CORE_REV_HEAD - + /* RTL head - no BRNs to apply */ #else #error "sgxerrata.h: SGX545 Core Revision unspecified" #endif @@ -645,36 +475,34 @@ #endif #endif #endif - #endif - #endif - #endif - + /* signal that the Core Version has a valid definition */ #define SGX_CORE_DEFINED #endif #if defined(SGX554) && !defined(SGX_CORE_DEFINED) - + /* define the _current_ SGX554 RTL head revision */ #define SGX_CORE_REV_HEAD 0 #if defined(USE_SGX_CORE_REV_HEAD) - + /* build config selects Core Revision to be the Head */ #define SGX_CORE_REV SGX_CORE_REV_HEAD #endif #if SGX_CORE_REV == 1251 #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif - + #define FIX_HW_BRN_36513 /* workaround in uKernel and Services */ + /* add BRNs here */ #else #if SGX_CORE_REV == SGX_CORE_REV_HEAD #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && defined(SGX_FEATURE_MP) - #define FIX_HW_BRN_33657 + #define FIX_HW_BRN_33657/* workaround in ukernel*/ #endif #else #error "sgxerrata.h: SGX554 Core Revision unspecified" #endif #endif - + /* signal that the Core Version has a valid definition */ #define SGX_CORE_DEFINED #endif @@ -686,5 +514,11 @@ #endif #endif -#endif +/* restore warning */ +/* PRQA S 3115 -- */ + +#endif /* _SGXERRATA_KM_H_ */ +/****************************************************************************** + End of file (sgxerrata.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/hwdefs/sgxfeaturedefs.h b/sgx/services4/srvkm/hwdefs/sgxfeaturedefs.h index 6427e7e..cefa154 100644 --- a/sgx/services4/srvkm/hwdefs/sgxfeaturedefs.h +++ b/sgx/services4/srvkm/hwdefs/sgxfeaturedefs.h @@ -1,29 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title SGX fexture definitions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #if defined(SGX520) #define SGX_CORE_FRIENDLY_NAME "SGX520" #define SGX_CORE_ID SGX_CORE_ID_520 @@ -105,13 +120,18 @@ #define SGX_FEATURE_AUTOCLOCKGATING #define SGX_FEATURE_MONOLITHIC_UKERNEL #define SGX_FEATURE_MULTI_EVENT_KICK +// #define SGX_FEATURE_DATA_BREAKPOINTS +// #define SGX_FEATURE_PERPIPE_BKPT_REGS +// #define SGX_FEATURE_PERPIPE_BKPT_REGS_NUMPIPES (2) +// #define SGX_FEATURE_2D_HARDWARE +// #define SGX_FEATURE_PTLA #define SGX_FEATURE_EXTENDED_PERF_COUNTERS #define SGX_FEATURE_EDM_VERTEX_PDSADDR_FULL_RANGE #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) #if defined(SGX_FEATURE_MP) #define SGX_FEATURE_MASTER_VDM_CONTEXT_SWITCH - #endif #define SGX_FEATURE_SLAVE_VDM_CONTEXT_SWITCH + #endif #define SGX_FEATURE_SW_ISP_CONTEXT_SWITCH #endif #else @@ -136,8 +156,8 @@ #define SGX_FEATURE_MAX_TA_RENDER_TARGETS (512) #define SGX_FEATURE_SECONDARY_REQUIRES_USE_KICK #define SGX_FEATURE_WRITEBACK_DCU - - + //FIXME: this is defined in the build config for now + //#define SGX_FEATURE_36BIT_MMU #define SGX_FEATURE_BIF_WIDE_TILING_AND_4K_ADDRESS #define SGX_FEATURE_MULTI_EVENT_KICK #define SGX_FEATURE_EDM_VERTEX_PDSADDR_FULL_RANGE @@ -157,6 +177,9 @@ #define SGX_FEATURE_AUTOCLOCKGATING #define SGX_FEATURE_MONOLITHIC_UKERNEL #define SGX_FEATURE_MULTI_EVENT_KICK +// #define SGX_FEATURE_DATA_BREAKPOINTS +// #define SGX_FEATURE_PERPIPE_BKPT_REGS +// #define SGX_FEATURE_PERPIPE_BKPT_REGS_NUMPIPES (2) #define SGX_FEATURE_2D_HARDWARE #define SGX_FEATURE_PTLA #define SGX_FEATURE_EXTENDED_PERF_COUNTERS @@ -180,21 +203,18 @@ #if defined(SGX_FEATURE_SLAVE_VDM_CONTEXT_SWITCH) \ || defined(SGX_FEATURE_MASTER_VDM_CONTEXT_SWITCH) +/* Enable the define so common code for HW VDMCS code is compiled */ #define SGX_FEATURE_VDM_CONTEXT_SWITCH #endif -#if defined(FIX_HW_BRN_22693) -#undef SGX_FEATURE_AUTOCLOCKGATING -#endif +/* + 'switch-off' features if defined BRNs affect the feature +*/ #if defined(FIX_HW_BRN_27266) #undef SGX_FEATURE_36BIT_MMU #endif -#if defined(FIX_HW_BRN_27456) -#undef SGX_FEATURE_BIF_WIDE_TILING_AND_4K_ADDRESS -#endif - #if defined(FIX_HW_BRN_22934) \ || defined(FIX_HW_BRN_25499) #undef SGX_FEATURE_MULTI_EVENT_KICK @@ -218,11 +238,16 @@ #undef SGX_FEATURE_BIF_NUM_DIRLISTS #endif +/* + Derive other definitions: +*/ + +/* define default MP core count */ #if defined(SGX_FEATURE_MP) #if defined(SGX_FEATURE_MP_CORE_COUNT_TA) && defined(SGX_FEATURE_MP_CORE_COUNT_3D) #if (SGX_FEATURE_MP_CORE_COUNT_TA > SGX_FEATURE_MP_CORE_COUNT_3D) #error Number of TA cores larger than number of 3D cores not supported in current driver -#endif +#endif /* (SGX_FEATURE_MP_CORE_COUNT_TA > SGX_FEATURE_MP_CORE_COUNT_3D) */ #else #if defined(SGX_FEATURE_MP_CORE_COUNT) #define SGX_FEATURE_MP_CORE_COUNT_TA (SGX_FEATURE_MP_CORE_COUNT) @@ -231,13 +256,13 @@ #error Either SGX_FEATURE_MP_CORE_COUNT or \ both SGX_FEATURE_MP_CORE_COUNT_TA and SGX_FEATURE_MP_CORE_COUNT_3D \ must be defined when SGX_FEATURE_MP is defined -#endif -#endif +#endif /* SGX_FEATURE_MP_CORE_COUNT */ +#endif /* defined(SGX_FEATURE_MP_CORE_COUNT_TA) && defined(SGX_FEATURE_MP_CORE_COUNT_3D) */ #else #define SGX_FEATURE_MP_CORE_COUNT (1) #define SGX_FEATURE_MP_CORE_COUNT_TA (1) #define SGX_FEATURE_MP_CORE_COUNT_3D (1) -#endif +#endif /* SGX_FEATURE_MP */ #if defined(SUPPORT_SGX_LOW_LATENCY_SCHEDULING) && !defined(SUPPORT_SGX_PRIORITY_SCHEDULING) #define SUPPORT_SGX_PRIORITY_SCHEDULING @@ -245,3 +270,6 @@ must be defined when SGX_FEATURE_MP is defined #include "img_types.h" +/****************************************************************************** + End of file (sgxfeaturedefs.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/hwdefs/sgxmmu.h b/sgx/services4/srvkm/hwdefs/sgxmmu.h index 1b265f1..509fa5a 100644 --- a/sgx/services4/srvkm/hwdefs/sgxmmu.h +++ b/sgx/services4/srvkm/hwdefs/sgxmmu.h @@ -1,40 +1,62 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title SGX MMU defines +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Provides SGX MMU declarations and macros +@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. + +*/ /**************************************************************************/ #if !defined(__SGXMMU_KM_H__) #define __SGXMMU_KM_H__ +/* to be implemented */ + +/* SGX MMU maps 4Kb pages */ #define SGX_MMU_PAGE_SHIFT (12) #define SGX_MMU_PAGE_SIZE (1U<<SGX_MMU_PAGE_SHIFT) #define SGX_MMU_PAGE_MASK (SGX_MMU_PAGE_SIZE - 1U) +/* PD details */ #define SGX_MMU_PD_SHIFT (10) #define SGX_MMU_PD_SIZE (1U<<SGX_MMU_PD_SHIFT) #define SGX_MMU_PD_MASK (0xFFC00000U) +/* PD Entry details */ #if defined(SGX_FEATURE_36BIT_MMU) #define SGX_MMU_PDE_ADDR_MASK (0xFFFFFF00U) #define SGX_MMU_PDE_ADDR_ALIGNSHIFT (4) @@ -43,6 +65,7 @@ #define SGX_MMU_PDE_ADDR_ALIGNSHIFT (0) #endif #define SGX_MMU_PDE_VALID (0x00000001U) +/* variable page size control field */ #define SGX_MMU_PDE_PAGE_SIZE_4K (0x00000000U) #define SGX_MMU_PDE_PAGE_SIZE_16K (0x00000002U) #define SGX_MMU_PDE_PAGE_SIZE_64K (0x00000004U) @@ -51,10 +74,12 @@ #define SGX_MMU_PDE_PAGE_SIZE_4M (0x0000000AU) #define SGX_MMU_PDE_PAGE_SIZE_MASK (0x0000000EU) +/* PT details */ #define SGX_MMU_PT_SHIFT (10) #define SGX_MMU_PT_SIZE (1U<<SGX_MMU_PT_SHIFT) #define SGX_MMU_PT_MASK (0x003FF000U) +/* PT Entry details */ #if defined(SGX_FEATURE_36BIT_MMU) #define SGX_MMU_PTE_ADDR_MASK (0xFFFFFF00U) #define SGX_MMU_PTE_ADDR_ALIGNSHIFT (4) @@ -68,5 +93,8 @@ #define SGX_MMU_PTE_CACHECONSISTENT (0x00000008U) #define SGX_MMU_PTE_EDMPROTECT (0x00000010U) -#endif +#endif /* __SGXMMU_KM_H__ */ +/***************************************************************************** + End of file (sgxmmu.h) +*****************************************************************************/ diff --git a/sgx/services4/srvkm/hwdefs/sgxmpdefs.h b/sgx/services4/srvkm/hwdefs/sgxmpdefs.h index e34561a..4186731 100644 --- a/sgx/services4/srvkm/hwdefs/sgxmpdefs.h +++ b/sgx/services4/srvkm/hwdefs/sgxmpdefs.h @@ -1,32 +1,49 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Hardware defs for SGXMP. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@License Dual MIT/GPLv2 -#ifndef _SGXMPDEFS_H_ -#define _SGXMPDEFS_H_ +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. + +*/ /**************************************************************************/ + +#ifndef _SGXMPDEFS_KM_H_ +#define _SGXMPDEFS_KM_H_ + +/* Register EUR_CR_MASTER_BIF_CTRL */ #define EUR_CR_MASTER_BIF_CTRL 0x4C00 #define EUR_CR_MASTER_BIF_CTRL_NOREORDER_MASK 0x00000001U #define EUR_CR_MASTER_BIF_CTRL_NOREORDER_SHIFT 0 @@ -49,6 +66,7 @@ #define EUR_CR_MASTER_BIF_CTRL_MMU_BYPASS_MASTER_DPM_MASK 0x00080000U #define EUR_CR_MASTER_BIF_CTRL_MMU_BYPASS_MASTER_DPM_SHIFT 19 #define EUR_CR_MASTER_BIF_CTRL_MMU_BYPASS_MASTER_DPM_SIGNED 0 +/* Register EUR_CR_MASTER_BIF_CTRL_INVAL */ #define EUR_CR_MASTER_BIF_CTRL_INVAL 0x4C34 #define EUR_CR_MASTER_BIF_CTRL_INVAL_PTE_MASK 0x00000004U #define EUR_CR_MASTER_BIF_CTRL_INVAL_PTE_SHIFT 2 @@ -56,6 +74,7 @@ #define EUR_CR_MASTER_BIF_CTRL_INVAL_ALL_MASK 0x00000008U #define EUR_CR_MASTER_BIF_CTRL_INVAL_ALL_SHIFT 3 #define EUR_CR_MASTER_BIF_CTRL_INVAL_ALL_SIGNED 0 +/* Register EUR_CR_MASTER_BIF_MMU_CTRL */ #define EUR_CR_MASTER_BIF_MMU_CTRL 0x4CD0 #define EUR_CR_MASTER_BIF_MMU_CTRL_PREFETCHING_ON_MASK 0x00000001U #define EUR_CR_MASTER_BIF_MMU_CTRL_PREFETCHING_ON_SHIFT 0 @@ -66,6 +85,7 @@ #define EUR_CR_MASTER_BIF_MMU_CTRL_ENABLE_DC_TLB_MASK 0x00000010U #define EUR_CR_MASTER_BIF_MMU_CTRL_ENABLE_DC_TLB_SHIFT 4 #define EUR_CR_MASTER_BIF_MMU_CTRL_ENABLE_DC_TLB_SIGNED 0 +/* Register EUR_CR_MASTER_SLC_CTRL */ #define EUR_CR_MASTER_SLC_CTRL 0x4D00 #define EUR_CR_MASTER_SLC_CTRL_DISABLE_REORDERING_MASK 0x00800000U #define EUR_CR_MASTER_SLC_CTRL_DISABLE_REORDERING_SHIFT 23 @@ -97,6 +117,7 @@ #define EUR_CR_MASTER_SLC_CTRL_PAUSE_MASK 0x00000100U #define EUR_CR_MASTER_SLC_CTRL_PAUSE_SHIFT 8 #define EUR_CR_MASTER_SLC_CTRL_PAUSE_SIGNED 0 +/* Register EUR_CR_MASTER_SLC_CTRL_BYPASS */ #define EUR_CR_MASTER_SLC_CTRL_BYPASS 0x4D04 #define EUR_CR_MASTER_SLC_CTRL_BYPASS_BYP_CC_N_MASK 0x08000000U #define EUR_CR_MASTER_SLC_CTRL_BYPASS_BYP_CC_N_SHIFT 27 @@ -182,10 +203,12 @@ #define EUR_CR_MASTER_SLC_CTRL_BYPASS_ALL_MASK 0x00000001U #define EUR_CR_MASTER_SLC_CTRL_BYPASS_ALL_SHIFT 0 #define EUR_CR_MASTER_SLC_CTRL_BYPASS_ALL_SIGNED 0 +/* Register EUR_CR_MASTER_SLC_CTRL_USSE_INVAL */ #define EUR_CR_MASTER_SLC_CTRL_USSE_INVAL 0x4D08 #define EUR_CR_MASTER_SLC_CTRL_USSE_INVAL_ADDR_MASK 0xFFFFFFFFU #define EUR_CR_MASTER_SLC_CTRL_USSE_INVAL_ADDR_SHIFT 0 #define EUR_CR_MASTER_SLC_CTRL_USSE_INVAL_ADDR_SIGNED 0 +/* Register EUR_CR_MASTER_SLC_CTRL_INVAL */ #define EUR_CR_MASTER_SLC_CTRL_INVAL 0x4D28 #define EUR_CR_MASTER_SLC_CTRL_INVAL_DM_EVENT_MASK 0x00000008U #define EUR_CR_MASTER_SLC_CTRL_INVAL_DM_EVENT_SHIFT 3 @@ -199,6 +222,7 @@ #define EUR_CR_MASTER_SLC_CTRL_INVAL_ALL_MASK 0x00000001U #define EUR_CR_MASTER_SLC_CTRL_INVAL_ALL_SHIFT 0 #define EUR_CR_MASTER_SLC_CTRL_INVAL_ALL_SIGNED 0 +/* Register EUR_CR_MASTER_SLC_CTRL_FLUSH */ #define EUR_CR_MASTER_SLC_CTRL_FLUSH 0x4D2C #define EUR_CR_MASTER_SLC_CTRL_FLUSH_DM_EVENT_MASK 0x00000080U #define EUR_CR_MASTER_SLC_CTRL_FLUSH_DM_EVENT_SHIFT 7 @@ -212,6 +236,7 @@ #define EUR_CR_MASTER_SLC_CTRL_FLUSH_ALL_MASK 0x00000010U #define EUR_CR_MASTER_SLC_CTRL_FLUSH_ALL_SHIFT 4 #define EUR_CR_MASTER_SLC_CTRL_FLUSH_ALL_SIGNED 0 +/* Register EUR_CR_MASTER_SLC_CTRL_FLUSH_INV */ #define EUR_CR_MASTER_SLC_CTRL_FLUSH_INV 0x4D34 #define EUR_CR_MASTER_SLC_CTRL_FLUSH_INV_DM_EVENT_MASK 0x00000080U #define EUR_CR_MASTER_SLC_CTRL_FLUSH_INV_DM_EVENT_SHIFT 7 @@ -225,10 +250,12 @@ #define EUR_CR_MASTER_SLC_CTRL_FLUSH_INV_ALL_MASK 0x00000010U #define EUR_CR_MASTER_SLC_CTRL_FLUSH_INV_ALL_SHIFT 4 #define EUR_CR_MASTER_SLC_CTRL_FLUSH_INV_ALL_SIGNED 0 +/* Register EUR_CR_MASTER_BREAKPOINT_READ */ #define EUR_CR_MASTER_BREAKPOINT_READ 0x4F18 #define EUR_CR_MASTER_BREAKPOINT_READ_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_MASTER_BREAKPOINT_READ_ADDRESS_SHIFT 4 #define EUR_CR_MASTER_BREAKPOINT_READ_ADDRESS_SIGNED 0 +/* Register EUR_CR_MASTER_BREAKPOINT_TRAP */ #define EUR_CR_MASTER_BREAKPOINT_TRAP 0x4F1C #define EUR_CR_MASTER_BREAKPOINT_TRAP_CONTINUE_MASK 0x00000002U #define EUR_CR_MASTER_BREAKPOINT_TRAP_CONTINUE_SHIFT 1 @@ -236,6 +263,7 @@ #define EUR_CR_MASTER_BREAKPOINT_TRAP_WRNOTIFY_MASK 0x00000001U #define EUR_CR_MASTER_BREAKPOINT_TRAP_WRNOTIFY_SHIFT 0 #define EUR_CR_MASTER_BREAKPOINT_TRAP_WRNOTIFY_SIGNED 0 +/* Register EUR_CR_MASTER_BREAKPOINT */ #define EUR_CR_MASTER_BREAKPOINT 0x4F20 #define EUR_CR_MASTER_BREAKPOINT_ID_MASK 0x00000030U #define EUR_CR_MASTER_BREAKPOINT_ID_SHIFT 4 @@ -246,10 +274,12 @@ #define EUR_CR_MASTER_BREAKPOINT_TRAPPED_MASK 0x00000004U #define EUR_CR_MASTER_BREAKPOINT_TRAPPED_SHIFT 2 #define EUR_CR_MASTER_BREAKPOINT_TRAPPED_SIGNED 0 +/* Register EUR_CR_MASTER_BREAKPOINT_TRAP_INFO0 */ #define EUR_CR_MASTER_BREAKPOINT_TRAP_INFO0 0x4F24 #define EUR_CR_MASTER_BREAKPOINT_TRAP_INFO0_ADDRESS_MASK 0xFFFFFFF0U #define EUR_CR_MASTER_BREAKPOINT_TRAP_INFO0_ADDRESS_SHIFT 4 #define EUR_CR_MASTER_BREAKPOINT_TRAP_INFO0_ADDRESS_SIGNED 0 +/* Register EUR_CR_MASTER_BREAKPOINT_TRAP_INFO1 */ #define EUR_CR_MASTER_BREAKPOINT_TRAP_INFO1 0x4F28 #define EUR_CR_MASTER_BREAKPOINT_TRAP_INFO1_SIZE_MASK 0x00007C00U #define EUR_CR_MASTER_BREAKPOINT_TRAP_INFO1_SIZE_SHIFT 10 @@ -266,10 +296,12 @@ #define EUR_CR_MASTER_BREAKPOINT_TRAP_INFO1_RNW_MASK 0x00000001U #define EUR_CR_MASTER_BREAKPOINT_TRAP_INFO1_RNW_SHIFT 0 #define EUR_CR_MASTER_BREAKPOINT_TRAP_INFO1_RNW_SIGNED 0 +/* Register EUR_CR_MASTER_CORE */ #define EUR_CR_MASTER_CORE 0x4000 #define EUR_CR_MASTER_CORE_ENABLE_MASK 0x00000003U #define EUR_CR_MASTER_CORE_ENABLE_SHIFT 0 #define EUR_CR_MASTER_CORE_ENABLE_SIGNED 0 +/* Register EUR_CR_MASTER_CORE_ID */ #define EUR_CR_MASTER_CORE_ID 0x4010 #define EUR_CR_MASTER_CORE_ID_CONFIG_MULTI_MASK 0x00000001U #define EUR_CR_MASTER_CORE_ID_CONFIG_MULTI_SHIFT 0 @@ -289,6 +321,7 @@ #define EUR_CR_MASTER_CORE_ID_ID_MASK 0xFFFF0000U #define EUR_CR_MASTER_CORE_ID_ID_SHIFT 16 #define EUR_CR_MASTER_CORE_ID_ID_SIGNED 0 +/* Register EUR_CR_MASTER_CORE_REVISION */ #define EUR_CR_MASTER_CORE_REVISION 0x4014 #define EUR_CR_MASTER_CORE_REVISION_MAINTENANCE_MASK 0x000000FFU #define EUR_CR_MASTER_CORE_REVISION_MAINTENANCE_SHIFT 0 @@ -302,6 +335,7 @@ #define EUR_CR_MASTER_CORE_REVISION_DESIGNER_MASK 0xFF000000U #define EUR_CR_MASTER_CORE_REVISION_DESIGNER_SHIFT 24 #define EUR_CR_MASTER_CORE_REVISION_DESIGNER_SIGNED 0 +/* Register EUR_CR_MASTER_SOFT_RESET */ #define EUR_CR_MASTER_SOFT_RESET 0x4080 #define EUR_CR_MASTER_SOFT_RESET_CORE_RESET_MASK(i) (0x00000001U << (0 + ((i) * 1))) #define EUR_CR_MASTER_SOFT_RESET_CORE_RESET_SHIFT(i) (0 + ((i) * 1)) @@ -328,5 +362,5 @@ #define EUR_CR_MASTER_SOFT_RESET_PTLA_RESET_SHIFT 10 #define EUR_CR_MASTER_SOFT_RESET_PTLA_RESET_SIGNED 0 -#endif +#endif /* _SGXMPDEFS_KM_H_ */ diff --git a/sgx/services4/srvkm/include/buffer_manager.h b/sgx/services4/srvkm/include/buffer_manager.h index 46f5a68..b7440a0 100644 --- a/sgx/services4/srvkm/include/buffer_manager.h +++ b/sgx/services4/srvkm/include/buffer_manager.h @@ -1,28 +1,46 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Buffer Management. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Manages buffers mapped into two virtual memory spaces, host and + device and referenced by handles. +@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. + +*/ /**************************************************************************/ #ifndef _BUFFER_MANAGER_H_ #define _BUFFER_MANAGER_H_ @@ -35,28 +53,37 @@ extern "C"{ #endif +/* forward reference */ typedef struct _BM_HEAP_ BM_HEAP; +/* + * The mapping structure is used to record relations between CPU virtual, + * CPU physical and device virtual addresses for large chunks of memory + * from which we have resource-allocator draw our buffers. + * + * There is one per contiguous pool and one per import from the host OS. + */ struct _BM_MAPPING_ { enum { - hm_wrapped = 1, - hm_wrapped_scatter, - hm_wrapped_virtaddr, - hm_wrapped_scatter_virtaddr, - hm_env, - hm_contiguous + hm_wrapped = 1, /*!< wrapped user supplied contiguous*/ + hm_wrapped_scatter, /*!< wrapped user supplied scattered */ + hm_wrapped_virtaddr, /*!< wrapped user supplied contiguous with virtual address*/ + hm_wrapped_scatter_virtaddr, /*!< wrapped user supplied scattered with virtual address*/ + hm_env, /*!< obtained from environment */ + hm_contiguous /*!< contigous arena */ } eCpuMemoryOrigin; - BM_HEAP *pBMHeap; - RA_ARENA *pArena; + BM_HEAP *pBMHeap; /* which BM heap */ + RA_ARENA *pArena; /* whence the memory comes */ IMG_CPU_VIRTADDR CpuVAddr; IMG_CPU_PHYADDR CpuPAddr; IMG_DEV_VIRTADDR DevVAddr; IMG_SYS_PHYADDR *psSysAddr; IMG_SIZE_T uSize; + IMG_SIZE_T uSizeVM; IMG_HANDLE hOSMemHandle; IMG_UINT32 ui32Flags; @@ -70,8 +97,20 @@ struct _BM_MAPPING_ * is remapped with the original alignment restrictions. */ IMG_UINT32 ui32DevVAddrAlignment; + + /* Sparse mapping data */ + IMG_UINT32 ui32ChunkSize; + IMG_UINT32 ui32NumVirtChunks; + IMG_UINT32 ui32NumPhysChunks; + IMG_BOOL *pabMapChunk; }; +/* + * The buffer structure handles individual allocations from the user; thus + * there is one allocated per call to BM_Alloc and one per call to BM_Wrap. + * We record a mapping reference so we know where to return allocated + * resources at BM_Free time. + */ typedef struct _BM_BUF_ { IMG_CPU_VIRTADDR *CpuVAddr; @@ -97,45 +136,101 @@ struct _BM_HEAP_ struct _BM_HEAP_ *psNext; struct _BM_HEAP_ **ppsThis; + /* BIF tile stride for this heap */ + IMG_UINT32 ui32XTileStride; }; +/* + * The bm-context structure + */ struct _BM_CONTEXT_ { MMU_CONTEXT *psMMUContext; - + /* + * Resource allocation arena of dual mapped pages. For devices + * where the hardware imposes different constraints on the valid + * device virtual address range depending on the use of the buffer + * we maintain two allocation arenas, one low address range, the + * other high. For devices without such a constrain we do not + * create the high arena, instead all allocations come from the + * low arena. + */ BM_HEAP *psBMHeap; - + /* + * The Shared Heaps + */ BM_HEAP *psBMSharedHeap; PVRSRV_DEVICE_NODE *psDeviceNode; - + /* + * Hash table management. + */ HASH_TABLE *pBufferHash; - + /* + * Resman item handle + */ IMG_HANDLE hResItem; IMG_UINT32 ui32RefCount; - - + /* + linked list next pointer + */ struct _BM_CONTEXT_ *psNext; struct _BM_CONTEXT_ **ppsThis; }; - - +/* refcount.c needs to know the internals of this structure */ +typedef struct _XPROC_DATA_{ + 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; +} XPROC_DATA; + +extern XPROC_DATA gXProcWorkaroundShareData[]; +/* + Buffer handle. +*/ typedef IMG_VOID *BM_HANDLE; +/** Buffer manager allocation flags. + * + * Flags passed to BM_Alloc to specify buffer capabilities. + * + * @defgroup BP Buffer Manager Allocation Flags + * @{ + */ + +/** Pool number mask. */ #define BP_POOL_MASK 0x7 +/* Request physically contiguous pages of memory */ #define BP_CONTIGUOUS (1 << 3) #define BP_PARAMBUFFER (1 << 4) #define BM_MAX_DEVMEM_ARENAS 2 +/** @} */ + +/** + * @Function BM_CreateContext + * + * @Description + * + * @Input + + * @Return + */ + IMG_HANDLE BM_CreateContext(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_DEV_PHYADDR *psPDDevPAddr, @@ -143,30 +238,113 @@ BM_CreateContext(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_BOOL *pbCreated); +/** + * @Function BM_DestroyContext + * + * @Description + * + * @Input + * + * @Return PVRSRV_ERROR + */ PVRSRV_ERROR BM_DestroyContext (IMG_HANDLE hBMContext, IMG_BOOL *pbCreated); +/** + * @Function BM_CreateHeap + * + * @Description + * + * @Input + * + * @Return + */ IMG_HANDLE BM_CreateHeap (IMG_HANDLE hBMContext, DEVICE_MEMORY_HEAP_INFO *psDevMemHeapInfo); +/** + * @Function BM_DestroyHeap + * + * @Description + * + * @Input + * + * @Return + */ IMG_VOID BM_DestroyHeap (IMG_HANDLE hDevMemHeap); +/** + * @Function BM_Reinitialise + * + * @Description + * + * Reinitialises the buffer manager after a power event. Calling this + * function will reprogram MMU registers and renable the MMU. + * + * @Input None + * @Return None + */ + IMG_BOOL BM_Reinitialise (PVRSRV_DEVICE_NODE *psDeviceNode); +/** + * @Function BM_Alloc + * + * @Description + * + * Allocate a buffer mapped into both host and device virtual memory + * maps. + * + * @Input uSize - require size in bytes of the buffer. + * @Input/Output pui32Flags - bit mask of buffer property flags + recieves heap flags. + * @Input uDevVAddrAlignment - required alignment in bytes, or 0. + * @Input pvPrivData - private data passed to OS allocator + * @Input ui32PrivDataLength - length of private data + * @Input ui32ChunkSize - Chunk size + * @Input ui32NumVirtChunks - Number of virtual chunks + * @Input ui32NumPhysChunks - Number of physical chunks + * @Input pabMapChunk - Chunk mapping array + * @Output phBuf - receives the buffer handle. + * @Return IMG_TRUE - Success, IMG_FALSE - Failed. + */ 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, + IMG_UINT32 ui32ChunkSize, + IMG_UINT32 ui32NumVirtChunks, + IMG_UINT32 ui32NumPhysChunks, + IMG_BOOL *pabMapChunk, BM_HANDLE *phBuf); +/** + * @Function BM_Wrap + * + * @Description + * + * Create a buffer which wraps user provided host physical memory. + * The wrapped memory must be page aligned. BM_Wrap will roundup the + * size to a multiple of host pages. + * + * @Input ui32Size - size of memory to wrap. + * @Input ui32Offset - Offset into page of memory to wrap. + * @Input bPhysContig - Is the wrap physically contiguous. + * @Input psSysAddr - list of system physical page addresses of memory to wrap. + * @Input pvCPUVAddr - optional CPU kernel virtual address (Page aligned) of memory to wrap. + * @Input uFlags - bit mask of buffer property flags. + * @Input phBuf - receives the buffer handle. + * @Return IMG_TRUE - Success, IMG_FALSE - Failed + */ IMG_BOOL BM_Wrap ( IMG_HANDLE hDevMemHeap, IMG_SIZE_T ui32Size, @@ -177,15 +355,20 @@ BM_Wrap ( IMG_HANDLE hDevMemHeap, IMG_UINT32 *pui32Flags, BM_HANDLE *phBuf); +/** + * @Function BM_Free + * + * @Description + * + * Free a buffer previously allocated via BM_Alloc. + * + * @Input hBuf - buffer handle. + * @Return None. + */ IMG_VOID BM_Free (BM_HANDLE hBuf, IMG_UINT32 ui32Flags); -IMG_VOID -BM_RegisterSmart(BM_HANDLE hBuf, IMG_HANDLE hSmartCache); - -IMG_VOID -BM_UnregisterSmart(BM_HANDLE hBuf, IMG_HANDLE hSmartCache); #if defined(SUPPORT_DRI_DRM_EXTERNAL) @@ -194,15 +377,56 @@ IMG_HANDLE BM_GetGEM(BM_HANDLE hBuf); #endif /* SUPPORT_DRI_DRM_EXTERNAL */ +/** + * @Function BM_HandleToCpuVaddr + * + * @Description + * + * Retrieve the host virtual address associated with a buffer. + * + * @Input hBuf - buffer handle. + * + * @Return buffers host virtual address. + */ IMG_CPU_VIRTADDR BM_HandleToCpuVaddr (BM_HANDLE hBuf); +/** + * @Function BM_HandleToDevVaddr + * + * @Description + * + * Retrieve the device virtual address associated with a buffer. + * + * @Input hBuf - buffer handle. + * @Return buffers device virtual address. + */ IMG_DEV_VIRTADDR BM_HandleToDevVaddr (BM_HANDLE hBuf); +/** + * @Function BM_HandleToSysPaddr + * + * @Description + * + * Retrieve the system physical address associated with a buffer. + * + * @Input hBuf - buffer handle. + * @Return buffers device virtual address. + */ IMG_SYS_PHYADDR BM_HandleToSysPaddr (BM_HANDLE hBuf); +/** + * @Function BM_HandleToMemOSHandle + * + * @Description + * + * Retrieve the underlying memory handle associated with a buffer. + * + * @Input hBuf - buffer handle. + * @Return An OS Specific memory handle + */ IMG_HANDLE BM_HandleToOSMemHandle (BM_HANDLE hBuf); @@ -214,34 +438,212 @@ IMG_BOOL BM_UnmapFromDev(BM_HANDLE hBuf); +/** + * @Function BM_GetPhysPageAddr + * + * @Description + * + * Retreive physical address backing dev V address + * + * @Input psMemInfo + * @Input sDevVPageAddr + * @Output psDevPAddr + * @Return PVRSRV_ERROR + */ IMG_VOID BM_GetPhysPageAddr(PVRSRV_KERNEL_MEM_INFO *psMemInfo, IMG_DEV_VIRTADDR sDevVPageAddr, IMG_DEV_PHYADDR *psDevPAddr); +/*! +****************************************************************************** + @Function BM_GetMMUContext + + @Description + utility function to return the MMU context + + @inputs hDevMemHeap - the Dev mem heap handle + + @Return MMU context, else NULL +**************************************************************************/ MMU_CONTEXT* BM_GetMMUContext(IMG_HANDLE hDevMemHeap); +/*! +****************************************************************************** + @Function BM_GetMMUContextFromMemContext + + @Description + utility function to return the MMU context + + @inputs hDevMemHeap - the Dev mem heap handle + + @Return MMU context, else NULL +**************************************************************************/ MMU_CONTEXT* BM_GetMMUContextFromMemContext(IMG_HANDLE hDevMemContext); +/*! +****************************************************************************** + @Function BM_GetMMUHeap + + @Description + utility function to return the MMU heap handle + + @inputs hDevMemHeap - the Dev mem heap handle + + @Return MMU heap handle, else NULL +**************************************************************************/ IMG_HANDLE BM_GetMMUHeap(IMG_HANDLE hDevMemHeap); +/*! +****************************************************************************** + @Function BM_GetDeviceNode + + @Description utility function to return the devicenode from the BM Context + + @inputs hDevMemContext - the Dev Mem Context + + @Return MMU heap handle, else NULL +**************************************************************************/ PVRSRV_DEVICE_NODE* BM_GetDeviceNode(IMG_HANDLE hDevMemContext); +/*! +****************************************************************************** + @Function BM_GetMappingHandle + + @Description utility function to return the mapping handle from a meminfo + + @inputs psMemInfo - kernel meminfo + + @Return mapping handle, else NULL +**************************************************************************/ IMG_HANDLE BM_GetMappingHandle(PVRSRV_KERNEL_MEM_INFO *psMemInfo); +/*! +****************************************************************************** + @Function BM_Export + + @Description Export a buffer previously allocated via BM_Alloc. + + @inputs hBuf - buffer handle. + + @Return None. +**************************************************************************/ IMG_VOID BM_Export(BM_HANDLE hBuf); +/*! +****************************************************************************** + @Function BM_FreeExport + + @Description Free a buffer previously exported via BM_Export. + + @inputs hBuf - buffer handle. + ui32Flags - flags + + @Return None. +**************************************************************************/ IMG_VOID BM_FreeExport(BM_HANDLE hBuf, IMG_UINT32 ui32Flags); -PVRSRV_ERROR BM_XProcSetShareIndex(PXProcShareDataNode pShareDataNode); -PVRSRV_ERROR BM_XProcFinishShareIndex(PXProcShareDataNode pShareDataNode, IMG_BOOL freeIfNotUsed); -PXProcShareDataNode BM_XProcAllocNewBuffer(void); +/*! +****************************************************************************** + @Function BM_MappingHandleFromBuffer + + @Description utility function to get the BM mapping handle from a BM buffer + + @Input hBuffer - Handle to BM buffer + + @Return BM mapping handle +**************************************************************************/ +IMG_HANDLE BM_MappingHandleFromBuffer(IMG_HANDLE hBuffer); + +/*! +****************************************************************************** + @Function BM_GetVirtualSize + + @Description utility function to get the VM size of a BM mapping + + @Input hBMHandle - Handle to BM mapping + + @Return VM size of mapping +**************************************************************************/ +IMG_UINT32 BM_GetVirtualSize(IMG_HANDLE hBMHandle); + +/*! +****************************************************************************** + @Function BM_MapPageAtOffset + + @Description utility function check if the specificed offset in a BM mapping + is a page that needs tp be mapped + + @Input hBMHandle - Handle to BM mapping + + @Input ui32Offset - Offset into import + + @Return IMG_TRUE if the page should be mapped +**************************************************************************/ +IMG_BOOL BM_MapPageAtOffset(IMG_HANDLE hBMHandle, IMG_UINT32 ui32Offset); + +/*! +****************************************************************************** + @Function BM_VirtOffsetToPhyscial + + @Description utility function find of physical offset of a sparse allocation + from it's virtual offset. + + @Input hBMHandle - Handle to BM mapping + + @Input ui32VirtOffset - Virtual offset into allocation + + @Output pui32PhysOffset - Physical offset + + @Return IMG_TRUE if the virtual offset is physically backed +**************************************************************************/ +IMG_BOOL BM_VirtOffsetToPhysical(IMG_HANDLE hBMHandle, + IMG_UINT32 ui32VirtOffset, + IMG_UINT32 *pui32PhysOffset); + +/* The following are present for the "share mem" workaround for + cross-process mapping. This is only valid for a specific + use-case, and only tested on Linux (Android) and only + superficially at that. Do not rely on this API! */ +/* The two "Set" functions set a piece of "global" state in the buffer + manager, and "Unset" removes this global state. Therefore, there + is no thread-safety here and it's the caller's responsibility to + ensure that a mutex is acquired before using these functions or any + device memory allocation functions, including, especially, + callbacks from RA. */ +/* Once a "Share Index" is set by this means, any requests from the RA + to import a block of physical memory shall cause the physical + memory allocation to be refcounted, and shared iff the IDs chosen + match */ +/* This API is difficult to use, but saves a lot of plumbing in other + APIs. The next generation of this library should have this functionality + plumbed in properly */ +PVRSRV_ERROR BM_XProcWorkaroundSetShareIndex(IMG_UINT32 ui32Index); +PVRSRV_ERROR BM_XProcWorkaroundUnsetShareIndex(IMG_UINT32 ui32Index); +PVRSRV_ERROR BM_XProcWorkaroundFindNewBufferAndSetShareIndex(IMG_UINT32 *pui32Index); + +#if defined(PVRSRV_REFCOUNT_DEBUG) +IMG_VOID _BM_XProcIndexAcquireDebug(const IMG_CHAR *pszFile, IMG_INT iLine, IMG_UINT32 ui32Index); +IMG_VOID _BM_XProcIndexReleaseDebug(const IMG_CHAR *pszFile, IMG_INT iLine, IMG_UINT32 ui32Index); + +#define BM_XProcIndexAcquire(x...) \ + _BM_XProcIndexAcquireDebug(__FILE__, __LINE__, x) +#define BM_XProcIndexRelease(x...) \ + _BM_XProcIndexReleaseDebug(__FILE__, __LINE__, x) + +#else +IMG_VOID _BM_XProcIndexAcquire(IMG_UINT32 ui32Index); +IMG_VOID _BM_XProcIndexRelease(IMG_UINT32 ui32Index); + +#define BM_XProcIndexAcquire(x) \ + _BM_XProcIndexAcquire( x) +#define BM_XProcIndexRelease(x) \ + _BM_XProcIndexRelease( x) +#endif -IMG_UINT32 BM_XProcWorkaroundGetRefCount(IMG_UINT32 ui32Index); #if defined(__cplusplus) } #endif #endif - diff --git a/sgx/services4/srvkm/include/device.h b/sgx/services4/srvkm/include/device.h index 9df2c73..726d5ce 100644 --- a/sgx/services4/srvkm/include/device.h +++ b/sgx/services4/srvkm/include/device.h @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Common Device header +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Device related function templates and defines +@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. + +*/ /**************************************************************************/ #ifndef __DEVICE_H__ #define __DEVICE_H__ @@ -31,19 +48,27 @@ extern "C" { #endif -#include "ra.h" -#include "resman.h" +#include "ra.h" /* RA_ARENA */ +#include "resman.h" /* PRESMAN_ITEM */ +/* BM context forward reference */ typedef struct _BM_CONTEXT_ BM_CONTEXT; +/* pre-defined MMU structure forward references */ typedef struct _MMU_HEAP_ MMU_HEAP; typedef struct _MMU_CONTEXT_ MMU_CONTEXT; +/* physical resource types: */ +/* contiguous system memory */ #define PVRSRV_BACKINGSTORE_SYSMEM_CONTIG (1<<(PVRSRV_MEM_BACKINGSTORE_FIELD_SHIFT+0)) +/* non-contiguous system memory */ #define PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG (1<<(PVRSRV_MEM_BACKINGSTORE_FIELD_SHIFT+1)) +/* contiguous local device memory */ #define PVRSRV_BACKINGSTORE_LOCALMEM_CONTIG (1<<(PVRSRV_MEM_BACKINGSTORE_FIELD_SHIFT+2)) +/* non-contiguous local device memory */ #define PVRSRV_BACKINGSTORE_LOCALMEM_NONCONTIG (1<<(PVRSRV_MEM_BACKINGSTORE_FIELD_SHIFT+3)) +/* heap types: */ typedef IMG_UINT32 DEVICE_MEMORY_HEAP_TYPE; #define DEVICE_MEMORY_HEAP_PERCONTEXT 0 #define DEVICE_MEMORY_HEAP_KERNEL 1 @@ -51,38 +76,38 @@ typedef IMG_UINT32 DEVICE_MEMORY_HEAP_TYPE; #define DEVICE_MEMORY_HEAP_SHARED_EXPORTED 3 #define PVRSRV_DEVICE_NODE_FLAGS_PORT80DISPLAY 1 -#define PVRSRV_DEVICE_NODE_FLAGS_MMU_OPT_INV 2 +#define PVRSRV_DEVICE_NODE_FLAGS_MMU_OPT_INV 2 /* FIXME : Optimal Invalidation is not default */ typedef struct _DEVICE_MEMORY_HEAP_INFO_ { - + /* heap identifier */ IMG_UINT32 ui32HeapID; - + /* heap identifier string */ IMG_CHAR *pszName; - + /* backing store identifier string */ IMG_CHAR *pszBSName; - + /* Device virtual address of base of heap */ IMG_DEV_VIRTADDR sDevVAddrBase; - + /* heapsize in bytes */ IMG_UINT32 ui32HeapSize; - + /* Flags, includes physical resource (backing store type). Must be available to SOC */ IMG_UINT32 ui32Attribs; - + /* Heap type: per device, kernel only, shared, shared_exported */ DEVICE_MEMORY_HEAP_TYPE DevMemHeapType; - + /* kernel heap handle */ IMG_HANDLE hDevMemHeap; - + /* ptr to local memory allocator for this heap */ RA_ARENA *psLocalDevMemArena; - + /* MMU data page size (4kb, 16kb, 256kb, 1Mb, 4Mb) */ IMG_UINT32 ui32DataPageSize; IMG_UINT32 ui32XTileStride; @@ -91,48 +116,56 @@ typedef struct _DEVICE_MEMORY_HEAP_INFO_ typedef struct _DEVICE_MEMORY_INFO_ { - + /* size of address space, as log2 */ IMG_UINT32 ui32AddressSpaceSizeLog2; - - - + /* + flags, includes physical memory resource types available to the system. + Allows for validation at heap creation, define PVRSRV_BACKINGSTORE_XXX + */ IMG_UINT32 ui32Flags; - + /* heap count. Doesn't include additional heaps from PVRSRVCreateDeviceMemHeap */ IMG_UINT32 ui32HeapCount; - + /* the sync heap id - common code needs to know */ IMG_UINT32 ui32SyncHeapID; - + /* heap for buffer mappings */ IMG_UINT32 ui32MappingHeapID; - + /* heap for ion buffers */ + IMG_UINT32 ui32IonHeapID; + + /* device memory heap info about each heap in a device address space */ DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; - + /* BM kernel context for the device */ BM_CONTEXT *pBMKernelContext; - + /* BM context list for the device*/ BM_CONTEXT *pBMContext; } DEVICE_MEMORY_INFO; +/*! + **************************************************************************** + Device memory descriptor for a given system + ****************************************************************************/ typedef struct DEV_ARENA_DESCRIPTOR_TAG { - IMG_UINT32 ui32HeapID; + IMG_UINT32 ui32HeapID; /*!< memory pool has a unique id for diagnostic purposes */ - IMG_CHAR *pszName; + IMG_CHAR *pszName; /*!< memory pool has a unique string for diagnostic purposes */ - IMG_DEV_VIRTADDR BaseDevVAddr; + IMG_DEV_VIRTADDR BaseDevVAddr; /*!< Device virtual base address of the managed memory pool. */ - IMG_UINT32 ui32Size; + IMG_UINT32 ui32Size; /*!< Size in bytes of the managed memory pool. */ - DEVICE_MEMORY_HEAP_TYPE DevMemHeapType; + DEVICE_MEMORY_HEAP_TYPE DevMemHeapType;/*!< heap type */ - + /* MMU data page size (4kb, 16kb, 256kb, 1Mb, 4Mb) */ IMG_UINT32 ui32DataPageSize; DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeapInfo; @@ -140,26 +173,30 @@ typedef struct DEV_ARENA_DESCRIPTOR_TAG } DEV_ARENA_DESCRIPTOR; +/* + PDUMP MMU atttributes +*/ typedef struct _PDUMP_MMU_ATTRIB_ { PVRSRV_DEVICE_IDENTIFIER sDevId; IMG_CHAR *pszPDRegRegion; - + /* data page info */ IMG_UINT32 ui32DataPageMask; - + /* page table info */ IMG_UINT32 ui32PTEValid; IMG_UINT32 ui32PTSize; IMG_UINT32 ui32PTEAlignShift; - + /* page directory info */ IMG_UINT32 ui32PDEMask; IMG_UINT32 ui32PDEAlignShift; } PDUMP_MMU_ATTRIB; +/* forward reference to _SYS_DATA_ */ typedef struct _SYS_DATA_TAG_ *PSYS_DATA; typedef struct _PVRSRV_DEVICE_NODE_ @@ -167,17 +204,18 @@ typedef struct _PVRSRV_DEVICE_NODE_ PVRSRV_DEVICE_IDENTIFIER sDevId; IMG_UINT32 ui32RefCount; - - - + /* + callbacks the device must support: + */ + /* device initialiser */ PVRSRV_ERROR (*pfnInitDevice) (IMG_VOID*); - + /* device deinitialiser */ PVRSRV_ERROR (*pfnDeInitDevice) (IMG_VOID*); - + /* device post-finalise compatibility check */ PVRSRV_ERROR (*pfnInitDeviceCompatCheck) (struct _PVRSRV_DEVICE_NODE_*); - + /* device MMU interface */ PVRSRV_ERROR (*pfnMMUInitialise)(struct _PVRSRV_DEVICE_NODE_*, MMU_CONTEXT**, IMG_DEV_PHYADDR*); IMG_VOID (*pfnMMUFinalise)(MMU_CONTEXT*); IMG_VOID (*pfnMMUInsertHeap)(MMU_CONTEXT*, MMU_HEAP*); @@ -198,6 +236,16 @@ typedef struct _PVRSRV_DEVICE_NODE_ IMG_SIZE_T uSize, IMG_UINT32 ui32MemFlags, IMG_HANDLE hUniqueTag); + IMG_VOID (*pfnMMUMapPagesSparse)(MMU_HEAP *pMMU, + IMG_DEV_VIRTADDR devVAddr, + IMG_SYS_PHYADDR SysPAddr, + IMG_UINT32 ui32ChunkSize, + IMG_UINT32 ui32NumVirtChunks, + IMG_UINT32 ui32NumPhysChunks, + IMG_BOOL *pabMapChunk, + IMG_UINT32 ui32MemFlags, + IMG_HANDLE hUniqueTag); + IMG_VOID (*pfnMMUMapShadow)(MMU_HEAP *pMMU, IMG_DEV_VIRTADDR MapBaseDevVAddr, IMG_SIZE_T uSize, @@ -206,6 +254,18 @@ typedef struct _PVRSRV_DEVICE_NODE_ IMG_DEV_VIRTADDR *pDevVAddr, IMG_UINT32 ui32MemFlags, IMG_HANDLE hUniqueTag); + IMG_VOID (*pfnMMUMapShadowSparse)(MMU_HEAP *pMMU, + IMG_DEV_VIRTADDR MapBaseDevVAddr, + IMG_UINT32 ui32ChunkSize, + IMG_UINT32 ui32NumVirtChunks, + IMG_UINT32 ui32NumPhysChunks, + IMG_BOOL *pabMapChunk, + IMG_CPU_VIRTADDR CpuVAddr, + IMG_HANDLE hOSMemHandle, + IMG_DEV_VIRTADDR *pDevVAddr, + IMG_UINT32 ui32MemFlags, + IMG_HANDLE hUniqueTag); + IMG_VOID (*pfnMMUUnmapPages)(MMU_HEAP *pMMU, IMG_DEV_VIRTADDR dev_vaddr, IMG_UINT32 ui32PageCount, @@ -225,7 +285,7 @@ typedef struct _PVRSRV_DEVICE_NODE_ IMG_VOID (*pfnMMUGetCacheFlushRange)(MMU_CONTEXT *pMMUContext, IMG_UINT32 *pui32RangeMask); IMG_VOID (*pfnMMUGetPDPhysAddr)(MMU_CONTEXT *pMMUContext, IMG_DEV_PHYADDR *psDevPAddr); - + /* tiling range control functions */ PVRSRV_ERROR (*pfnAllocMemTilingRange)(struct _PVRSRV_DEVICE_NODE_ *psDeviceNode, PVRSRV_KERNEL_MEM_INFO *psMemInfo, IMG_UINT32 ui32TilingStride, @@ -233,36 +293,36 @@ typedef struct _PVRSRV_DEVICE_NODE_ PVRSRV_ERROR (*pfnFreeMemTilingRange)(struct _PVRSRV_DEVICE_NODE_ *psDeviceNode, IMG_UINT32 ui32RangeIndex); - + /* LISR handler for device */ IMG_BOOL (*pfnDeviceISR)(IMG_VOID*); - + /* ISR data */ IMG_VOID *pvISRData; - + /* System/SOC specific interrupt bit relating to this device */ IMG_UINT32 ui32SOCInterruptBit; - + /* MISR handler for device */ IMG_VOID (*pfnDeviceMISR)(IMG_VOID*); - + /* Software command complete callback for device */ IMG_VOID (*pfnDeviceCommandComplete)(struct _PVRSRV_DEVICE_NODE_ *psDeviceNode); - + /* Flag indicating that command complete callback needs to be reprocessed */ IMG_BOOL bReProcessDeviceCommandComplete; IMG_VOID (*pfnCacheInvalidate)(struct _PVRSRV_DEVICE_NODE_ *psDeviceNode); - + /* information about the device's address space and heaps */ DEVICE_MEMORY_INFO sDevMemoryInfo; - + /* private device information */ IMG_VOID *pvDevice; - IMG_UINT32 ui32pvDeviceSize; + IMG_UINT32 ui32pvDeviceSize; /* required by GetClassDeviceInfo API */ - + /* Resource Manager Context */ PRESMAN_CONTEXT hResManContext; - + /* pointer back to parent sysdata */ PSYS_DATA psSysData; - + /* default MMU PT/PD backing store to use for the device */ RA_ARENA *psLocalDevMemArena; IMG_UINT32 ui32Flags; @@ -271,9 +331,11 @@ typedef struct _PVRSRV_DEVICE_NODE_ struct _PVRSRV_DEVICE_NODE_ **ppsThis; #if defined(PDUMP) - + /* device-level callback which is called when pdump.exe starts. + * Should be implemented in device-specific init code, e.g. sgxinit.c + */ PVRSRV_ERROR (*pfnPDumpInitDevice)(struct _PVRSRV_DEVICE_NODE_ *psDeviceNode); - + /* device-level callback to return pdump ID associated to a memory context */ IMG_UINT32 (*pfnMMUGetContextID)(IMG_HANDLE hDevMemContext); #endif } PVRSRV_DEVICE_NODE; @@ -292,23 +354,45 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVDeinitialiseDevice(IMG_UINT32 ui32DevIndex); #if !defined(USE_CODE) -IMG_IMPORT PVRSRV_ERROR IMG_CALLCONV PollForValueKM(volatile IMG_UINT32* pui32LinMemAddr, - IMG_UINT32 ui32Value, - IMG_UINT32 ui32Mask, - IMG_UINT32 ui32Timeoutus, - IMG_UINT32 ui32PollPeriodus, - IMG_BOOL bAllowPreemption); +/*! +****************************************************************************** -#endif + @Function PollForValueKM + + @Description + Polls for a value to match a masked read of sysmem + + @Input pui32LinMemAddr : CPU linear address of the mem to poll + @Input ui32Value : req'd value + @Input ui32Mask : Mask + @Input ui32Timeoutus : maximum total time to wait (us) + @Input ui32PollPeriodus : minimum delay between consecutive polls (us) + @Input bAllowPreemption : allow the polling loop to be preempted + + @Return PVRSRV_ERROR : + +******************************************************************************/ +IMG_IMPORT PVRSRV_ERROR IMG_CALLCONV PollForValueKM(volatile IMG_UINT32* pui32LinMemAddr, + IMG_UINT32 ui32Value, + IMG_UINT32 ui32Mask, + IMG_UINT32 ui32Timeoutus, + IMG_UINT32 ui32PollPeriodus, + IMG_BOOL bAllowPreemption); + +#endif /* !defined(USE_CODE) */ #if defined (USING_ISR_INTERRUPTS) PVRSRV_ERROR IMG_CALLCONV PollForInterruptKM(IMG_UINT32 ui32Value, - IMG_UINT32 ui32Mask, - IMG_UINT32 ui32Waitus, - IMG_UINT32 ui32Tries); -#endif + IMG_UINT32 ui32Mask, + IMG_UINT32 ui32Waitus, + IMG_UINT32 ui32Tries); + +#endif /* #if defined (USING_ISR_INTERRUPTS) */ +/* The following functions don't really belong here (srvkm.h might be a better + * place), but as they use the device data structures, this is the most convenient + * place for them. */ PVRSRV_ERROR IMG_CALLCONV PVRSRVInit(PSYS_DATA psSysData); IMG_VOID IMG_CALLCONV PVRSRVDeInit(PSYS_DATA psSysData); IMG_BOOL IMG_CALLCONV PVRSRVDeviceLISR(PVRSRV_DEVICE_NODE *psDeviceNode); @@ -319,5 +403,8 @@ IMG_VOID IMG_CALLCONV PVRSRVMISR(IMG_VOID *pvSysData); } #endif -#endif +#endif /* __DEVICE_H__ */ +/****************************************************************************** + End of file (device.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/include/handle.h b/sgx/services4/srvkm/include/handle.h index 536fa56..fdfe0a8 100644 --- a/sgx/services4/srvkm/include/handle.h +++ b/sgx/services4/srvkm/include/handle.h @@ -1,31 +1,184 @@ -/********************************************************************** +/*************************************************************************/ /*! +@Title Handle Manager API +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Provide handle management +@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. + +*/ /**************************************************************************/ +#ifndef __HANDLE_H__ +#define __HANDLE_H__ + +/* + * Handle API + * ---------- + * The handle API is intended to provide handles for kernel resources, + * which can then be passed back to user space processes. * - * 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". + * The following functions comprise the API. Each function takes a + * pointer to a PVRSRV_HANDLE_BASE strcture, one of which is allocated + * for each process, and stored in the per-process data area. Use + * KERNEL_HANDLE_BASE for handles not allocated for a particular process, + * or for handles that need to be allocated before the PVRSRV_HANDLE_BASE + * structure for the process is available. * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * PVRSRV_ERROR PVRSRVAllocHandle(PVRSRV_HANDLE_BASE *psBase, + * IMG_HANDLE *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, + * PVRSRV_HANDLE_ALLOC_FLAG eFlag); * - ******************************************************************************/ - -#ifndef __HANDLE_H__ -#define __HANDLE_H__ + * Allocate a handle phHandle, for the resource of type eType pointed to by + * pvData. + * + * For handles that have a definite lifetime, where the corresponding + * resource is explicitly created and destroyed, eFlag should be zero. + * + * If the resource is not explicitly created and destroyed, eFlag should be + * set to PVRSRV_HANDLE_ALLOC_FLAG_SHARED. For a given process, the same + * handle will be returned each time a handle for the resource is allocated + * with the PVRSRV_HANDLE_ALLOC_FLAG_SHARED flag. + * + * If a particular resource may be referenced multiple times by a + * given process, setting eFlag to PVRSRV_HANDLE_ALLOC_FLAG_MULTI + * will allow multiple handles to be allocated for the resource. + * Such handles cannot be found with PVRSRVFindHandle. + * + * PVRSRV_ERROR PVRSRVAllocSubHandle(PVRSRV_HANDLE_BASE *psBase, + * IMG_HANDLE *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, + * PVRSRV_HANDLE_ALLOC_FLAG eFlag, IMG_HANDLE hParent); + * + * This function is similar to PVRSRVAllocHandle, except that the allocated + * handles are associated with a parent handle, hParent, that has been + * allocated previously. Subhandles are automatically deallocated when their + * parent handle is dealloacted. + * Subhandles can be treated as ordinary handles. For example, they may + * have subhandles of their own, and may be explicity deallocated using + * PVRSRVReleaseHandle (see below). + * + * PVRSRV_ERROR PVRSRVFindHandle(PVRSRV_HANDLE_BASE *psBase, + * IMG_HANDLE *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType); + * + * Find the handle previously allocated for the resource pointed to by + * pvData, of type eType. Handles allocated with the flag + * PVRSRV_HANDLE_ALLOC_FLAG_MULTI cannot be found using this + * function. + * + * PVRSRV_ERROR PVRSRVLookupHandle(PVRSRV_HANDLE_BASE *psBase, + * IMG_PVOID *ppvData, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType); + * + * Given a handle for a resource of type eType, return the pointer to the + * resource. + * + * PVRSRV_ERROR PVRSRVLookuSubHandle(PVRSRV_HANDLE_BASE *psBase, + * IMG_PVOID *ppvData, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType, + * IMH_HANDLE hAncestor); + * + * Similar to PVRSRVLookupHandle, but checks the handle is a descendent + * of hAncestor. + * + * PVRSRV_ERROR PVRSRVLookupHandleAnyType(PVRSRV_HANDLE_BASE *psBase, + * IMG_PVOID *ppvData, PVRSRV_HANDLE_TYPE *peType, IMG_HANDLE hHandle); + * + * This function returns the resource pointer corresponding to the + * given handle, and the resource type in peType. This function is + * intended for situations where a handle may be one of several types, + * but the type isn't known beforehand. + * + * PVRSRV_ERROR PVRSRVReleaseHandle(PVRSRV_HANDLE_BASE *psBase, + * IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType); + * + * Deallocate a handle of given type. + * + * PVRSRV_ERROR PVRSRVLookupAndReleaseHandle(PVRSRV_HANDLE_BASE *psBase, + * IMG_PVOID *ppvData, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType); + * + * This function combines the functionality of PVRSRVLookupHandle and + * PVRSRVReleaseHandle, deallocating the handle after looking it up. + * + * PVRSRV_ERROR PVRSRVGetParentHandle(PVRSRV_HANDLE_BASE *psBase, + * IMG_PVOID *phParent, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType); + * + * Return the parent of a handle in *phParent, or IMG_NULL if the handle has + * no parent. + * + * PVRSRV_ERROR PVRSRVNewHandleBatch(PVRSRV_HANDLE_BASE *psBase, + * IMG_UINT32 ui32BatchSize) + * + * Allocate a new handle batch. This preallocates ui32BatchSize handles. + * Batch mode simplifies the handling of handle allocation failures. + * The handle API is unchanged in batch mode, except that handles freed + * in batch mode will not be available for reallocation until the batch + * is committed or released (see below). + * + * PVRSRV_ERROR PVRSRVCommitHandleBatch(PVRSRV_HANDLE_BASE *psBase) + * void PVRSRVReleaseHandleBatch(PVRSRV_HANDLE_BASE *psBase) + * + * When handle allocation from a handle batch is complete, the + * batch must be committed by calling PVRSRVCommitHandleBatch. If + * an error occurred, and none of the handles in the batch are no + * longer needed, PVRSRVReleaseHandleBatch must be called. + * The macros PVRSRVAllocHandleNR, and PVRSRVAllocSubHandleNR + * are defined for use in batch mode. These work the same way + * as PVRSRVAllocHandle and PVRSRVAllocSubHandle, except that + * they don't return a value, relying on the fact that + * PVRSRVCommitHandleBatch will not commit any of the handles + * in a batch if there was an error allocating one of the + * handles in the batch. + * + * PVRSRV_ERROR PVRSRVSetMaxHandle(PVRSRV_HANDLE_BASE *psBase, + * IMG_UINT32 ui32MaxHandle) + * Set the maximum handle number. This is intended to restrict the + * handle range so that it will fit within a given field width. For + * example, setting the maximum handle number to 0x7fffffff, would + * ensure the handles would fit within a 31 bit width field. This + * facility should be used with caution, as it restricts the number of + * handles that can be allocated. + * + * IMG_UINT32 PVRSRVGetMaxHandle(PVRSRV_HANDLE_BASE *psBase) + * Return the maximum handle number, or 0 if the setting of a limit + * is not supported. + * + * PVRSRV_ERROR PVRSRVEnableHandlePurging(PVRSRV_HANDLE_BASE *psBase) + * Allows unused handle space to be reclaimed, by calling + * PVRSRVPurgeHandles. Note that allocating handles may have a + * higher overhead if purging is enabled. + * + * PVRSRV_ERROR PVRSRVPurgeHandles((PVRSRV_HANDLE_BASE *psBase) + * Purge handles for a handle base that has purging enabled. + */ #if defined (__cplusplus) extern "C" { @@ -65,13 +218,13 @@ typedef enum typedef enum { - + /* No flags */ PVRSRV_HANDLE_ALLOC_FLAG_NONE = 0, - + /* Share a handle that already exists for a given data pointer */ PVRSRV_HANDLE_ALLOC_FLAG_SHARED = 0x01, - + /* Muliple handles can point at the given data pointer */ PVRSRV_HANDLE_ALLOC_FLAG_MULTI = 0x02, - + /* Subhandles are allocated in a private handle space */ PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE = 0x04 } PVRSRV_HANDLE_ALLOC_FLAG; @@ -119,7 +272,7 @@ PVRSRV_ERROR PVRSRVGetParentHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *phPare PVRSRV_ERROR PVRSRVLookupAndReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType); PVRSRV_ERROR PVRSRVReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType); -#endif +#endif /* #if defined (SUPPORT_SID_INTERFACE) */ PVRSRV_ERROR PVRSRVNewHandleBatch(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32BatchSize); @@ -143,7 +296,7 @@ PVRSRV_ERROR PVRSRVHandleInit(IMG_VOID); PVRSRV_ERROR PVRSRVHandleDeInit(IMG_VOID); -#else +#else /* #if defined (PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE)*/ #define KERNEL_HANDLE_BASE IMG_NULL @@ -196,7 +349,10 @@ static INLINE PVRSRV_ERROR PVRSRVLookupHandleAnyType(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, PVRSRV_HANDLE_TYPE *peType, IMG_HANDLE hHandle) { PVR_UNREFERENCED_PARAMETER(psBase); - + /* + * Unlike the other functions here, the returned results will need + * to be handled differently for the secure and non-secure cases. + */ *peType = PVRSRV_HANDLE_TYPE_NONE; *ppvData = hHandle; @@ -388,8 +544,13 @@ PVRSRV_ERROR PVRSRVHandleDeInit(IMG_VOID) return PVRSRV_OK; } -#endif +#endif /* #if defined (PVR_SECURE_HANDLES) || defined (SUPPORT_SID_INTERFACE)*/ +/* + * Versions of PVRSRVAllocHandle and PVRSRVAllocSubHandle with no return + * values. Intended for use with batched handle allocation, relying on + * CommitHandleBatch to detect handle allocation errors. + */ #define PVRSRVAllocHandleNR(psBase, phHandle, pvData, eType, eFlag) \ (IMG_VOID)PVRSRVAllocHandle(psBase, phHandle, pvData, eType, eFlag) @@ -400,5 +561,8 @@ PVRSRV_ERROR PVRSRVHandleDeInit(IMG_VOID) } #endif -#endif +#endif /* __HANDLE_H__ */ +/****************************************************************************** + End of file (handle.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/include/hash.h b/sgx/services4/srvkm/include/hash.h index 3662089..2179ac0 100644 --- a/sgx/services4/srvkm/include/hash.h +++ b/sgx/services4/srvkm/include/hash.h @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Self scaling hash tables +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Implements simple self scaling hash tables. +@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. + +*/ /**************************************************************************/ #ifndef _HASH_H_ #define _HASH_H_ @@ -34,6 +51,10 @@ extern "C" { #endif +/* + * Keys passed to the comparsion function are only guaranteed to + * be aligned on an IMG_UINTPTR_T boundary. + */ typedef IMG_UINT32 HASH_FUNC(IMG_SIZE_T uKeySize, IMG_VOID *pKey, IMG_UINT32 uHashTabLen); typedef IMG_BOOL HASH_KEY_COMP(IMG_SIZE_T uKeySize, IMG_VOID *pKey1, IMG_VOID *pKey2); @@ -44,31 +65,203 @@ typedef PVRSRV_ERROR (*HASH_pfnCallback) ( IMG_UINTPTR_T v ); +/*! +****************************************************************************** + @Function HASH_Func_Default + + @Description Hash function intended for hashing keys composed of + IMG_UINTPTR_T arrays. + + @Input uKeySize - the size of the hash key, in bytes. + @Input pKey - a pointer to the key to hash. + @Input uHashTabLen - the length of the hash table. + + @Return The hash value. +******************************************************************************/ IMG_UINT32 HASH_Func_Default (IMG_SIZE_T uKeySize, IMG_VOID *pKey, IMG_UINT32 uHashTabLen); +/*! +****************************************************************************** + @Function HASH_Key_Comp_Default + + @Description Compares keys composed of IMG_UINTPTR_T arrays. + + @Input uKeySize - the size of the hash key, in bytes. + @Input pKey1 - pointer to first hash key to compare. + @Input pKey2 - pointer to second hash key to compare. + + @Return IMG_TRUE - the keys match. + IMG_FALSE - the keys don't match. +******************************************************************************/ IMG_BOOL HASH_Key_Comp_Default (IMG_SIZE_T uKeySize, IMG_VOID *pKey1, IMG_VOID *pKey2); +/*! +****************************************************************************** + @Function HASH_Create_Extended + + @Description Create a self scaling hash table, using the supplied + key size, and the supllied hash and key comparsion + functions. + + @Input uInitialLen - initial and minimum length of the + hash table, where the length refers to the number + of entries in the hash table, not its size in + bytes. + @Input uKeySize - the size of the key, in bytes. + @Input pfnHashFunc - pointer to hash function. + @Input pfnKeyComp - pointer to key comparsion function. + + @Return IMG_NULL or hash table handle. +******************************************************************************/ HASH_TABLE * HASH_Create_Extended (IMG_UINT32 uInitialLen, IMG_SIZE_T uKeySize, HASH_FUNC *pfnHashFunc, HASH_KEY_COMP *pfnKeyComp); +/*! +****************************************************************************** + @Function HASH_Create + + @Description Create a self scaling hash table with a key + consisting of a single IMG_UINTPTR_T, and using + the default hash and key comparison functions. + + @Input uInitialLen - initial and minimum length of the + hash table, where the length refers to the + number of entries in the hash table, not its size + in bytes. + + @Return IMG_NULL or hash table handle. +******************************************************************************/ HASH_TABLE * HASH_Create (IMG_UINT32 uInitialLen); +/*! +****************************************************************************** + @Function HASH_Delete + + @Description Delete a hash table created by HASH_Create_Extended or + HASH_Create. All entries in the table must have been + removed before calling this function. + + @Input pHash - hash table + + @Return None +******************************************************************************/ IMG_VOID HASH_Delete (HASH_TABLE *pHash); +/*! +****************************************************************************** + @Function HASH_Insert_Extended + + @Description Insert a key value pair into a hash table created + with HASH_Create_Extended. + + @Input pHash - the hash table. + @Input pKey - pointer to the key. + @Input v - the value associated with the key. + + @Return IMG_TRUE - success. + IMG_FALSE - failure. +******************************************************************************/ IMG_BOOL HASH_Insert_Extended (HASH_TABLE *pHash, IMG_VOID *pKey, IMG_UINTPTR_T v); +/*! +****************************************************************************** + @Function HASH_Insert + + @Description Insert a key value pair into a hash table created with + HASH_Create. + + @Input pHash - the hash table. + @Input k - the key value. + @Input v - the value associated with the key. + + @Return IMG_TRUE - success. + IMG_FALSE - failure. +******************************************************************************/ IMG_BOOL HASH_Insert (HASH_TABLE *pHash, IMG_UINTPTR_T k, IMG_UINTPTR_T v); +/*! +****************************************************************************** + @Function HASH_Remove_Extended + + @Description Remove a key from a hash table created with + HASH_Create_Extended. + + @Input pHash - the hash table. + @Input pKey - pointer to key. + + @Return 0 if the key is missing, or the value associated + with the key. +******************************************************************************/ IMG_UINTPTR_T HASH_Remove_Extended(HASH_TABLE *pHash, IMG_VOID *pKey); +/*! +****************************************************************************** + @Function HASH_Remove + + @Description Remove a key value pair from a hash table created + with HASH_Create. + + @Input pHash - the hash table + @Input k - the key + + @Return 0 if the key is missing, or the value associated + with the key. +******************************************************************************/ IMG_UINTPTR_T HASH_Remove (HASH_TABLE *pHash, IMG_UINTPTR_T k); +/*! +****************************************************************************** + @Function HASH_Retrieve_Extended + + @Description Retrieve a value from a hash table created with + HASH_Create_Extended. + + @Input pHash - the hash table. + @Input pKey - pointer to the key. + + @Return 0 if the key is missing, or the value associated with + the key. +******************************************************************************/ IMG_UINTPTR_T HASH_Retrieve_Extended (HASH_TABLE *pHash, IMG_VOID *pKey); +/*! +****************************************************************************** + @Function HASH_Retrieve + + @Description Retrieve a value from a hash table created with + HASH_Create. + + @Input pHash - the hash table + @Input k - the key + + @Return 0 if the key is missing, or the value associated with + the key. +******************************************************************************/ IMG_UINTPTR_T HASH_Retrieve (HASH_TABLE *pHash, IMG_UINTPTR_T k); +/*! +****************************************************************************** + @Function HASH_Interate + + @Description Iterate over every entry in the hash table + + @Input pHash - the old hash table + @Input HASH_pfnCallback - the size of the old hash table + + @Return Callback error if any, otherwise PVRSRV_OK +******************************************************************************/ PVRSRV_ERROR HASH_Iterate(HASH_TABLE *pHash, HASH_pfnCallback pfnCallback); #ifdef HASH_TRACE +/*! +****************************************************************************** + @Function HASH_Dump + + @Description Dump out some information about a hash table. + + @Input pHash - the hash table + + @Return None +******************************************************************************/ IMG_VOID HASH_Dump (HASH_TABLE *pHash); #endif @@ -76,5 +269,10 @@ IMG_VOID HASH_Dump (HASH_TABLE *pHash); } #endif -#endif +#endif /* _HASH_H_ */ + +/****************************************************************************** + End of file (hash.h) +******************************************************************************/ + diff --git a/sgx/services4/srvkm/include/lists.h b/sgx/services4/srvkm/include/lists.h index a02307a..f39c8e2 100644 --- a/sgx/services4/srvkm/include/lists.h +++ b/sgx/services4/srvkm/include/lists.h @@ -1,35 +1,91 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Linked list shared functions templates. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Definition of the linked list function templates. +@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. + +*/ /**************************************************************************/ #ifndef __LISTS_UTILS__ #define __LISTS_UTILS__ +/* instruct QAC to ignore warnings about the following custom formatted macros */ +/* PRQA S 0881,3410 ++ */ #include <stdarg.h> #include "img_types.h" +/* + - USAGE - + + The list functions work with any structure that provides the fields psNext and + ppsThis. In order to make a function available for a given type, it is required + to use the funcion template macro that creates the actual code. + + There are 4 main types of functions: + - INSERT : given a pointer to the head pointer of the list and a pointer to + the node, inserts it as the new head. + - REMOVE : given a pointer to a node, removes it from its list. + - FOR EACH : apply a function over all the elements of a list. + - ANY : apply a function over the elements of a list, until one of them + return a non null value, and then returns it. + + The two last functions can have a variable argument form, with allows to pass + additional parameters to the callback function. In order to do this, the + callback function must take two arguments, the first is the current node and + the second is a list of variable arguments (va_list). + + The ANY functions have also another for wich specifies the return type of the + callback function and the default value returned by the callback function. + +*/ + +/*! +****************************************************************************** + @Function List_##TYPE##_ForEach + + @Description Apply a callback function to all the elements of a list. + + @Input psHead - the head of the list to be processed. + @Input pfnCallBack - the function to be applied to each element + of the list. + + @Return None +******************************************************************************/ #define DECLARE_LIST_FOR_EACH(TYPE) \ IMG_VOID List_##TYPE##_ForEach(TYPE *psHead, IMG_VOID(*pfnCallBack)(TYPE* psNode)) @@ -61,6 +117,19 @@ IMG_VOID List_##TYPE##_ForEach_va(TYPE *psHead, IMG_VOID(*pfnCallBack)(TYPE* psN } +/*! +****************************************************************************** + @Function List_##TYPE##_Any + + @Description Applies a callback function to the elements of a list until + the function returns a non null value, then returns it. + + @Input psHead - the head of the list to be processed. + @Input pfnCallBack - the function to be applied to each element + of the list. + + @Return None +******************************************************************************/ #define DECLARE_LIST_ANY(TYPE) \ IMG_VOID* List_##TYPE##_Any(TYPE *psHead, IMG_VOID* (*pfnCallBack)(TYPE* psNode)) @@ -81,6 +150,8 @@ IMG_VOID* List_##TYPE##_Any(TYPE *psHead, IMG_VOID* (*pfnCallBack)(TYPE* psNode) } +/*with variable arguments, that will be passed as a va_list to the callback function*/ + #define DECLARE_LIST_ANY_VA(TYPE) \ IMG_VOID* List_##TYPE##_Any_va(TYPE *psHead, IMG_VOID*(*pfnCallBack)(TYPE* psNode, va_list va), ...) @@ -101,6 +172,8 @@ IMG_VOID* List_##TYPE##_Any_va(TYPE *psHead, IMG_VOID*(*pfnCallBack)(TYPE* psNod return pResult;\ } +/*those ones are for extra type safety, so there's no need to use castings for the results*/ + #define DECLARE_LIST_ANY_2(TYPE, RTYPE, CONTINUE) \ RTYPE List_##TYPE##_##RTYPE##_Any(TYPE *psHead, RTYPE (*pfnCallBack)(TYPE* psNode)) @@ -142,6 +215,16 @@ RTYPE List_##TYPE##_##RTYPE##_Any_va(TYPE *psHead, RTYPE(*pfnCallBack)(TYPE* psN } +/*! +****************************************************************************** + @Function List_##TYPE##_Remove + + @Description Removes a given node from the list. + + @Input psNode - the pointer to the node to be removed. + + @Return None +******************************************************************************/ #define DECLARE_LIST_REMOVE(TYPE) \ IMG_VOID List_##TYPE##_Remove(TYPE *psNode) @@ -155,6 +238,17 @@ IMG_VOID List_##TYPE##_Remove(TYPE *psNode)\ }\ } +/*! +****************************************************************************** + @Function List_##TYPE##_Insert + + @Description Inserts a given node at the beginnning of the list. + + @Input psHead - The pointer to the pointer to the head node. + @Input psNode - The pointer to the node to be inserted. + + @Return None +******************************************************************************/ #define DECLARE_LIST_INSERT(TYPE) \ IMG_VOID List_##TYPE##_Insert(TYPE **ppsHead, TYPE *psNewNode) @@ -170,6 +264,16 @@ IMG_VOID List_##TYPE##_Insert(TYPE **ppsHead, TYPE *psNewNode)\ }\ } +/*! +****************************************************************************** + @Function List_##TYPE##_Reverse + + @Description Reverse a list in place + + @Input ppsHead - The pointer to the pointer to the head node. + + @Return None +******************************************************************************/ #define DECLARE_LIST_REVERSE(TYPE) \ IMG_VOID List_##TYPE##_Reverse(TYPE **ppsHead) @@ -242,3 +346,5 @@ IMG_VOID* MatchPowerDeviceIndex_AnyVaCb(PVRSRV_POWER_DEV *psPowerDev, va_list va #endif +/* re-enable warnings */ +/* PRQA S 0881,3410 -- */ diff --git a/sgx/services4/srvkm/include/metrics.h b/sgx/services4/srvkm/include/metrics.h index 69e1b3d..3326a7f 100644 --- a/sgx/services4/srvkm/include/metrics.h +++ b/sgx/services4/srvkm/include/metrics.h @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Time measurement interface. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #ifndef _METRICS_ #define _METRICS_ @@ -90,21 +106,21 @@ extern IMG_VOID PVRSRVOutputMetricTotals(IMG_VOID); #if defined(__sh__) -#define TST_REG ((volatile IMG_UINT8 *) (psDevInfo->pvSOCRegsBaseKM)) +#define TST_REG ((volatile IMG_UINT8 *) (psDevInfo->pvSOCRegsBaseKM)) // timer start register -#define TCOR_2 ((volatile IMG_UINT *) (psDevInfo->pvSOCRegsBaseKM+28)) -#define TCNT_2 ((volatile IMG_UINT *) (psDevInfo->pvSOCRegsBaseKM+32)) -#define TCR_2 ((volatile IMG_UINT16 *)(psDevInfo->pvSOCRegsBaseKM+36)) +#define TCOR_2 ((volatile IMG_UINT *) (psDevInfo->pvSOCRegsBaseKM+28)) // timer constant register_2 +#define TCNT_2 ((volatile IMG_UINT *) (psDevInfo->pvSOCRegsBaseKM+32)) // timer counter register_2 +#define TCR_2 ((volatile IMG_UINT16 *)(psDevInfo->pvSOCRegsBaseKM+36)) // timer control register_2 #define TIMER_DIVISOR 4 -#endif +#endif /* defined(__sh__) */ -#else +#else /* defined(DEBUG) || defined(TIMING) */ @@ -119,12 +135,15 @@ extern IMG_VOID PVRSRVOutputMetricTotals(IMG_VOID); -#endif +#endif /* defined(DEBUG) || defined(TIMING) */ #if defined(__cplusplus) } #endif -#endif +#endif /* _METRICS_ */ +/************************************************************************** + End of file (metrics.h) +**************************************************************************/ diff --git a/sgx/services4/srvkm/include/osfunc.h b/sgx/services4/srvkm/include/osfunc.h index 2341c87..953a4b3 100644 --- a/sgx/services4/srvkm/include/osfunc.h +++ b/sgx/services4/srvkm/include/osfunc.h @@ -1,29 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ - +/*************************************************************************/ /*! +@Title OS functions header +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description OS specific API definitions +@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. + +*/ /**************************************************************************/ #ifdef DEBUG_RELEASE_BUILD #pragma optimize( "", off ) #define DEBUG 1 @@ -46,9 +62,13 @@ extern "C" { #endif - +/* setup conditional pageable / non-pageable select */ + /* Non-Vista OSs only need pageable */ #define PVRSRV_PAGEABLE_SELECT PVRSRV_OS_PAGEABLE_HEAP +/****************************************************************************** + * Static defines + *****************************************************************************/ #define KERNEL_ID 0xffffffffL #define POWER_MANAGER_ID 0xfffffffeL #define ISR_ID 0xfffffffdL @@ -59,9 +79,12 @@ extern "C" { #define HOST_PAGEMASK (HOST_PAGESIZE()-1) #define HOST_PAGEALIGN(addr) (((addr) + HOST_PAGEMASK) & ~HOST_PAGEMASK) -#define PVRSRV_OS_HEAP_MASK 0xf -#define PVRSRV_OS_PAGEABLE_HEAP 0x1 -#define PVRSRV_OS_NON_PAGEABLE_HEAP 0x2 +/****************************************************************************** + * Host memory heaps + *****************************************************************************/ +#define PVRSRV_OS_HEAP_MASK 0xf /* host heap flags mask */ +#define PVRSRV_OS_PAGEABLE_HEAP 0x1 /* allocation pageable */ +#define PVRSRV_OS_NON_PAGEABLE_HEAP 0x2 /* allocation non pageable */ IMG_UINT32 OSClockus(IMG_VOID); @@ -80,26 +103,36 @@ IMG_VOID OSMemCopy(IMG_VOID *pvDst, IMG_VOID *pvSrc, IMG_SIZE_T ui32Size); IMG_VOID *OSMapPhysToLin(IMG_CPU_PHYADDR BasePAddr, IMG_SIZE_T ui32Bytes, IMG_UINT32 ui32Flags, IMG_HANDLE *phOSMemHandle); IMG_BOOL OSUnMapPhysToLin(IMG_VOID *pvLinAddr, IMG_SIZE_T ui32Bytes, IMG_UINT32 ui32Flags, IMG_HANDLE hOSMemHandle); -PVRSRV_ERROR OSReservePhys(IMG_CPU_PHYADDR BasePAddr, IMG_SIZE_T ui32Bytes, IMG_UINT32 ui32Flags, IMG_VOID **ppvCpuVAddr, IMG_HANDLE *phOSMemHandle); +PVRSRV_ERROR OSReservePhys(IMG_CPU_PHYADDR BasePAddr, IMG_SIZE_T ui32Bytes, IMG_UINT32 ui32Flags, IMG_HANDLE hBMHandle, IMG_VOID **ppvCpuVAddr, IMG_HANDLE *phOSMemHandle); PVRSRV_ERROR OSUnReservePhys(IMG_VOID *pvCpuVAddr, IMG_SIZE_T ui32Bytes, IMG_UINT32 ui32Flags, IMG_HANDLE hOSMemHandle); -#if defined(__linux__) && defined(__KERNEL__) +/* Some terminology: + * + * FLUSH Flush w/ invalidate + * CLEAN Flush w/o invalidate + * INVALIDATE Invalidate w/o flush + */ + +#if (defined(__linux__) && defined(__KERNEL__)) || (UNDER_CE >= 600) IMG_VOID OSFlushCPUCacheKM(IMG_VOID); IMG_VOID OSCleanCPUCacheKM(IMG_VOID); IMG_BOOL OSFlushCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length); IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length); IMG_BOOL OSInvalidateCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length); -#else +#else /* defined(__linux__) && defined(__KERNEL__) */ #ifdef INLINE_IS_PRAGMA #pragma inline(OSFlushCPUCacheKM) @@ -115,10 +148,12 @@ static INLINE IMG_VOID OSCleanCPUCacheKM(IMG_VOID) {} #pragma inline(OSFlushCPUCacheRangeKM) #endif static INLINE IMG_BOOL OSFlushCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length) { PVR_UNREFERENCED_PARAMETER(hOSMemHandle); + PVR_UNREFERENCED_PARAMETER(ui32ByteOffset); PVR_UNREFERENCED_PARAMETER(pvRangeAddrStart); PVR_UNREFERENCED_PARAMETER(ui32Length); return IMG_FALSE; @@ -128,10 +163,12 @@ static INLINE IMG_BOOL OSFlushCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, #pragma inline(OSCleanCPUCacheRangeKM) #endif static INLINE IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length) { PVR_UNREFERENCED_PARAMETER(hOSMemHandle); + PVR_UNREFERENCED_PARAMETER(ui32ByteOffset); PVR_UNREFERENCED_PARAMETER(pvRangeAddrStart); PVR_UNREFERENCED_PARAMETER(ui32Length); return IMG_FALSE; @@ -141,16 +178,18 @@ static INLINE IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, #pragma inline(OSInvalidateCPUCacheRangeKM) #endif static INLINE IMG_BOOL OSInvalidateCPUCacheRangeKM(IMG_HANDLE hOSMemHandle, + IMG_UINT32 ui32ByteOffset, IMG_VOID *pvRangeAddrStart, IMG_UINT32 ui32Length) { PVR_UNREFERENCED_PARAMETER(hOSMemHandle); + PVR_UNREFERENCED_PARAMETER(ui32ByteOffset); PVR_UNREFERENCED_PARAMETER(pvRangeAddrStart); PVR_UNREFERENCED_PARAMETER(ui32Length); return IMG_FALSE; } -#endif +#endif /* defined(__linux__) && defined(__KERNEL__) */ #if (defined(__linux__) || defined(__QNXNTO__)) PVRSRV_ERROR OSRegisterDiscontigMem(IMG_SYS_PHYADDR *pBasePAddr, @@ -162,7 +201,7 @@ PVRSRV_ERROR OSUnRegisterDiscontigMem(IMG_VOID *pvCpuVAddr, IMG_SIZE_T ui32Bytes, IMG_UINT32 ui32Flags, IMG_HANDLE hOSMemHandle); -#else +#else /* defined(__linux__) */ #ifdef INLINE_IS_PRAGMA #pragma inline(OSRegisterDiscontigMem) #endif @@ -196,7 +235,7 @@ static INLINE PVRSRV_ERROR OSUnRegisterDiscontigMem(IMG_VOID *pvCpuVAddr, return PVRSRV_ERROR_NOT_SUPPORTED; } -#endif +#endif /* defined(__linux__) */ #if (defined(__linux__) || defined(__QNXNTO__)) @@ -211,8 +250,16 @@ static INLINE PVRSRV_ERROR OSReserveDiscontigPhys(IMG_SYS_PHYADDR *pBasePAddr, I #else extern IMG_CPU_PHYADDR SysSysPAddrToCpuPAddr(IMG_SYS_PHYADDR SysPAddr); - - return OSReservePhys(SysSysPAddrToCpuPAddr(pBasePAddr[0]), ui32Bytes, ui32Flags, ppvCpuVAddr, phOSMemHandle); + /* + * On uITRON we know: + * 1. We will only be called with a non-contig physical if we + * already have a contiguous CPU linear + * 2. There is a one->one mapping of CpuPAddr -> CpuVAddr + * 3. Looking up the first CpuPAddr will find the first CpuVAddr + * 4. We don't need to unmap + */ + + return OSReservePhys(SysSysPAddrToCpuPAddr(pBasePAddr[0]), ui32Bytes, ui32Flags, IMG_NULL, ppvCpuVAddr, phOSMemHandle); #endif } @@ -221,10 +268,10 @@ static INLINE PVRSRV_ERROR OSUnReserveDiscontigPhys(IMG_VOID *pvCpuVAddr, IMG_SI #if defined(__linux__) || defined(__QNXNTO__) OSUnRegisterDiscontigMem(pvCpuVAddr, ui32Bytes, ui32Flags, hOSMemHandle); #endif - + /* We don't need to unmap */ return PVRSRV_OK; } -#else +#else /* defined(__linux__) */ #ifdef INLINE_IS_PRAGMA @@ -253,7 +300,7 @@ static INLINE PVRSRV_ERROR OSUnReserveDiscontigPhys(IMG_VOID *pvCpuVAddr, IMG_SI return PVRSRV_ERROR_NOT_SUPPORTED; } -#endif +#endif /* defined(__linux__) */ PVRSRV_ERROR OSRegisterMem(IMG_CPU_PHYADDR BasePAddr, IMG_VOID *pvCpuVAddr, @@ -304,18 +351,33 @@ IMG_UINT32 OSGetCurrentProcessIDKM(IMG_VOID); IMG_UINTPTR_T OSGetCurrentThreadID( IMG_VOID ); IMG_VOID OSMemSet(IMG_VOID *pvDest, IMG_UINT8 ui8Value, IMG_SIZE_T ui32Size); -PVRSRV_ERROR OSAllocPages_Impl(IMG_UINT32 ui32Flags, IMG_SIZE_T ui32Size, IMG_UINT32 ui32PageSize, IMG_PVOID *ppvLinAddr, IMG_HANDLE *phPageAlloc); +PVRSRV_ERROR OSAllocPages_Impl(IMG_UINT32 ui32Flags, IMG_SIZE_T ui32Size, IMG_UINT32 ui32PageSize, + IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength, IMG_HANDLE hBMHandle, IMG_PVOID *ppvLinAddr, IMG_HANDLE *phPageAlloc); PVRSRV_ERROR OSFreePages(IMG_UINT32 ui32Flags, IMG_SIZE_T ui32Size, IMG_PVOID pvLinAddr, IMG_HANDLE hPageAlloc); +/*--------------------- +The set of macros below follows this pattern: + +f(x) = if F -> f2(g(x)) + else -> g(x) + +g(x) = if G -> g2(h(x)) + else -> h(x) + +h(x) = ... + +-----------------------*/ + +/*If level 3 wrapper is enabled, we add a PVR_TRACE and call the next level, else just call the next level*/ #ifdef PVRSRV_LOG_MEMORY_ALLOCS #define OSAllocMem(flags, size, linAddr, blockAlloc, logStr) \ (PVR_TRACE(("OSAllocMem(" #flags ", " #size ", " #linAddr ", " #blockAlloc "): " logStr " (size = 0x%lx)", size)), \ OSAllocMem_Debug_Wrapper(flags, size, linAddr, blockAlloc, __FILE__, __LINE__)) - #define OSAllocPages(flags, size, pageSize, linAddr, pageAlloc) \ + #define OSAllocPages(flags, size, pageSize, privdata, privdatalength, bmhandle, linAddr, pageAlloc) \ (PVR_TRACE(("OSAllocPages(" #flags ", " #size ", " #pageSize ", " #linAddr ", " #pageAlloc "): (size = 0x%lx)", size)), \ - OSAllocPages_Impl(flags, size, pageSize, linAddr, pageAlloc)) + OSAllocPages_Impl(flags, size, pageSize, linAddr, privdata, privdatalength, bmhandle, pageAlloc)) #define OSFreeMem(flags, size, linAddr, blockAlloc) \ (PVR_TRACE(("OSFreeMem(" #flags ", " #size ", " #linAddr ", " #blockAlloc "): (pointer = 0x%X)", linAddr)), \ @@ -330,6 +392,8 @@ PVRSRV_ERROR OSFreePages(IMG_UINT32 ui32Flags, IMG_SIZE_T ui32Size, IMG_PVOID pv OSFreeMem_Debug_Wrapper(flags, size, linAddr, blockAlloc, __FILE__, __LINE__) #endif +/*If level 2 wrapper is enabled declare the function, +else alias to level 1 wrapper, else the wrapper function will be used*/ #ifdef PVRSRV_DEBUG_OS_MEMORY PVRSRV_ERROR OSAllocMem_Debug_Wrapper(IMG_UINT32 ui32Flags, @@ -360,14 +424,16 @@ PVRSRV_ERROR OSFreePages(IMG_UINT32 ui32Flags, IMG_SIZE_T ui32Size, IMG_PVOID pv } eValid; } OSMEM_DEBUG_INFO; - #define TEST_BUFFER_PADDING_STATUS (sizeof(OSMEM_DEBUG_INFO)) - #define TEST_BUFFER_PADDING_AFTER (8) + #define TEST_BUFFER_PADDING_STATUS (sizeof(OSMEM_DEBUG_INFO)) + #define TEST_BUFFER_PADDING_AFTER (8) #define TEST_BUFFER_PADDING (TEST_BUFFER_PADDING_STATUS + TEST_BUFFER_PADDING_AFTER) #else #define OSAllocMem_Debug_Wrapper OSAllocMem_Debug_Linux_Memory_Allocations #define OSFreeMem_Debug_Wrapper OSFreeMem_Debug_Linux_Memory_Allocations #endif +/*If level 1 wrapper is enabled declare the functions with extra parameters +else alias to level 0 and declare the functions without the extra debugging parameters*/ #if (defined(__linux__) || defined(__QNXNTO__)) && defined(DEBUG_LINUX_MEMORY_ALLOCATIONS) PVRSRV_ERROR OSAllocMem_Impl(IMG_UINT32 ui32Flags, IMG_SIZE_T ui32Size, IMG_PVOID *ppvLinAddr, IMG_HANDLE *phBlockAlloc, IMG_CHAR *pszFilename, IMG_UINT32 ui32Line); PVRSRV_ERROR OSFreeMem_Impl(IMG_UINT32 ui32Flags, IMG_SIZE_T ui32Size, IMG_PVOID pvLinAddr, IMG_HANDLE hBlockAlloc, IMG_CHAR *pszFilename, IMG_UINT32 ui32Line); @@ -384,8 +450,6 @@ PVRSRV_ERROR OSFreePages(IMG_UINT32 ui32Flags, IMG_SIZE_T ui32Size, IMG_PVOID pv OSFreeMem_Impl(flags, size, addr, blockAlloc) #endif -IMG_VOID OSMemHandleRegisterSmart(IMG_VOID *hOSMemHandle, IMG_HANDLE hSmartCache); -IMG_VOID OSMemHandleUnegisterSmart(IMG_VOID *hOSMemHandle, IMG_HANDLE hSmartCache); #if defined(SUPPORT_DRI_DRM_EXTERNAL) IMG_VOID OSMemHandleSetGEM(IMG_VOID *hOSMemHandle, IMG_HANDLE buf); @@ -407,6 +471,20 @@ static INLINE IMG_CPU_PHYADDR OSMemHandleToCpuPAddr(IMG_HANDLE hOSMemHandle, IMG return sCpuPAddr; } #endif + +#if defined(__linux__) +IMG_BOOL OSMemHandleIsPhysContig(IMG_VOID *hOSMemHandle); +#else +#ifdef INLINE_IS_PRAGMA +#pragma inline(OSMemHandleIsPhysContig) +#endif +static INLINE IMG_BOOL OSMemHandleIsPhysContig(IMG_HANDLE hOSMemHandle) +{ + PVR_UNREFERENCED_PARAMETER(hOSMemHandle); + return IMG_FALSE; +} +#endif + PVRSRV_ERROR OSInitEnvData(IMG_PVOID *ppvEnvSpecificData); PVRSRV_ERROR OSDeInitEnvData(IMG_PVOID pvEnvSpecificData); IMG_CHAR* OSStringCopy(IMG_CHAR *pszDest, const IMG_CHAR *pszSrc); @@ -433,7 +511,7 @@ PVRSRV_ERROR OSEventObjectOpenKM(PVRSRV_EVENTOBJECT *psEventObject, IMG_HANDLE *phOSEvent); PVRSRV_ERROR OSEventObjectCloseKM(PVRSRV_EVENTOBJECT *psEventObject, IMG_HANDLE hOSEventKM); -#endif +#endif /* #if defined (SUPPORT_SID_INTERFACE) */ PVRSRV_ERROR OSBaseAllocContigMemory(IMG_SIZE_T ui32Size, IMG_CPU_VIRTADDR *pLinAddr, IMG_CPU_PHYADDR *pPhysAddr); @@ -468,15 +546,57 @@ IMG_VOID OSBreakResourceLock(PVRSRV_RESOURCE *psResource, IMG_UINT32 ui32ID); #define OSPowerLockWrap SysPowerLockWrap #define OSPowerLockUnwrap SysPowerLockUnwrap #else +/****************************************************************************** + @Function OSPowerLockWrap + + @Description OS-specific wrapper around the power lock + + @Input bTryLock - don't block on lock contention + + @Return PVRSRV_ERROR +******************************************************************************/ PVRSRV_ERROR OSPowerLockWrap(IMG_BOOL bTryLock); +/****************************************************************************** + @Function OSPowerLockUnwrap + + @Description OS-specific wrapper around the power unlock + + @Return IMG_VOID +******************************************************************************/ IMG_VOID OSPowerLockUnwrap(IMG_VOID); -#endif +#endif /* SYS_CUSTOM_POWERLOCK_WRAP */ + +/*! +****************************************************************************** + @Function OSWaitus + @Description + This function implements a busy wait of the specified microseconds + This function does NOT release thread quanta + + @Input ui32Timeus - (us) + + @Return IMG_VOID + +******************************************************************************/ IMG_VOID OSWaitus(IMG_UINT32 ui32Timeus); +/*! +****************************************************************************** + + @Function OSSleepms + + @Description + This function implements a sleep of the specified milliseconds + This function may allow pre-emption if implemented + @Input ui32Timems - (ms) + + @Return IMG_VOID + +******************************************************************************/ IMG_VOID OSSleepms(IMG_UINT32 ui32Timems); IMG_HANDLE OSFuncHighResTimerCreate(IMG_VOID); @@ -486,6 +606,14 @@ IMG_VOID OSReleaseThreadQuanta(IMG_VOID); IMG_UINT32 OSPCIReadDword(IMG_UINT32 ui32Bus, IMG_UINT32 ui32Dev, IMG_UINT32 ui32Func, IMG_UINT32 ui32Reg); IMG_VOID OSPCIWriteDword(IMG_UINT32 ui32Bus, IMG_UINT32 ui32Dev, IMG_UINT32 ui32Func, IMG_UINT32 ui32Reg, IMG_UINT32 ui32Value); +IMG_IMPORT +IMG_UINT32 ReadHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset); + +IMG_IMPORT +IMG_VOID WriteHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UINT32 ui32Value); + +IMG_IMPORT IMG_VOID WriteHWRegs(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Count, PVRSRV_HWREG *psHWRegs); + #ifndef OSReadHWReg IMG_UINT32 OSReadHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset); #endif @@ -525,6 +653,17 @@ PVRSRV_ERROR OSPCIResumeDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI); PVRSRV_ERROR OSScheduleMISR(IMG_VOID *pvSysData); +/****************************************************************************** + + @Function OSPanic + + @Description Take action in response to an unrecoverable driver error + + @Input IMG_VOID + + @Return IMG_VOID + +******************************************************************************/ IMG_VOID OSPanic(IMG_VOID); IMG_BOOL OSProcHasPrivSrvInit(IMG_VOID); @@ -591,7 +730,7 @@ static inline IMG_VOID OSMemoryBarrier(IMG_VOID) mb(); } -#else +#else /* defined(__linux__) && defined(__KERNEL__) */ #ifdef INLINE_IS_PRAGMA #pragma inline(OSWriteMemoryBarrier) @@ -603,11 +742,58 @@ static INLINE IMG_VOID OSWriteMemoryBarrier(IMG_VOID) { } #endif static INLINE IMG_VOID OSMemoryBarrier(IMG_VOID) { } -#endif +#endif /* defined(__linux__) && defined(__KERNEL__) */ + +/* Atomic functions */ +PVRSRV_ERROR OSAtomicAlloc(IMG_PVOID *ppvRefCount); +IMG_VOID OSAtomicFree(IMG_PVOID pvRefCount); +IMG_VOID OSAtomicInc(IMG_PVOID pvRefCount); +IMG_BOOL OSAtomicDecAndTest(IMG_PVOID pvRefCount); +IMG_UINT32 OSAtomicRead(IMG_PVOID pvRefCount); + +PVRSRV_ERROR OSTimeCreateWithUSOffset(IMG_PVOID *pvRet, IMG_UINT32 ui32MSOffset); +IMG_BOOL OSTimeHasTimePassed(IMG_PVOID pvData); +IMG_VOID OSTimeDestroy(IMG_PVOID pvData); + +#if defined(__linux__) +IMG_VOID OSReleaseBridgeLock(IMG_VOID); +IMG_VOID OSReacquireBridgeLock(IMG_VOID); +#else + +#ifdef INLINE_IS_PRAGMA +#pragma inline(OSReleaseBridgeLock) +#endif +static INLINE IMG_VOID OSReleaseBridgeLock(IMG_VOID) { } + +#ifdef INLINE_IS_PRAGMA +#pragma inline(OSReacquireBridgeLock) +#endif +static INLINE IMG_VOID OSReacquireBridgeLock(IMG_VOID) { } + +#endif + +#if defined(__linux__) +IMG_VOID OSGetCurrentProcessNameKM(IMG_CHAR *pszName, IMG_UINT32 ui32Size); +#else + +#ifdef INLINE_IS_PRAGMA +#pragma inline(OSGetCurrentProcessNameKM) +#endif +static INLINE IMG_VOID OSGetCurrentProcessNameKM(IMG_CHAR *pszName, IMG_UINT32 ui32Size) +{ + PVR_UNREFERENCED_PARAMETER(pszName); + PVR_UNREFERENCED_PARAMETER(ui32Size); +} + +#endif #if defined (__cplusplus) } #endif -#endif +#endif /* __OSFUNC_H__ */ + +/****************************************************************************** + End of file (osfunc.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/include/osperproc.h b/sgx/services4/srvkm/include/osperproc.h index e5c81da..9c72be0 100644 --- a/sgx/services4/srvkm/include/osperproc.h +++ b/sgx/services4/srvkm/include/osperproc.h @@ -1,29 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title OS specific per process data interface +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description OS specific per process data interface +@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. + +*/ /**************************************************************************/ #ifndef __OSPERPROC_H__ #define __OSPERPROC_H__ @@ -36,7 +52,7 @@ PVRSRV_ERROR OSPerProcessPrivateDataInit(IMG_HANDLE *phOsPrivateData); PVRSRV_ERROR OSPerProcessPrivateDataDeInit(IMG_HANDLE hOsPrivateData); PVRSRV_ERROR OSPerProcessSetHandleOptions(PVRSRV_HANDLE_BASE *psHandleBase); -#else +#else /* defined(__linux__) */ #ifdef INLINE_IS_PRAGMA #pragma inline(OSPerProcessPrivateDataInit) #endif @@ -66,11 +82,14 @@ static INLINE PVRSRV_ERROR OSPerProcessSetHandleOptions(PVRSRV_HANDLE_BASE *psHa return PVRSRV_OK; } -#endif +#endif /* defined(__linux__) */ #if defined (__cplusplus) } #endif -#endif +#endif /* __OSPERPROC_H__ */ +/****************************************************************************** + End of file (osperproc.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/include/pdump_int.h b/sgx/services4/srvkm/include/pdump_int.h index 9f68549..9777f63 100644 --- a/sgx/services4/srvkm/include/pdump_int.h +++ b/sgx/services4/srvkm/include/pdump_int.h @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Parameter dump internal common functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ + #ifndef __PDUMP_INT_H__ #define __PDUMP_INT_H__ @@ -31,22 +48,35 @@ extern "C" { #endif +/* + * This file contains internal pdump utility functions which may be accessed + * from OS-specific code. The header should not be included outside of srvkm + * pdump files. + */ + #if !defined(_UITRON) +/* + * No dbgdriver on uitron, so ignore any common functions for communicating + * with dbgdriver. + */ #include "dbgdrvif.h" +/* Callbacks which are registered with the debug driver. */ IMG_EXPORT IMG_VOID PDumpConnectionNotify(IMG_VOID); -#endif +#endif /* !defined(_UITRON) */ typedef enum { - + /* Continuous writes are always captured in the dbgdrv; the buffer will + * expand if no client/sink process is running. + */ PDUMP_WRITE_MODE_CONTINUOUS = 0, - + /* Last frame capture */ PDUMP_WRITE_MODE_LASTFRAME, - + /* Capture frame, binary data */ PDUMP_WRITE_MODE_BINCM, - + /* Persistent capture, append data to init phase */ PDUMP_WRITE_MODE_PERSISTENT } PDUMP_DDWMODE; @@ -63,5 +93,9 @@ IMG_UINT32 PDumpOSDebugDriverWrite( PDBG_STREAM psStream, #if defined (__cplusplus) } #endif -#endif +#endif /* __PDUMP_INT_H__ */ + +/****************************************************************************** + End of file (pdump_int.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/include/pdump_km.h b/sgx/services4/srvkm/include/pdump_km.h index 418c6d7..97b5e2a 100644 --- a/sgx/services4/srvkm/include/pdump_km.h +++ b/sgx/services4/srvkm/include/pdump_km.h @@ -1,50 +1,76 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ - +/*************************************************************************/ /*! +@Title pdump functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Main APIs for pdump functions +@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. + +*/ /**************************************************************************/ #ifndef _PDUMP_KM_H_ #define _PDUMP_KM_H_ +/* + * Include the OS abstraction APIs + */ #include "pdump_osfunc.h" #if defined(__cplusplus) extern "C" { #endif +/* + * Pull in pdump flags from services include + */ #include "pdump.h" #define PDUMP_PD_UNIQUETAG (IMG_HANDLE)0 #define PDUMP_PT_UNIQUETAG (IMG_HANDLE)0 +/* + * PDump streams (common to all OSes) + */ #define PDUMP_STREAM_PARAM2 0 #define PDUMP_STREAM_SCRIPT2 1 #define PDUMP_STREAM_DRIVERINFO 2 #define PDUMP_NUM_STREAMS 3 #if defined(PDUMP_DEBUG_OUTFILES) +/* counter increments each time debug write is called */ extern IMG_UINT32 g_ui32EveryLineCounter; #endif @@ -114,8 +140,6 @@ extern IMG_UINT32 g_ui32EveryLineCounter; PVRSRV_ERROR PDumpStopInitPhaseKM(IMG_VOID); IMG_IMPORT PVRSRV_ERROR PDumpSetFrameKM(IMG_UINT32 ui32Frame); IMG_IMPORT PVRSRV_ERROR PDumpCommentKM(IMG_CHAR *pszComment, IMG_UINT32 ui32Flags); - - IMG_IMPORT PVRSRV_ERROR PDumpDriverInfoKM(IMG_CHAR *pszString, IMG_UINT32 ui32Flags); PVRSRV_ERROR PDumpRegWithFlagsKM(IMG_CHAR *pszPDumpRegName, @@ -258,7 +282,8 @@ extern IMG_UINT32 g_ui32EveryLineCounter; IMG_UINT32 ui32NumBytes, IMG_UINT32 ui32PageSize, IMG_HANDLE hUniqueTag, - IMG_BOOL bInterleaved); + IMG_BOOL bInterleaved, + IMG_BOOL bSparse); PVRSRV_ERROR PDumpFreePageTable(PVRSRV_DEVICE_IDENTIFIER *psDevID, IMG_HANDLE hOSMemHandle, IMG_CPU_VIRTADDR pvLinAddr, @@ -309,7 +334,7 @@ extern IMG_UINT32 g_ui32EveryLineCounter; IMG_VOID PDumpSuspendKM(IMG_VOID); IMG_VOID PDumpResumeKM(IMG_VOID); - + /* New pdump common functions */ PVRSRV_ERROR PDumpStoreMemToFile(PDUMP_MMU_ATTRIB *psMMUAttrib, IMG_CHAR *pszFileName, IMG_UINT32 ui32FileOffset, @@ -356,7 +381,7 @@ extern IMG_UINT32 g_ui32EveryLineCounter; #define PDUMPRESUME PDumpResumeKM #else - #if (((defined(LINUX) || defined(__QNXNTO__)) || defined(GCC_IA32)) || defined(GCC_ARM)) +#if (((defined(LINUX) || defined(__QNXNTO__)) || defined(GCC_IA32)) || defined(GCC_ARM)) #define PDUMPMEMPOL(args...) #define PDUMPMEM(args...) #define PDUMPMEMPTENTRIES(args...) @@ -410,5 +435,8 @@ extern IMG_UINT32 g_ui32EveryLineCounter; } #endif -#endif +#endif /* _PDUMP_KM_H_ */ +/****************************************************************************** + End of file (pdump_km.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/include/pdump_osfunc.h b/sgx/services4/srvkm/include/pdump_osfunc.h index f3ed914..3bda7df 100644 --- a/sgx/services4/srvkm/include/pdump_osfunc.h +++ b/sgx/services4/srvkm/include/pdump_osfunc.h @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title OS-independent interface to helper functions for pdump +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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 <stdarg.h> @@ -31,12 +47,23 @@ extern "C" { #endif +/* + * Some OSes (WinXP,CE) allocate the string on the stack, but some + * (Linux,Symbian) use a global variable/lock instead. + * Would be good to use the same across all OSes. + * + * A handle is returned which represents IMG_CHAR* type on all OSes except + * Symbian when it represents PDumpState* type. + * + * The allocated buffer length is also returned on OSes where it's + * supported (e.g. Linux). + */ #define MAX_PDUMP_STRING_LENGTH (256) - - - + /* + * Linux + */ #define PDUMP_GET_SCRIPT_STRING() \ IMG_HANDLE hScript; \ IMG_UINT32 ui32MaxLen; \ @@ -69,17 +96,42 @@ extern "C" { eError = PDumpOSGetFilenameString(&pszFileName, &ui32MaxLenFileName);\ if(eError != PVRSRV_OK) return eError; - + /*! + * @name PDumpOSGetScriptString + * @brief Get the "script" buffer + * @param phScript - buffer handle for pdump script + * @param pui32MaxLen - max length of the script buffer + * FIXME: the max length should be internal to the OS-specific code + * @return error (always PVRSRV_OK on some OSes) + */ PVRSRV_ERROR PDumpOSGetScriptString(IMG_HANDLE *phScript, IMG_UINT32 *pui32MaxLen); - + /*! + * @name PDumpOSGetMessageString + * @brief Get the "message" buffer + * @param pszMsg - buffer pointer for pdump messages + * @param pui32MaxLen - max length of the message buffer + * FIXME: the max length should be internal to the OS-specific code + * @return error (always PVRSRV_OK on some OSes) + */ PVRSRV_ERROR PDumpOSGetMessageString(IMG_CHAR **ppszMsg, IMG_UINT32 *pui32MaxLen); - + /*! + * @name PDumpOSGetFilenameString + * @brief Get the "filename" buffer + * @param ppszFile - buffer pointer for filename + * @param pui32MaxLen - max length of the filename buffer + * FIXME: the max length should be internal to the OS-specific code + * @return error (always PVRSRV_OK on some OSes) + */ PVRSRV_ERROR PDumpOSGetFilenameString(IMG_CHAR **ppszFile, IMG_UINT32 *pui32MaxLen); +/* + * Define macro for processing variable args list in OS-independent + * manner. See e.g. PDumpComment(). + */ #define PDUMP_va_list va_list #define PDUMP_va_start va_start @@ -87,37 +139,138 @@ extern "C" { +/*! + * @name PDumpOSGetStream + * @brief Get a handle to the labelled stream (cast the handle to PDBG_STREAM to use it) + * @param ePDumpStream - stream label + */ IMG_HANDLE PDumpOSGetStream(IMG_UINT32 ePDumpStream); +/*! + * @name PDumpOSGetStreamOffset + * @brief Return current offset within the labelled stream + * @param ePDumpStream - stream label + */ IMG_UINT32 PDumpOSGetStreamOffset(IMG_UINT32 ePDumpStream); +/*! + * @name PDumpOSGetParamFileNum + * @brief Return file number of the 'script' stream, in the case that the file was split + * @param ePDumpStream - stream label + */ IMG_UINT32 PDumpOSGetParamFileNum(IMG_VOID); +/*! + * @name PDumpOSCheckForSplitting + * @brief Check if the requested pdump params are too large for a single file + * @param hStream - pdump stream + * @param ui32Size - size of params to dump (bytes) + * @param ui32Flags - pdump flags + */ IMG_VOID PDumpOSCheckForSplitting(IMG_HANDLE hStream, IMG_UINT32 ui32Size, IMG_UINT32 ui32Flags); +/*! + * @name PDumpOSIsSuspended + * @brief Is the pdump stream busy? + * @return IMG_BOOL + */ IMG_BOOL PDumpOSIsSuspended(IMG_VOID); +/*! + * @name PDumpOSIsSuspended + * @brief Is the pdump jump table initialised? + * @return IMG_BOOL + */ IMG_BOOL PDumpOSJTInitialised(IMG_VOID); +/*! + * @name PDumpOSWriteString + * @brief General function for writing to pdump stream. + * Usually more convenient to use PDumpOSWriteString2 below. + * @param hDbgStream - pdump stream handle + * @param psui8Data - data to write + * @param ui32Size - size of write + * @param ui32Flags - pdump flags + * @return error + */ IMG_BOOL PDumpOSWriteString(IMG_HANDLE hDbgStream, IMG_UINT8 *psui8Data, IMG_UINT32 ui32Size, IMG_UINT32 ui32Flags); +/*! + * @name PDumpOSWriteString2 + * @brief Write a string to the "script" output stream + * @param pszScript - buffer to write (ptr to state structure on Symbian) + * @param ui32Flags - pdump flags + * @return error + */ IMG_BOOL PDumpOSWriteString2(IMG_HANDLE hScript, IMG_UINT32 ui32Flags); +/*! + * @name PDumpOSBufprintf + * @brief Printf to OS-specific pdump state buffer + * @param hBuf - buffer handle to write into (ptr to state structure on Symbian) + * @param ui32ScriptSizeMax - maximum size of data to write (not supported on all OSes) + * @param pszFormat - format string + */ PVRSRV_ERROR PDumpOSBufprintf(IMG_HANDLE hBuf, IMG_UINT32 ui32ScriptSizeMax, IMG_CHAR* pszFormat, ...) IMG_FORMAT_PRINTF(3, 4); +/*! + * @name PDumpOSDebugPrintf + * @brief Debug message during pdumping + * @param pszFormat - format string + */ IMG_VOID PDumpOSDebugPrintf(IMG_CHAR* pszFormat, ...) IMG_FORMAT_PRINTF(1, 2); +/* + * FIXME: Is this function useful for Symbian? + * Write into a IMG_CHAR* on all OSes. Can be allocated on the stack or heap. + */ +/*! + * @name PDumpOSSprintf + * @brief Printf to IMG char array + * @param pszComment - char array to print into + * @param pszFormat - format string + */ PVRSRV_ERROR PDumpOSSprintf(IMG_CHAR *pszComment, IMG_UINT32 ui32ScriptSizeMax, IMG_CHAR *pszFormat, ...) IMG_FORMAT_PRINTF(3, 4); +/*! + * @name PDumpOSVSprintf + * @brief Printf to IMG string using variable args (see stdarg.h). This is necessary + * because the ... notation does not support nested function calls. + * @param pszMsg - char array to print into + * @param ui32ScriptSizeMax - maximum size of data to write (not supported on all OSes) + * @param pszFormat - format string + * @param vaArgs - variable args structure (from stdarg.h) + */ PVRSRV_ERROR PDumpOSVSprintf(IMG_CHAR *pszMsg, IMG_UINT32 ui32ScriptSizeMax, IMG_CHAR* pszFormat, PDUMP_va_list vaArgs) IMG_FORMAT_PRINTF(3, 0); +/*! + * @name PDumpOSBuflen + * @param hBuffer - handle to buffer (ptr to state structure on Symbian) + * @param ui32BuffeRSizeMax - max size of buffer (chars) + * @return length of buffer, will always be <= ui32BufferSizeMax + */ IMG_UINT32 PDumpOSBuflen(IMG_HANDLE hBuffer, IMG_UINT32 ui32BufferSizeMax); +/*! + * @name PDumpOSVerifyLineEnding + * @brief Put \r\n sequence at the end if it isn't already there + * @param hBuffer - handle to buffer + * @param ui32BufferSizeMax - max size of buffer (chars) + */ IMG_VOID PDumpOSVerifyLineEnding(IMG_HANDLE hBuffer, IMG_UINT32 ui32BufferSizeMax); +/*! + * @name PDumpOSCPUVAddrToDevPAddr + * @brief OS function to convert CPU virtual to device physical for dumping pages + * @param hOSMemHandle mem allocation handle (used if kernel virtual mem space is limited, e.g. linux) + * @param ui32Offset dword offset into allocation (for use with mem handle, e.g. linux) + * @param pui8LinAddr CPU linear addr (usually a kernel virtual address) + * @param ui32PageSize page size, used for assertion check + * @return psDevPAddr device physical addr + */ IMG_VOID PDumpOSCPUVAddrToDevPAddr(PVRSRV_DEVICE_TYPE eDeviceType, IMG_HANDLE hOSMemHandle, IMG_UINT32 ui32Offset, @@ -125,16 +278,37 @@ IMG_VOID PDumpOSCPUVAddrToDevPAddr(PVRSRV_DEVICE_TYPE eDeviceType, IMG_UINT32 ui32PageSize, IMG_DEV_PHYADDR *psDevPAddr); +/*! + * @name PDumpOSCPUVAddrToPhysPages + * @brief OS function to convert CPU virtual to backing physical pages + * @param hOSMemHandle mem allocation handle (used if kernel virtual mem space is limited, e.g. linux) + * @param ui32Offset offset within mem allocation block + * @param pui8LinAddr CPU linear addr + * @param ui32DataPageMask mask for data page (= data page size -1) + * @return pui32PageOffset CPU page offset (same as device page offset if page sizes equal) + */ IMG_VOID PDumpOSCPUVAddrToPhysPages(IMG_HANDLE hOSMemHandle, IMG_UINT32 ui32Offset, IMG_PUINT8 pui8LinAddr, IMG_UINT32 ui32DataPageMask, IMG_UINT32 *pui32PageOffset); +/*! + * @name PDumpOSReleaseExecution + * @brief OS function to switch to another process, to clear pdump buffers + */ IMG_VOID PDumpOSReleaseExecution(IMG_VOID); +/*! + * @name PDumpOSIsCaptureFrameKM + * @brief Is the current frame a capture frame? + */ IMG_BOOL PDumpOSIsCaptureFrameKM(IMG_VOID); +/*! + * @name PDumpOSSetFrameKM + * @brief Set frame counter + */ PVRSRV_ERROR PDumpOSSetFrameKM(IMG_UINT32 ui32Frame); #if defined (__cplusplus) diff --git a/sgx/services4/srvkm/include/perfkm.h b/sgx/services4/srvkm/include/perfkm.h new file mode 100644 index 0000000..719b61d --- /dev/null +++ b/sgx/services4/srvkm/include/perfkm.h @@ -0,0 +1,59 @@ +/*************************************************************************/ /*! +@Title Vista-specific Perf initialisation +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ +#ifndef _PERFKM_H_ +#define _PERFKM_H_ + +#include "img_types.h" + +/* + * Note, WDDM needs to perform initialisation and deinitialisation + * in order to support HW performance measurement. Other platforms + * should not need to do anything in these functions. + */ +#define PERFINIT() +#define PERFDEINIT() + +#endif /* _PERFKM_H_ */ + +/****************************************************************************** + End of file (perfkm.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/include/perproc.h b/sgx/services4/srvkm/include/perproc.h index 842680c..d7a7a11 100644 --- a/sgx/services4/srvkm/include/perproc.h +++ b/sgx/services4/srvkm/include/perproc.h @@ -1,29 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ - +/*************************************************************************/ /*! +@Title Handle Manager API +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Perprocess data +@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. + +*/ /**************************************************************************/ #ifndef __PERPROC_H__ #define __PERPROC_H__ @@ -48,27 +64,33 @@ typedef struct _PVRSRV_PER_PROCESS_DATA_ #endif PVRSRV_HANDLE_BASE *psHandleBase; #if defined (SUPPORT_SID_INTERFACE) - + /* Handles are being allocated in batches */ IMG_BOOL bHandlesBatched; #else #if defined (PVR_SECURE_HANDLES) - + /* Handles are being allocated in batches */ IMG_BOOL bHandlesBatched; -#endif -#endif +#endif /* PVR_SECURE_HANDLES */ +#endif /* SUPPORT_SID_INTERFACE */ IMG_UINT32 ui32RefCount; - + /* True if the process is the initialisation server. */ IMG_BOOL bInitProcess; #if defined(PDUMP) - + /* True if pdump data from the process is 'persistent' */ IMG_BOOL bPDumpPersistent; #if defined(SUPPORT_PDUMP_MULTI_PROCESS) - + /* True if this process is marked for pdumping. This flag is + * significant in a multi-app environment. + */ IMG_BOOL bPDumpActive; -#endif +#endif /* SUPPORT_PDUMP_MULTI_PROCESS */ #endif - + /* + * OS specific data can be stored via this handle. + * See osperproc.h for a generic mechanism for initialising + * this field. + */ IMG_HANDLE hOsPrivateData; } PVRSRV_PER_PROCESS_DATA; @@ -122,5 +144,8 @@ IMG_HANDLE PVRSRVFindPerProcessPrivateData(IMG_VOID) } #endif -#endif +#endif /* __PERPROC_H__ */ +/****************************************************************************** + End of file (perproc.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/include/power.h b/sgx/services4/srvkm/include/power.h index 9e3dcc4..eb05e2c 100644 --- a/sgx/services4/srvkm/include/power.h +++ b/sgx/services4/srvkm/include/power.h @@ -1,29 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ - +/*************************************************************************/ /*! +@Title Power Management Functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Main APIs for power management functions +@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. + +*/ /**************************************************************************/ #ifndef POWER_H #define POWER_H @@ -32,6 +48,10 @@ extern "C" { #endif +/*! + ***************************************************************************** + * Power management + *****************************************************************************/ typedef struct _PVRSRV_POWER_DEV_TAG_ { @@ -75,9 +95,7 @@ IMG_VOID PVRSRVPowerUnlock(IMG_UINT32 ui32CallerID); IMG_IMPORT PVRSRV_ERROR PVRSRVSetDevicePowerStateKM(IMG_UINT32 ui32DeviceIndex, - PVRSRV_DEV_POWER_STATE eNewPowerState, - IMG_UINT32 ui32CallerID, - IMG_BOOL bRetainMutex); + PVRSRV_DEV_POWER_STATE eNewPowerState); IMG_IMPORT PVRSRV_ERROR PVRSRVSystemPrePowerStateKM(PVRSRV_SYS_POWER_STATE eNewPowerState); @@ -116,5 +134,8 @@ IMG_VOID PVRSRVDevicePostClockSpeedChange(IMG_UINT32 ui32DeviceIndex, #if defined (__cplusplus) } #endif -#endif +#endif /* POWER_H */ +/****************************************************************************** + End of file (power.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/include/queue.h b/sgx/services4/srvkm/include/queue.h index ab89527..266cc81 100644 --- a/sgx/services4/srvkm/include/queue.h +++ b/sgx/services4/srvkm/include/queue.h @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Command Queue API +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Internal structures and definitions for command queues +@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. + +*/ /**************************************************************************/ #ifndef QUEUE_H #define QUEUE_H @@ -32,19 +49,33 @@ extern "C" { #endif +/*! + * Macro to Read Offset in given command queue + */ #define UPDATE_QUEUE_ROFF(psQueue, ui32Size) \ (psQueue)->ui32ReadOffset = ((psQueue)->ui32ReadOffset + (ui32Size)) \ & ((psQueue)->ui32QueueSize - 1); +/*! + generic cmd complete structure. + This structure represents the storage required between starting and finishing + a given cmd and is required to hold the generic sync object update data. + note: for any given system we know what command types we support and + therefore how much storage is required for any number of commands in progress + */ typedef struct _COMMAND_COMPLETE_DATA_ { IMG_BOOL bInUse; - - IMG_UINT32 ui32DstSyncCount; - IMG_UINT32 ui32SrcSyncCount; - PVRSRV_SYNC_OBJECT *psDstSync; - PVRSRV_SYNC_OBJECT *psSrcSync; - IMG_UINT32 ui32AllocSize; + /* <arg(s) to PVRSRVProcessQueues>; */ /*!< TBD */ + IMG_UINT32 ui32DstSyncCount; /*!< number of dst sync objects */ + IMG_UINT32 ui32SrcSyncCount; /*!< number of src sync objects */ + PVRSRV_SYNC_OBJECT *psDstSync; /*!< dst sync ptr list, + allocated on back of this structure */ + PVRSRV_SYNC_OBJECT *psSrcSync; /*!< src sync ptr list, + allocated on back of this structure */ + IMG_UINT32 ui32AllocSize; /*!< allocated size*/ + PFN_QUEUE_COMMAND_COMPLETE pfnCommandComplete; /*!< Command complete callback */ + IMG_HANDLE hCallbackData; /*!< Command complete callback data */ }COMMAND_COMPLETE_DATA, *PCOMMAND_COMPLETE_DATA; #if !defined(USE_CODE) @@ -76,7 +107,9 @@ PVRSRV_ERROR IMG_CALLCONV PVRSRVInsertCommandKM(PVRSRV_QUEUE_INFO *psQueue, PVRSRV_KERNEL_SYNC_INFO *apsDstSync[], IMG_UINT32 ui32SrcSyncCount, PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[], - IMG_SIZE_T ui32DataByteSize ); + IMG_SIZE_T ui32DataByteSize, + PFN_QUEUE_COMMAND_COMPLETE pfnCommandComplete, + IMG_HANDLE hCallbackData); IMG_IMPORT PVRSRV_ERROR IMG_CALLCONV PVRSRVGetQueueSpaceKM(PVRSRV_QUEUE_INFO *psQueue, @@ -99,12 +132,15 @@ IMG_IMPORT PVRSRV_ERROR PVRSRVRemoveCmdProcListKM(IMG_UINT32 ui32DevIndex, IMG_UINT32 ui32CmdCount); -#endif +#endif /* !defined(USE_CODE) */ #if defined (__cplusplus) } #endif -#endif +#endif /* QUEUE_H */ +/****************************************************************************** + End of file (queue.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/include/ra.h b/sgx/services4/srvkm/include/ra.h index db141f6..b6bd587 100644 --- a/sgx/services4/srvkm/include/ra.h +++ b/sgx/services4/srvkm/include/ra.h @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Resource Allocator API +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #ifndef _RA_H_ #define _RA_H_ @@ -31,41 +47,46 @@ #include "hash.h" #include "osfunc.h" -typedef struct _RA_ARENA_ RA_ARENA; +/** Resource arena. + * struct _RA_ARENA_ deliberately opaque + */ +typedef struct _RA_ARENA_ RA_ARENA; //PRQA S 3313 typedef struct _BM_MAPPING_ BM_MAPPING; +/** Enable support for arena statistics. */ #define RA_STATS +/** Resource arena statistics. */ struct _RA_STATISTICS_ { - + /** total number of segments add to the arena */ IMG_SIZE_T uSpanCount; - + /** number of current live segments within the arena */ IMG_SIZE_T uLiveSegmentCount; - + /** number of current free segments within the arena */ IMG_SIZE_T uFreeSegmentCount; - + /** total number of resource within the arena */ IMG_SIZE_T uTotalResourceCount; - + /** number of free resource within the arena */ IMG_SIZE_T uFreeResourceCount; - + /** total number of resources allocated from the arena */ IMG_SIZE_T uCumulativeAllocs; - + /** total number of resources returned to the arena */ IMG_SIZE_T uCumulativeFrees; - + /** total number of spans allocated by the callback mechanism */ IMG_SIZE_T uImportCount; - + /** total number of spans deallocated by the callback mechanism */ IMG_SIZE_T uExportCount; }; typedef struct _RA_STATISTICS_ RA_STATISTICS; @@ -78,6 +99,23 @@ struct _RA_SEGMENT_DETAILS_ }; typedef struct _RA_SEGMENT_DETAILS_ RA_SEGMENT_DETAILS; +/** + * @Function RA_Create + * + * @Description + * + * To create a resource arena. + * + * @Input name - the name of the arena for diagnostic purposes. + * @Input base - the base of an initial resource span or 0. + * @Input uSize - the size of an initial resource span or 0. + * @Input pRef - the reference to return for the initial resource or 0. + * @Input uQuantum - the arena allocation quantum. + * @Input alloc - a resource allocation callback or 0. + * @Input free - a resource de-allocation callback or 0. + * @Input import_handle - handle passed to alloc and free or 0. + * @Return arena handle, or IMG_NULL. + */ RA_ARENA * RA_Create (IMG_CHAR *name, IMG_UINTPTR_T base, @@ -89,6 +127,8 @@ RA_Create (IMG_CHAR *name, IMG_SIZE_T *pActualSize, BM_MAPPING **ppsMapping, IMG_UINT32 uFlags, + IMG_PVOID pvPrivData, + IMG_UINT32 ui32PrivDataLength, IMG_UINTPTR_T *pBase), IMG_VOID (*imp_free) (IMG_VOID *, IMG_UINTPTR_T, @@ -99,15 +139,73 @@ RA_Create (IMG_CHAR *name, IMG_HANDLE), IMG_VOID *import_handle); +/** + * @Function RA_Delete + * + * @Description + * + * To delete a resource arena. All resources allocated from the arena + * must be freed before deleting the arena. + * + * @Input pArena - the arena to delete. + * @Return None + */ IMG_VOID RA_Delete (RA_ARENA *pArena); +/** + * @Function RA_TestDelete + * + * @Description + * + * To test whether it is safe to delete a resource arena. If any allocations + * have not been freed, the RA must not be deleted. + * + * @Input pArena - the arena to test. + * @Return IMG_BOOL - IMG_TRUE if is safe to go on and call RA_Delete. + */ IMG_BOOL RA_TestDelete (RA_ARENA *pArena); +/** + * @Function RA_Add + * + * @Description + * + * To add a resource span to an arena. The span must not overlap with + * any span previously added to the arena. + * + * @Input pArena - the arena to add a span into. + * @Input base - the base of the span. + * @Input uSize - the extent of the span. + * @Return IMG_TRUE - success, IMG_FALSE - failure + */ IMG_BOOL RA_Add (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize); +/** + * @Function RA_Alloc + * + * @Description + * + * To allocate resource from an arena. + * + * @Input pArena - the arena + * @Input uRequestSize - the size of resource segment requested. + * @Output pActualSize - the actual_size of resource segment allocated, + * typcially rounded up by quantum. + * @Output ppsMapping - the user reference associated with allocated + * resource span. + * @Input uFlags - flags influencing allocation policy. + * @Input uAlignment - the alignment constraint required for the + * allocated segment, use 0 if alignment not required. + * @Input uAlignmentOffset - the required alignment offset + * @Input pvPrivData - private data passed to OS allocator + * @Input ui32PrivData - length of private data + * + * @Output pBase - allocated base resource + * @Return IMG_TRUE - success, IMG_FALSE - failure + */ IMG_BOOL RA_Alloc (RA_ARENA *pArena, IMG_SIZE_T uSize, @@ -116,8 +214,21 @@ RA_Alloc (RA_ARENA *pArena, IMG_UINT32 uFlags, IMG_UINT32 uAlignment, IMG_UINT32 uAlignmentOffset, + IMG_PVOID pvPrivData, + IMG_UINT32 ui32PrivDataLength, IMG_UINTPTR_T *pBase); +/** + * @Function RA_Free + * + * @Description To free a resource segment. + * + * @Input pArena - the arena the segment was originally allocated from. + * @Input base - the base of the resource span to free. + * @Input bFreeBackingStore - Should backing store memory be freed? + * + * @Return None + */ IMG_VOID RA_Free (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_BOOL bFreeBackingStore); @@ -142,9 +253,30 @@ RA_Free (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_BOOL bFreeBackingStore); } +/** + * @Function RA_GetNextLiveSegment + * + * @Description Returns details of the next live resource segments + * + * @Input pArena - the arena the segment was originally allocated from. + * @Output psSegDetails - rtn details of segments + * + * @Return IMG_TRUE if operation succeeded + */ IMG_BOOL RA_GetNextLiveSegment(IMG_HANDLE hArena, RA_SEGMENT_DETAILS *psSegDetails); +/** + * @Function RA_GetStats + * + * @Description gets stats on a given arena + * + * @Input pArena - the arena the segment was originally allocated from. + * @Input ppszStr - string to write stats to + * @Input pui32StrLen - length of string + * + * @Return PVRSRV_ERROR + */ PVRSRV_ERROR RA_GetStats(RA_ARENA *pArena, IMG_CHAR **ppszStr, IMG_UINT32 *pui32StrLen); @@ -153,7 +285,7 @@ PVRSRV_ERROR RA_GetStatsFreeMem(RA_ARENA *pArena, IMG_CHAR **ppszStr, IMG_UINT32 *pui32StrLen); -#endif +#endif /* #ifdef RA_STATS */ #endif diff --git a/sgx/services4/srvkm/include/refcount.h b/sgx/services4/srvkm/include/refcount.h new file mode 100644 index 0000000..73f6780 --- /dev/null +++ b/sgx/services4/srvkm/include/refcount.h @@ -0,0 +1,204 @@ +/*************************************************************************/ /*! +@Title Services reference count debugging +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ + +#ifndef __REFCOUNT_H__ +#define __REFCOUNT_H__ + +#include "pvr_bridge_km.h" + +#if defined(PVRSRV_REFCOUNT_DEBUG) + +void PVRSRVDumpRefCountCCB(void); + +#define PVRSRVKernelSyncInfoIncRef(x...) \ + PVRSRVKernelSyncInfoIncRef2(__FILE__, __LINE__, x) +#define PVRSRVKernelSyncInfoDecRef(x...) \ + PVRSRVKernelSyncInfoDecRef2(__FILE__, __LINE__, x) +#define PVRSRVKernelMemInfoIncRef(x...) \ + PVRSRVKernelMemInfoIncRef2(__FILE__, __LINE__, x) +#define PVRSRVKernelMemInfoDecRef(x...) \ + PVRSRVKernelMemInfoDecRef2(__FILE__, __LINE__, x) +#define PVRSRVBMBufIncRef(x...) \ + PVRSRVBMBufIncRef2(__FILE__, __LINE__, x) +#define PVRSRVBMBufDecRef(x...) \ + PVRSRVBMBufDecRef2(__FILE__, __LINE__, x) +#define PVRSRVBMBufIncExport(x...) \ + PVRSRVBMBufIncExport2(__FILE__, __LINE__, x) +#define PVRSRVBMBufDecExport(x...) \ + PVRSRVBMBufDecExport2(__FILE__, __LINE__, x) + +void PVRSRVKernelSyncInfoIncRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo, + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo); +void PVRSRVKernelSyncInfoDecRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo, + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo); +void PVRSRVKernelMemInfoIncRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo); +void PVRSRVKernelMemInfoDecRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo); +void PVRSRVBMBufIncRef2(const IMG_CHAR *pszFile, + IMG_INT iLine, BM_BUF *pBuf); +void PVRSRVBMBufDecRef2(const IMG_CHAR *pszFile, + IMG_INT iLine, BM_BUF *pBuf); +void PVRSRVBMBufIncExport2(const IMG_CHAR *pszFile, + IMG_INT iLine, BM_BUF *pBuf); +void PVRSRVBMBufDecExport2(const IMG_CHAR *pszFile, + IMG_INT iLine, BM_BUF *pBuf); +void PVRSRVBMXProcIncRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + IMG_UINT32 ui32Index); +void PVRSRVBMXProcDecRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + IMG_UINT32 ui32Index); + +#if defined(__linux__) + +/* mmap refcounting is Linux specific */ +#include "mmap.h" + +#define PVRSRVOffsetStructIncRef(x...) \ + PVRSRVOffsetStructIncRef2(__FILE__, __LINE__, x) +#define PVRSRVOffsetStructDecRef(x...) \ + PVRSRVOffsetStructDecRef2(__FILE__, __LINE__, x) +#define PVRSRVOffsetStructIncMapped(x...) \ + PVRSRVOffsetStructIncMapped2(__FILE__, __LINE__, x) +#define PVRSRVOffsetStructDecMapped(x...) \ + PVRSRVOffsetStructDecMapped2(__FILE__, __LINE__, x) + +void PVRSRVOffsetStructIncRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + PKV_OFFSET_STRUCT psOffsetStruct); +void PVRSRVOffsetStructDecRef2(const IMG_CHAR *pszFile, IMG_INT iLine, + PKV_OFFSET_STRUCT psOffsetStruct); +void PVRSRVOffsetStructIncMapped2(const IMG_CHAR *pszFile, IMG_INT iLine, + PKV_OFFSET_STRUCT psOffsetStruct); +void PVRSRVOffsetStructDecMapped2(const IMG_CHAR *pszFile, IMG_INT iLine, + PKV_OFFSET_STRUCT psOffsetStruct); + +#endif /* defined(__linux__) */ + +#else /* defined(PVRSRV_REFCOUNT_DEBUG) */ + +static INLINE void PVRSRVDumpRefCountCCB(void) { } + +static INLINE void PVRSRVKernelSyncInfoIncRef(PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo, + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo) +{ + PVR_UNREFERENCED_PARAMETER(psKernelMemInfo); + PVRSRVAcquireSyncInfoKM(psKernelSyncInfo); +} + +static INLINE void PVRSRVKernelSyncInfoDecRef(PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo, + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo) +{ + PVR_UNREFERENCED_PARAMETER(psKernelMemInfo); + PVRSRVReleaseSyncInfoKM(psKernelSyncInfo); +} + +static INLINE void PVRSRVKernelMemInfoIncRef(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo) +{ + psKernelMemInfo->ui32RefCount++; +} + +static INLINE void PVRSRVKernelMemInfoDecRef(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo) +{ + psKernelMemInfo->ui32RefCount--; +} + +static INLINE void PVRSRVBMBufIncRef(BM_BUF *pBuf) +{ + pBuf->ui32RefCount++; +} + +static INLINE void PVRSRVBMBufDecRef(BM_BUF *pBuf) +{ + pBuf->ui32RefCount--; +} + +static INLINE void PVRSRVBMBufIncExport(BM_BUF *pBuf) +{ + pBuf->ui32ExportCount++; +} + +static INLINE void PVRSRVBMBufDecExport(BM_BUF *pBuf) +{ + pBuf->ui32ExportCount--; +} + +static INLINE void PVRSRVBMXProcIncRef(IMG_UINT32 ui32Index) +{ + gXProcWorkaroundShareData[ui32Index].ui32RefCount++; +} + +static INLINE void PVRSRVBMXProcDecRef(IMG_UINT32 ui32Index) +{ + gXProcWorkaroundShareData[ui32Index].ui32RefCount--; +} + +#if defined(__linux__) + +/* mmap refcounting is Linux specific */ +#include "mmap.h" + +static INLINE void PVRSRVOffsetStructIncRef(PKV_OFFSET_STRUCT psOffsetStruct) +{ + psOffsetStruct->ui32RefCount++; +} + +static INLINE void PVRSRVOffsetStructDecRef(PKV_OFFSET_STRUCT psOffsetStruct) +{ + psOffsetStruct->ui32RefCount--; +} + +static INLINE void PVRSRVOffsetStructIncMapped(PKV_OFFSET_STRUCT psOffsetStruct) +{ + psOffsetStruct->ui32Mapped++; +} + +static INLINE void PVRSRVOffsetStructDecMapped(PKV_OFFSET_STRUCT psOffsetStruct) +{ + psOffsetStruct->ui32Mapped--; +} + +#endif /* defined(__linux__) */ + +#endif /* defined(PVRSRV_REFCOUNT_DEBUG) */ + +#endif /* __REFCOUNT_H__ */ diff --git a/sgx/services4/srvkm/include/resman.h b/sgx/services4/srvkm/include/resman.h index 648e490..6c9b93e 100644 --- a/sgx/services4/srvkm/include/resman.h +++ b/sgx/services4/srvkm/include/resman.h @@ -1,28 +1,45 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Resource Manager API +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Provide resource management +@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. + +*/ /**************************************************************************/ #ifndef __RESMAN_H__ #define __RESMAN_H__ @@ -31,56 +48,70 @@ extern "C" { #endif -enum { - - RESMAN_TYPE_SHARED_PB_DESC = 1, - RESMAN_TYPE_SHARED_PB_DESC_CREATE_LOCK, - RESMAN_TYPE_HW_RENDER_CONTEXT, - RESMAN_TYPE_HW_TRANSFER_CONTEXT, - RESMAN_TYPE_HW_2D_CONTEXT, - RESMAN_TYPE_TRANSFER_CONTEXT, - - - RESMAN_TYPE_DMA_CLIENT_FIFO_DATA, - - - - - - RESMAN_TYPE_DISPLAYCLASS_SWAPCHAIN_REF, - RESMAN_TYPE_DISPLAYCLASS_DEVICE, +/****************************************************************************** + * resman definitions + *****************************************************************************/ +enum { + /* SGX: */ + RESMAN_TYPE_SHARED_PB_DESC = 1, /*!< Parameter buffer kernel stubs */ + RESMAN_TYPE_SHARED_PB_DESC_CREATE_LOCK, /*!< Shared parameter buffer creation lock */ + RESMAN_TYPE_HW_RENDER_CONTEXT, /*!< Hardware Render Context Resource */ + RESMAN_TYPE_HW_TRANSFER_CONTEXT, /*!< Hardware transfer Context Resource */ + RESMAN_TYPE_HW_2D_CONTEXT, /*!< Hardware 2D Context Resource */ + RESMAN_TYPE_TRANSFER_CONTEXT, /*!< Transfer Queue context */ + + /* VGX: */ + RESMAN_TYPE_DMA_CLIENT_FIFO_DATA, /*!< VGX DMA Client FIFO data */ + + /* DISPLAY CLASS: */ + RESMAN_TYPE_DISPLAYCLASS_SWAPCHAIN_REF, /*!< Display Class Swapchain Reference Resource */ + RESMAN_TYPE_DISPLAYCLASS_DEVICE, /*!< Display Class Device Resource */ + + /* BUFFER CLASS: */ + RESMAN_TYPE_BUFFERCLASS_DEVICE, /*!< Buffer Class Device Resource */ - RESMAN_TYPE_BUFFERCLASS_DEVICE, - - - RESMAN_TYPE_OS_USERMODE_MAPPING, - - - RESMAN_TYPE_DEVICEMEM_CONTEXT, - RESMAN_TYPE_DEVICECLASSMEM_MAPPING, - RESMAN_TYPE_DEVICEMEM_MAPPING, - RESMAN_TYPE_DEVICEMEM_WRAP, - RESMAN_TYPE_DEVICEMEM_ALLOCATION, - RESMAN_TYPE_EVENT_OBJECT, - RESMAN_TYPE_SHARED_MEM_INFO, - RESMAN_TYPE_MODIFY_SYNC_OPS, - RESMAN_TYPE_SYNC_INFO, + /* OS specific User mode Mappings: */ + RESMAN_TYPE_OS_USERMODE_MAPPING, /*!< OS specific User mode mappings */ + /* COMMON: */ + RESMAN_TYPE_DEVICEMEM_CONTEXT, /*!< Device Memory Context Resource */ + RESMAN_TYPE_DEVICECLASSMEM_MAPPING, /*!< Device Memory Mapping Resource */ + RESMAN_TYPE_DEVICEMEM_MAPPING, /*!< Device Memory Mapping Resource */ + RESMAN_TYPE_DEVICEMEM_WRAP, /*!< Device Memory Wrap Resource */ + RESMAN_TYPE_DEVICEMEM_ALLOCATION, /*!< Device Memory Allocation Resource */ + RESMAN_TYPE_DEVICEMEM_ION, /*!< Device Memory Ion Resource */ + RESMAN_TYPE_EVENT_OBJECT, /*!< Event Object */ + RESMAN_TYPE_SHARED_MEM_INFO, /*!< Shared system memory meminfo */ + RESMAN_TYPE_MODIFY_SYNC_OPS, /*!< Syncobject synchronisation Resource*/ + RESMAN_TYPE_SYNC_INFO, /*!< Syncobject Resource*/ - RESMAN_TYPE_KERNEL_DEVICEMEM_ALLOCATION + /* KERNEL: */ + RESMAN_TYPE_KERNEL_DEVICEMEM_ALLOCATION /*!< Device Memory Allocation Resource */ }; -#define RESMAN_CRITERIA_ALL 0x00000000 -#define RESMAN_CRITERIA_RESTYPE 0x00000001 -#define RESMAN_CRITERIA_PVOID_PARAM 0x00000002 -#define RESMAN_CRITERIA_UI32_PARAM 0x00000004 +#define RESMAN_CRITERIA_ALL 0x00000000 /*!< match by criteria all */ +#define RESMAN_CRITERIA_RESTYPE 0x00000001 /*!< match by criteria type */ +#define RESMAN_CRITERIA_PVOID_PARAM 0x00000002 /*!< match by criteria param1 */ +#define RESMAN_CRITERIA_UI32_PARAM 0x00000004 /*!< match by criteria param2 */ typedef PVRSRV_ERROR (*RESMAN_FREE_FN)(IMG_PVOID pvParam, IMG_UINT32 ui32Param, IMG_BOOL bForceCleanup); typedef struct _RESMAN_ITEM_ *PRESMAN_ITEM; typedef struct _RESMAN_CONTEXT_ *PRESMAN_CONTEXT; +/****************************************************************************** + * resman functions + *****************************************************************************/ + +/* + Note: + Resource cleanup can fail with retry in which case we don't remove + it from resman's list and either UM or KM will try to release the + resource at a later date (and will keep trying until a non-retry + error is returned) +*/ + PVRSRV_ERROR ResManInit(IMG_VOID); IMG_VOID ResManDeInit(IMG_VOID); @@ -114,5 +145,9 @@ IMG_VOID PVRSRVResManDisconnect(PRESMAN_CONTEXT hResManContext, } #endif -#endif +#endif /* __RESMAN_H__ */ + +/****************************************************************************** + End of file (resman.h) +******************************************************************************/ diff --git a/sgx/services4/srvkm/include/services_headers.h b/sgx/services4/srvkm/include/services_headers.h index 2b5f197..30a4b23 100644 --- a/sgx/services4/srvkm/include/services_headers.h +++ b/sgx/services4/srvkm/include/services_headers.h @@ -1,28 +1,47 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Command queues and synchronisation +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Internal structures and definitions for command queues and + synchronisation +@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. + +*/ /**************************************************************************/ + #ifndef SERVICES_HEADERS_H #define SERVICES_HEADERS_H @@ -44,6 +63,7 @@ #include "pvr_debug.h" #include "metrics.h" #include "osfunc.h" +#include "refcount.h" -#endif +#endif /* SERVICES_HEADERS_H */ diff --git a/sgx/services4/srvkm/include/srvkm.h b/sgx/services4/srvkm/include/srvkm.h index 474a1ee..14828bd 100644 --- a/sgx/services4/srvkm/include/srvkm.h +++ b/sgx/services4/srvkm/include/srvkm.h @@ -1,28 +1,44 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Services kernel module internal header file +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@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. + +*/ /**************************************************************************/ #ifndef SRVKM_H #define SRVKM_H @@ -32,11 +48,12 @@ extern "C" { #endif - + /** Use PVR_DPF() unless message is necessary in release build + */ #ifdef PVR_DISABLE_LOGGING #define PVR_LOG(X) #else - + /* PRQA S 3410 1 */ /* this macro requires no brackets in order to work */ #define PVR_LOG(X) PVRSRVReleasePrintf X; #endif @@ -58,7 +75,34 @@ extern "C" { } #endif - +/****************** +HIGHER LEVEL MACROS +*******************/ + +/*---------------------------------------------------------------------------- +Repeats the body of the loop for a certain minimum time, or until the body +exits by its own means (break, return, goto, etc.) + +Example of usage: + +LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) +{ + if(psQueueInfo->ui32ReadOffset == psQueueInfo->ui32WriteOffset) + { + bTimeout = IMG_FALSE; + break; + } + + OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT); +} END_LOOP_UNTIL_TIMEOUT(); + +-----------------------------------------------------------------------------*/ + +/* uiNotLastLoop will remain at 1 until the timeout has expired, at which time + * it will be decremented and the loop executed one final time. This is necessary + * when preemption is enabled. + */ +/* PRQA S 3411,3431 12 */ /* critical format, leave alone */ #define LOOP_UNTIL_TIMEOUT(TIMEOUT) \ {\ IMG_UINT32 uiOffset, uiStart, uiCurrent; \ @@ -72,7 +116,15 @@ extern "C" { #define END_LOOP_UNTIL_TIMEOUT() \ } +/*! + ****************************************************************************** + + @Function PVRSRVGetErrorStringKM + + @Description Returns a text string relating to the PVRSRV_ERROR enum. + + ******************************************************************************/ IMG_IMPORT const IMG_CHAR *PVRSRVGetErrorStringKM(PVRSRV_ERROR eError); -#endif +#endif /* SRVKM_H */ diff --git a/sgx/services4/srvkm/include/ttrace.h b/sgx/services4/srvkm/include/ttrace.h index 9e04b88..d073b7c 100644 --- a/sgx/services4/srvkm/include/ttrace.h +++ b/sgx/services4/srvkm/include/ttrace.h @@ -1,29 +1,46 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ - +/*************************************************************************/ /*! +@Title Timed Trace header +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Timed Trace header. Contines structures and functions used + in the timed trace subsystem. +@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 "services_headers.h" #include "ttrace_common.h" #include "ttrace_tokens.h" @@ -147,7 +164,7 @@ static INLINE IMG_VOID PVRSRVTimeTraceSysPhysAddr(IMG_UINT32 ui32Group, IMG_UINT 1, (IMG_UINT8 *) &psPAddr.uiAddr); } -#else +#else /* defined(PVRSRV_NEED_PVR_TIME_TRACE) */ #define PVR_TTRACE(group, class, token) \ ((void) 0) @@ -170,7 +187,7 @@ static INLINE IMG_VOID PVRSRVTimeTraceSysPhysAddr(IMG_UINT32 ui32Group, IMG_UINT #define PVR_TTRACE_SYNC_OBJECT(group, token, syncobj, op) \ ((void) 0) -#endif +#endif /* defined(PVRSRV_NEED_PVR_TIME_TRACE) */ IMG_IMPORT PVRSRV_ERROR PVRSRVTimeTraceInit(IMG_VOID); IMG_IMPORT IMG_VOID PVRSRVTimeTraceDeinit(IMG_VOID); @@ -181,4 +198,4 @@ IMG_IMPORT PVRSRV_ERROR PVRSRVTimeTraceBufferCreate(IMG_UINT32 ui32PID); IMG_IMPORT PVRSRV_ERROR PVRSRVTimeTraceBufferDestroy(IMG_UINT32 ui32PID); IMG_IMPORT IMG_VOID PVRSRVDumpTimeTraceBuffers(IMG_VOID); -#endif +#endif /* __TTRACE_H__ */ diff --git a/sgx/services4/srvkm/include/ttrace_common.h b/sgx/services4/srvkm/include/ttrace_common.h index 5895b6c..3e8b763 100644 --- a/sgx/services4/srvkm/include/ttrace_common.h +++ b/sgx/services4/srvkm/include/ttrace_common.h @@ -1,34 +1,96 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Timed Trace header +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Timed Trace common header. Contains shared defines and + structures which are shared with the post processing tool. +@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 "img_types.h" #ifndef __TTRACE_COMMON_H__ #define __TTRACE_COMMON_H__ +/* + * Trace item + * ========== + * + * A trace item contains a trace header, a timestamp, a UID and a + * data header all of which are 32-bit and mandatory. If there + * is no data then the data header size is set to 0. + * + * Trace header + * ------------ + * 31 27 23 19 15 11 7 3 + * GGGG GGGG CCCC CCCC TTTT TTTT TTTT TTTT + * + * G = group + * Note: + * Group 0xff means the message is padding + * + * C = class + * T = Token + * + * Data header + *----------- + * 31 27 23 19 15 11 7 3 + * SSSS SSSS SSSS SSSS TTTT CCCC CCCC CCCC + * + * S = data packet size + * T = Type + * 0000 - 8 bit + * 0001 - 16 bit + * 0010 - 32 bit + * 0011 - 64 bit + * + * C = data item count + * + * Note: It might look strange having both the packet + * size and the data item count, but the idea + * is the you might have a "special" data type + * who's size might not be known by the post + * processing program and rather then fail + * processing the buffer after that point if we + * know the size we can just skip it and move to + * the next item. + */ + + #define PVRSRV_TRACE_HEADER 0 #define PVRSRV_TRACE_TIMESTAMP 1 #define PVRSRV_TRACE_HOSTUID 2 @@ -62,6 +124,7 @@ #define TIME_TRACE_BUFFER_SIZE 4096 +/* Type defines for trace items */ #define PVRSRV_TRACE_TYPE_UI8 0 #define PVRSRV_TRACE_TYPE_UI16 1 #define PVRSRV_TRACE_TYPE_UI32 2 @@ -76,6 +139,9 @@ #define PVRSRV_TRACE_SYNC_WO_DEV_VADDR 5 #define PVRSRV_TRACE_SYNC_RO_DEV_VADDR 6 #define PVRSRV_TRACE_SYNC_OP 7 -#define PVRSRV_TRACE_TYPE_SYNC_SIZE ((PVRSRV_TRACE_SYNC_OP + 1) * sizeof(IMG_UINT32)) + #define PVRSRV_TRACE_SYNC_RO2P 8 + #define PVRSRV_TRACE_SYNC_RO2C 9 + #define PVRSRV_TRACE_SYNC_RO2_DEV_VADDR 10 +#define PVRSRV_TRACE_TYPE_SYNC_SIZE ((PVRSRV_TRACE_SYNC_RO2_DEV_VADDR + 1) * sizeof(IMG_UINT32)) -#endif +#endif /* __TTRACE_COMMON_H__*/ diff --git a/sgx/services4/srvkm/include/ttrace_tokens.h b/sgx/services4/srvkm/include/ttrace_tokens.h index 21ea5fb..73323ad 100644 --- a/sgx/services4/srvkm/include/ttrace_tokens.h +++ b/sgx/services4/srvkm/include/ttrace_tokens.h @@ -1,32 +1,53 @@ -/********************************************************************** - * - * Copyright (C) Imagination Technologies Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * Imagination Technologies Ltd. <gpl-support@imgtec.com> - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK - * - ******************************************************************************/ +/*************************************************************************/ /*! +@Title Timed Trace header +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Timed Trace token header. Contains defines for all the tokens + used. +@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. + +*/ /**************************************************************************/ #ifndef __TTRACE_TOKENS_H__ #define __TTRACE_TOKENS_H__ +/* All defines should use decimal so to not confuse the post processing tool */ + +/* Trace groups */ #define PVRSRV_TRACE_GROUP_KICK 0 #define PVRSRV_TRACE_GROUP_TRANSFER 1 #define PVRSRV_TRACE_GROUP_QUEUE 2 @@ -35,6 +56,7 @@ #define PVRSRV_TRACE_GROUP_PADDING 255 +/* Trace classes */ #define PVRSRV_TRACE_CLASS_FUNCTION_ENTER 0 #define PVRSRV_TRACE_CLASS_FUNCTION_EXIT 1 #define PVRSRV_TRACE_CLASS_SYNC 2 @@ -46,10 +68,18 @@ #define PVRSRV_TRACE_CLASS_NONE 255 +/* Operation about to happen on the sync object */ #define PVRSRV_SYNCOP_SAMPLE 0 #define PVRSRV_SYNCOP_COMPLETE 1 #define PVRSRV_SYNCOP_DUMP 2 +/* + * Trace tokens + * ------------ + * These only need to unique within a group. + */ + +/* Kick group tokens */ #define KICK_TOKEN_DOKICK 0 #define KICK_TOKEN_CCB_OFFSET 1 #define KICK_TOKEN_TA3D_SYNC 2 @@ -58,6 +88,7 @@ #define KICK_TOKEN_SRC_SYNC 5 #define KICK_TOKEN_DST_SYNC 6 +/* Transfer Queue group tokens */ #define TRANSFER_TOKEN_SUBMIT 0 #define TRANSFER_TOKEN_TA_SYNC 1 #define TRANSFER_TOKEN_3D_SYNC 2 @@ -65,6 +96,7 @@ #define TRANSFER_TOKEN_DST_SYNC 4 #define TRANSFER_TOKEN_CCB_OFFSET 5 +/* Queue group tokens */ #define QUEUE_TOKEN_GET_SPACE 0 #define QUEUE_TOKEN_INSERTKM 1 #define QUEUE_TOKEN_SUBMITKM 2 @@ -77,8 +109,9 @@ #define QUEUE_TOKEN_DST_SYNC 9 #define QUEUE_TOKEN_COMMAND_TYPE 10 +/* uKernel Sync tokens */ #define MKSYNC_TOKEN_KERNEL_CCB_OFFSET 0 #define MKSYNC_TOKEN_CORE_CLK 1 #define MKSYNC_TOKEN_UKERNEL_CLK 2 -#endif +#endif /* __TTRACE_TOKENS_H__ */ |