| /*************************************************************************/ /*! |
| @File sync_server.c |
| @Title Server side synchronisation functions |
| @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved |
| @Description Implements the server side functions that for 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. |
| */ /**************************************************************************/ |
| #include "img_types.h" |
| #include "sync_server.h" |
| #include "sync_server_internal.h" |
| #include "allocmem.h" |
| #include "devicemem.h" |
| #include "devicemem_pdump.h" |
| #include "osfunc.h" |
| #include "pdump.h" |
| #include "pvr_debug.h" |
| #include "pdump_km.h" |
| #include "sync.h" |
| #include "sync_internal.h" |
| #include "pvrsrv.h" |
| #include "debug_request_ids.h" |
| #include "connection_server.h" |
| |
| #if defined(SUPPORT_SECURE_EXPORT) |
| #include "ossecure_export.h" |
| #endif |
| |
| struct _SYNC_PRIMITIVE_BLOCK_ |
| { |
| PVRSRV_DEVICE_NODE *psDevNode; |
| DEVMEM_MEMDESC *psMemDesc; |
| DEVMEM_EXPORTCOOKIE sExportCookie; |
| IMG_UINT32 *pui32LinAddr; |
| IMG_UINT32 ui32BlockSize; /*!< Size of the Sync Primitive Block */ |
| IMG_UINT32 ui32RefCount; |
| POS_LOCK hLock; |
| DLLIST_NODE sConnectionNode; |
| SYNC_CONNECTION_DATA *psSyncConnectionData; /*!< Link back to the sync connection data if there is one */ |
| }; |
| |
| struct _SERVER_SYNC_PRIMITIVE_ |
| { |
| PVRSRV_CLIENT_SYNC_PRIM *psSync; |
| IMG_UINT32 ui32NextOp; |
| IMG_UINT32 ui32RefCount; |
| IMG_UINT32 ui32UID; |
| IMG_UINT32 ui32LastSyncRequesterID; |
| DLLIST_NODE sNode; |
| /* PDump only data */ |
| IMG_BOOL bSWOperation; |
| IMG_BOOL bSWOpStartedInCaptRange; |
| IMG_UINT32 ui32LastHWUpdate; |
| IMG_BOOL bPDumped; |
| POS_LOCK hLock; |
| IMG_CHAR szClassName[SYNC_MAX_CLASS_NAME_LEN]; |
| }; |
| |
| struct _SERVER_SYNC_EXPORT_ |
| { |
| SERVER_SYNC_PRIMITIVE *psSync; |
| }; |
| |
| struct _SERVER_OP_COOKIE_ |
| { |
| IMG_BOOL bActive; |
| /* |
| Client syncblock(s) info. |
| If this changes update the calculation of ui32BlockAllocSize |
| */ |
| IMG_UINT32 ui32SyncBlockCount; |
| SYNC_PRIMITIVE_BLOCK **papsSyncPrimBlock; |
| |
| /* |
| Client sync(s) info. |
| If this changes update the calculation of ui32ClientAllocSize |
| */ |
| IMG_UINT32 ui32ClientSyncCount; |
| IMG_UINT32 *paui32SyncBlockIndex; |
| IMG_UINT32 *paui32Index; |
| IMG_UINT32 *paui32Flags; |
| IMG_UINT32 *paui32FenceValue; |
| IMG_UINT32 *paui32UpdateValue; |
| |
| /* |
| Server sync(s) info |
| If this changes update the calculation of ui32ServerAllocSize |
| */ |
| IMG_UINT32 ui32ServerSyncCount; |
| SERVER_SYNC_PRIMITIVE **papsServerSync; |
| IMG_UINT32 *paui32ServerFenceValue; |
| IMG_UINT32 *paui32ServerUpdateValue; |
| |
| }; |
| |
| struct _SYNC_CONNECTION_DATA_ |
| { |
| DLLIST_NODE sListHead; |
| IMG_UINT32 ui32RefCount; |
| POS_LOCK hLock; |
| }; |
| |
| static IMG_UINT32 g_ServerSyncUID = 0; |
| |
| POS_LOCK g_hListLock; |
| static DLLIST_NODE g_sAllServerSyncs; |
| IMG_HANDLE g_hNotify; |
| |
| #define SYNC_REQUESTOR_UNKNOWN 0 |
| static IMG_UINT32 g_ui32NextSyncRequestorID = 1; |
| |
| #if defined(SYNC_DEBUG) || defined(REFCOUNT_DEBUG) |
| #define SYNC_REFCOUNT_PRINT(fmt, ...) PVRSRVDebugPrintf(PVR_DBG_WARNING, __FILE__, __LINE__, fmt, __VA_ARGS__) |
| #else |
| #define SYNC_REFCOUNT_PRINT(fmt, ...) |
| #endif |
| |
| #if defined(SYNC_DEBUG) |
| #define SYNC_UPDATES_PRINT(fmt, ...) PVRSRVDebugPrintf(PVR_DBG_WARNING, __FILE__, __LINE__, fmt, __VA_ARGS__) |
| #else |
| #define SYNC_UPDATES_PRINT(fmt, ...) |
| #endif |
| |
| static |
| IMG_VOID _SyncConnectionRef(SYNC_CONNECTION_DATA *psSyncConnectionData) |
| { |
| IMG_UINT32 ui32RefCount; |
| |
| OSLockAcquire(psSyncConnectionData->hLock); |
| ui32RefCount = ++psSyncConnectionData->ui32RefCount; |
| OSLockRelease(psSyncConnectionData->hLock); |
| |
| SYNC_REFCOUNT_PRINT("%s: Sync connection %p, refcount = %d", |
| __FUNCTION__, psSyncConnectionData, ui32RefCount); |
| } |
| |
| static |
| IMG_VOID _SyncConnectionUnref(SYNC_CONNECTION_DATA *psSyncConnectionData) |
| { |
| IMG_UINT32 ui32RefCount; |
| |
| OSLockAcquire(psSyncConnectionData->hLock); |
| ui32RefCount = --psSyncConnectionData->ui32RefCount; |
| OSLockRelease(psSyncConnectionData->hLock); |
| |
| if (ui32RefCount == 0) |
| { |
| SYNC_REFCOUNT_PRINT("%s: Sync connection %p, refcount = %d", |
| __FUNCTION__, psSyncConnectionData, ui32RefCount); |
| |
| PVR_ASSERT(dllist_is_empty(&psSyncConnectionData->sListHead)); |
| OSLockDestroy(psSyncConnectionData->hLock); |
| OSFreeMem(psSyncConnectionData); |
| } |
| else |
| { |
| SYNC_REFCOUNT_PRINT("%s: Sync connection %p, refcount = %d", |
| __FUNCTION__, psSyncConnectionData, ui32RefCount); |
| } |
| } |
| |
| static |
| IMG_VOID _SyncConnectionAddBlock(CONNECTION_DATA *psConnection, SYNC_PRIMITIVE_BLOCK *psBlock) |
| { |
| if (psConnection) |
| { |
| SYNC_CONNECTION_DATA *psSyncConnectionData = psConnection->psSyncConnectionData; |
| |
| /* |
| Make sure the connection doesn't go away. It doesn't matter that we will release |
| the lock between as the refcount and list don't have to be atomic w.r.t. to each other |
| */ |
| _SyncConnectionRef(psSyncConnectionData); |
| |
| OSLockAcquire(psSyncConnectionData->hLock); |
| if (psConnection != IMG_NULL) |
| { |
| dllist_add_to_head(&psSyncConnectionData->sListHead, &psBlock->sConnectionNode); |
| } |
| OSLockRelease(psSyncConnectionData->hLock); |
| psBlock->psSyncConnectionData = psSyncConnectionData; |
| } |
| else |
| { |
| psBlock->psSyncConnectionData = IMG_NULL; |
| } |
| } |
| |
| static |
| IMG_VOID _SyncConnectionRemoveBlock(SYNC_PRIMITIVE_BLOCK *psBlock) |
| { |
| SYNC_CONNECTION_DATA *psSyncConnectionData = psBlock->psSyncConnectionData; |
| |
| if (psBlock->psSyncConnectionData) |
| { |
| OSLockAcquire(psSyncConnectionData->hLock); |
| dllist_remove_node(&psBlock->sConnectionNode); |
| OSLockRelease(psSyncConnectionData->hLock); |
| |
| _SyncConnectionUnref(psBlock->psSyncConnectionData); |
| } |
| } |
| |
| static |
| IMG_VOID _SyncPrimitiveBlockRef(SYNC_PRIMITIVE_BLOCK *psSyncBlk) |
| { |
| IMG_UINT32 ui32RefCount; |
| |
| OSLockAcquire(psSyncBlk->hLock); |
| ui32RefCount = ++psSyncBlk->ui32RefCount; |
| OSLockRelease(psSyncBlk->hLock); |
| |
| SYNC_REFCOUNT_PRINT("%s: Sync block %p, refcount = %d", |
| __FUNCTION__, psSyncBlk, ui32RefCount); |
| } |
| |
| static |
| IMG_VOID _SyncPrimitiveBlockUnref(SYNC_PRIMITIVE_BLOCK *psSyncBlk) |
| { |
| IMG_UINT32 ui32RefCount; |
| |
| OSLockAcquire(psSyncBlk->hLock); |
| ui32RefCount = --psSyncBlk->ui32RefCount; |
| OSLockRelease(psSyncBlk->hLock); |
| |
| if (ui32RefCount == 0) |
| { |
| PVRSRV_DEVICE_NODE *psDevNode = psSyncBlk->psDevNode; |
| |
| SYNC_REFCOUNT_PRINT("%s: Sync block %p, refcount = %d (remove)", |
| __FUNCTION__, psSyncBlk, ui32RefCount); |
| |
| _SyncConnectionRemoveBlock(psSyncBlk); |
| OSLockDestroy(psSyncBlk->hLock); |
| DevmemUnexport(psSyncBlk->psMemDesc, &psSyncBlk->sExportCookie); |
| DevmemReleaseCpuVirtAddr(psSyncBlk->psMemDesc); |
| psDevNode->pfnFreeUFOBlock(psDevNode, psSyncBlk->psMemDesc); |
| OSFreeMem(psSyncBlk); |
| } |
| else |
| { |
| SYNC_REFCOUNT_PRINT("%s: Sync block %p, refcount = %d", |
| __FUNCTION__, psSyncBlk, ui32RefCount); |
| } |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVAllocSyncPrimitiveBlockKM(CONNECTION_DATA *psConnection, |
| PVRSRV_DEVICE_NODE *psDevNode, |
| SYNC_PRIMITIVE_BLOCK **ppsSyncBlk, |
| IMG_UINT32 *puiSyncPrimVAddr, |
| IMG_UINT32 *puiSyncPrimBlockSize, |
| DEVMEM_EXPORTCOOKIE **psExportCookie) |
| { |
| SYNC_PRIMITIVE_BLOCK *psNewSyncBlk; |
| PVRSRV_ERROR eError; |
| |
| psNewSyncBlk = OSAllocMem(sizeof(SYNC_PRIMITIVE_BLOCK)); |
| if (psNewSyncBlk == IMG_NULL) |
| { |
| eError = PVRSRV_ERROR_OUT_OF_MEMORY; |
| goto e0; |
| } |
| psNewSyncBlk->psDevNode = psDevNode; |
| |
| PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "Allocate UFO block"); |
| |
| eError = psDevNode->pfnAllocUFOBlock(psDevNode, |
| &psNewSyncBlk->psMemDesc, |
| puiSyncPrimVAddr, |
| &psNewSyncBlk->ui32BlockSize); |
| if (eError != PVRSRV_OK) |
| { |
| goto e1; |
| } |
| |
| eError = DevmemAcquireCpuVirtAddr(psNewSyncBlk->psMemDesc, |
| (IMG_PVOID *) &psNewSyncBlk->pui32LinAddr); |
| if (eError != PVRSRV_OK) |
| { |
| goto e2; |
| } |
| |
| eError = DevmemExport(psNewSyncBlk->psMemDesc, &psNewSyncBlk->sExportCookie); |
| if (eError != PVRSRV_OK) |
| { |
| goto e3; |
| } |
| |
| eError = OSLockCreate(&psNewSyncBlk->hLock, LOCK_TYPE_NONE); |
| if (eError != PVRSRV_OK) |
| { |
| goto e4; |
| } |
| |
| psNewSyncBlk->ui32RefCount = 1; |
| |
| /* If there is a connection pointer then add the new block onto it's list */ |
| _SyncConnectionAddBlock(psConnection, psNewSyncBlk); |
| |
| *psExportCookie = &psNewSyncBlk->sExportCookie; |
| *ppsSyncBlk = psNewSyncBlk; |
| *puiSyncPrimBlockSize = psNewSyncBlk->ui32BlockSize; |
| |
| PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, |
| "Allocated UFO block (FirmwareVAddr = 0x%08x)", |
| *puiSyncPrimVAddr); |
| |
| return PVRSRV_OK; |
| e4: |
| DevmemUnexport(psNewSyncBlk->psMemDesc, &psNewSyncBlk->sExportCookie); |
| |
| e3: |
| DevmemReleaseCpuVirtAddr(psNewSyncBlk->psMemDesc); |
| e2: |
| psDevNode->pfnFreeUFOBlock(psDevNode, psNewSyncBlk->psMemDesc); |
| e1: |
| OSFreeMem(psNewSyncBlk); |
| e0: |
| return eError; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVFreeSyncPrimitiveBlockKM(SYNC_PRIMITIVE_BLOCK *psSyncBlk) |
| { |
| _SyncPrimitiveBlockUnref(psSyncBlk); |
| |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimSetKM(SYNC_PRIMITIVE_BLOCK *psSyncBlk, IMG_UINT32 ui32Index, |
| IMG_UINT32 ui32Value) |
| { |
| psSyncBlk->pui32LinAddr[ui32Index] = ui32Value; |
| |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVServerSyncPrimSetKM(SERVER_SYNC_PRIMITIVE *psServerSync, IMG_UINT32 ui32Value) |
| { |
| *psServerSync->psSync->pui32LinAddr = ui32Value; |
| |
| return PVRSRV_OK; |
| } |
| |
| IMG_VOID |
| ServerSyncRef(SERVER_SYNC_PRIMITIVE *psSync) |
| { |
| IMG_UINT32 ui32RefCount; |
| |
| OSLockAcquire(psSync->hLock); |
| ui32RefCount = ++psSync->ui32RefCount; |
| OSLockRelease(psSync->hLock); |
| |
| SYNC_REFCOUNT_PRINT("%s: Server sync %p, refcount = %d", |
| __FUNCTION__, psSync, ui32RefCount); |
| } |
| |
| IMG_VOID |
| ServerSyncUnref(SERVER_SYNC_PRIMITIVE *psSync) |
| { |
| IMG_UINT32 ui32RefCount; |
| |
| OSLockAcquire(psSync->hLock); |
| ui32RefCount = --psSync->ui32RefCount; |
| OSLockRelease(psSync->hLock); |
| |
| if (ui32RefCount == 0) |
| { |
| SYNC_REFCOUNT_PRINT("%s: Server sync %p, refcount = %d", |
| __FUNCTION__, psSync, ui32RefCount); |
| |
| /* Remove the sync from the global list */ |
| OSLockAcquire(g_hListLock); |
| dllist_remove_node(&psSync->sNode); |
| OSLockRelease(g_hListLock); |
| |
| OSLockDestroy(psSync->hLock); |
| SyncPrimFree(psSync->psSync); |
| OSFreeMem(psSync); |
| } |
| else |
| { |
| SYNC_REFCOUNT_PRINT("%s: Server sync %p, refcount = %d", |
| __FUNCTION__, psSync, ui32RefCount); |
| } |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVServerSyncAllocKM(PVRSRV_DEVICE_NODE *psDevNode, |
| SERVER_SYNC_PRIMITIVE **ppsSync, |
| IMG_UINT32 *pui32SyncPrimVAddr, |
| IMG_UINT32 ui32ClassNameSize, |
| const IMG_CHAR *pszClassName) |
| { |
| SERVER_SYNC_PRIMITIVE *psNewSync; |
| PVRSRV_ERROR eError; |
| |
| psNewSync = OSAllocMem(sizeof(SERVER_SYNC_PRIMITIVE)); |
| if (psNewSync == IMG_NULL) |
| { |
| return PVRSRV_ERROR_OUT_OF_MEMORY; |
| } |
| |
| eError = SyncPrimAlloc(psDevNode->hSyncPrimContext, |
| &psNewSync->psSync); |
| if (eError != PVRSRV_OK) |
| { |
| goto fail_sync_alloc; |
| } |
| |
| eError = OSLockCreate(&psNewSync->hLock, LOCK_TYPE_NONE); |
| if (eError != PVRSRV_OK) |
| { |
| goto fail_lock_create; |
| } |
| |
| SyncPrimSet(psNewSync->psSync, 0); |
| |
| psNewSync->ui32NextOp = 0; |
| psNewSync->ui32RefCount = 1; |
| psNewSync->ui32UID = g_ServerSyncUID++; |
| psNewSync->ui32LastSyncRequesterID = SYNC_REQUESTOR_UNKNOWN; |
| psNewSync->bSWOperation = IMG_FALSE; |
| psNewSync->ui32LastHWUpdate = 0x0bad592c; |
| psNewSync->bPDumped = IMG_FALSE; |
| |
| if(pszClassName) |
| { |
| if (ui32ClassNameSize >= SYNC_MAX_CLASS_NAME_LEN) |
| ui32ClassNameSize = SYNC_MAX_CLASS_NAME_LEN - 1; |
| /* Copy over the class name annotation */ |
| OSStringNCopy(psNewSync->szClassName, pszClassName, ui32ClassNameSize); |
| psNewSync->szClassName[ui32ClassNameSize] = 0; |
| } |
| else |
| { |
| /* No class name annotation */ |
| psNewSync->szClassName[0] = 0; |
| } |
| |
| /* Add the sync to the global list */ |
| OSLockAcquire(g_hListLock); |
| dllist_add_to_head(&g_sAllServerSyncs, &psNewSync->sNode); |
| OSLockRelease(g_hListLock); |
| |
| *pui32SyncPrimVAddr = SyncPrimGetFirmwareAddr(psNewSync->psSync); |
| SYNC_UPDATES_PRINT("%s: sync: %p, fwaddr: %8.8X", __FUNCTION__, psNewSync, *pui32SyncPrimVAddr); |
| *ppsSync = psNewSync; |
| return PVRSRV_OK; |
| |
| fail_lock_create: |
| SyncPrimFree(psNewSync->psSync); |
| |
| fail_sync_alloc: |
| OSFreeMem(psNewSync); |
| return eError; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVServerSyncFreeKM(SERVER_SYNC_PRIMITIVE *psSync) |
| { |
| ServerSyncUnref(psSync); |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVServerSyncGetStatusKM(IMG_UINT32 ui32SyncCount, |
| SERVER_SYNC_PRIMITIVE **papsSyncs, |
| IMG_UINT32 *pui32UID, |
| IMG_UINT32 *pui32FWAddr, |
| IMG_UINT32 *pui32CurrentOp, |
| IMG_UINT32 *pui32NextOp) |
| { |
| IMG_UINT32 i; |
| |
| for (i=0;i<ui32SyncCount;i++) |
| { |
| PVRSRV_CLIENT_SYNC_PRIM *psClientSync = papsSyncs[i]->psSync; |
| |
| pui32UID[i] = papsSyncs[i]->ui32UID; |
| pui32FWAddr[i] = SyncPrimGetFirmwareAddr(psClientSync); |
| pui32CurrentOp[i] = *psClientSync->pui32LinAddr; |
| pui32NextOp[i] = papsSyncs[i]->ui32NextOp; |
| } |
| return PVRSRV_OK; |
| } |
| |
| static PVRSRV_ERROR |
| _PVRSRVSyncPrimServerExportKM(SERVER_SYNC_PRIMITIVE *psSync, |
| SERVER_SYNC_EXPORT **ppsExport) |
| { |
| SERVER_SYNC_EXPORT *psNewExport; |
| PVRSRV_ERROR eError; |
| |
| psNewExport = OSAllocMem(sizeof(SERVER_SYNC_EXPORT)); |
| if (!psNewExport) |
| { |
| eError = PVRSRV_ERROR_OUT_OF_MEMORY; |
| goto e0; |
| } |
| |
| ServerSyncRef(psSync); |
| |
| psNewExport->psSync = psSync; |
| *ppsExport = psNewExport; |
| |
| return PVRSRV_OK; |
| e0: |
| return eError; |
| } |
| |
| static PVRSRV_ERROR |
| _PVRSRVSyncPrimServerUnexportKM(SERVER_SYNC_EXPORT *psExport) |
| { |
| ServerSyncUnref(psExport->psSync); |
| |
| OSFreeMem(psExport); |
| |
| return PVRSRV_OK; |
| } |
| |
| static IMG_VOID |
| _PVRSRVSyncPrimServerImportKM(SERVER_SYNC_EXPORT *psExport, |
| SERVER_SYNC_PRIMITIVE **ppsSync, |
| IMG_UINT32 *pui32SyncPrimVAddr) |
| { |
| ServerSyncRef(psExport->psSync); |
| |
| *ppsSync = psExport->psSync; |
| *pui32SyncPrimVAddr = SyncPrimGetFirmwareAddr(psExport->psSync->psSync); |
| } |
| |
| #if defined(SUPPORT_INSECURE_EXPORT) |
| PVRSRV_ERROR |
| PVRSRVSyncPrimServerExportKM(SERVER_SYNC_PRIMITIVE *psSync, |
| SERVER_SYNC_EXPORT **ppsExport) |
| { |
| return _PVRSRVSyncPrimServerExportKM(psSync, |
| ppsExport); |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimServerUnexportKM(SERVER_SYNC_EXPORT *psExport) |
| { |
| return _PVRSRVSyncPrimServerUnexportKM(psExport); |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimServerImportKM(SERVER_SYNC_EXPORT *psExport, |
| SERVER_SYNC_PRIMITIVE **ppsSync, |
| IMG_UINT32 *pui32SyncPrimVAddr) |
| { |
| _PVRSRVSyncPrimServerImportKM(psExport, |
| ppsSync, |
| pui32SyncPrimVAddr); |
| |
| return PVRSRV_OK; |
| } |
| #endif /* defined(SUPPORT_INSECURE_EXPORT) */ |
| |
| #if defined(SUPPORT_SECURE_EXPORT) |
| PVRSRV_ERROR |
| PVRSRVSyncPrimServerSecureExportKM(CONNECTION_DATA *psConnection, |
| SERVER_SYNC_PRIMITIVE *psSync, |
| IMG_SECURE_TYPE *phSecure, |
| SERVER_SYNC_EXPORT **ppsExport, |
| CONNECTION_DATA **ppsSecureConnection) |
| { |
| SERVER_SYNC_EXPORT *psNewExport; |
| PVRSRV_ERROR eError; |
| |
| /* Create an export server sync */ |
| eError = _PVRSRVSyncPrimServerExportKM(psSync, |
| &psNewExport); |
| |
| if (eError != PVRSRV_OK) |
| { |
| goto e0; |
| } |
| |
| /* Transform it into a secure export */ |
| eError = OSSecureExport(psConnection, |
| (IMG_PVOID) psNewExport, |
| phSecure, |
| ppsSecureConnection); |
| if (eError != PVRSRV_OK) |
| { |
| goto e1; |
| } |
| |
| *ppsExport = psNewExport; |
| return PVRSRV_OK; |
| e1: |
| _PVRSRVSyncPrimServerUnexportKM(psNewExport); |
| e0: |
| PVR_ASSERT(eError != PVRSRV_OK); |
| return eError; |
| } |
| |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimServerSecureUnexportKM(SERVER_SYNC_EXPORT *psExport) |
| { |
| _PVRSRVSyncPrimServerUnexportKM(psExport); |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimServerSecureImportKM(IMG_SECURE_TYPE hSecure, |
| SERVER_SYNC_PRIMITIVE **ppsSync, |
| IMG_UINT32 *pui32SyncPrimVAddr) |
| { |
| PVRSRV_ERROR eError; |
| SERVER_SYNC_EXPORT *psImport; |
| |
| /* Retrieve the data from the secure import */ |
| eError = OSSecureImport(hSecure, (IMG_PVOID *) &psImport); |
| if (eError != PVRSRV_OK) |
| { |
| goto e0; |
| } |
| |
| _PVRSRVSyncPrimServerImportKM(psImport, |
| ppsSync, |
| pui32SyncPrimVAddr); |
| return PVRSRV_OK; |
| |
| e0: |
| PVR_ASSERT(eError != PVRSRV_OK); |
| return eError; |
| } |
| #endif /* defined(SUPPORT_SECURE_EXPORT) */ |
| |
| IMG_UINT32 PVRSRVServerSyncRequesterRegisterKM(IMG_UINT32 *pui32SyncRequesterID) |
| { |
| *pui32SyncRequesterID = g_ui32NextSyncRequestorID++; |
| |
| return PVRSRV_OK; |
| } |
| |
| IMG_VOID PVRSRVServerSyncRequesterUnregisterKM(IMG_UINT32 ui32SyncRequesterID) |
| { |
| PVR_UNREFERENCED_PARAMETER(ui32SyncRequesterID); |
| } |
| |
| static IMG_VOID |
| _ServerSyncTakeOperation(SERVER_SYNC_PRIMITIVE *psSync, |
| IMG_BOOL bUpdate, |
| IMG_UINT32 *pui32FenceValue, |
| IMG_UINT32 *pui32UpdateValue) |
| { |
| IMG_BOOL bInCaptureRange; |
| |
| /* Only advance the pending if the an update is required */ |
| if (bUpdate) |
| { |
| *pui32FenceValue = psSync->ui32NextOp++; |
| } |
| else |
| { |
| *pui32FenceValue = psSync->ui32NextOp; |
| } |
| |
| *pui32UpdateValue = psSync->ui32NextOp; |
| |
| PDumpIsCaptureFrameKM(&bInCaptureRange); |
| /* |
| If this is the 1st operation (in this capture range) then PDump |
| this sync |
| */ |
| if (!psSync->bPDumped && bInCaptureRange) |
| { |
| IMG_CHAR azTmp[100]; |
| OSSNPrintf(azTmp, |
| sizeof(azTmp), |
| "Dump initial sync state (0x%p, FW VAddr = 0x%08x) = 0x%08x\n", |
| psSync, |
| SyncPrimGetFirmwareAddr(psSync->psSync), |
| *psSync->psSync->pui32LinAddr); |
| PDumpCommentKM(azTmp, 0); |
| |
| SyncPrimPDump(psSync->psSync); |
| psSync->bPDumped = IMG_TRUE; |
| } |
| |
| /* |
| When exiting capture range clear down bPDumped as we might re-enter |
| capture range and thus need to PDump this sync again |
| */ |
| if (!bInCaptureRange) |
| { |
| psSync->bPDumped = IMG_FALSE; |
| } |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVServerSyncQueueSWOpKM(SERVER_SYNC_PRIMITIVE *psSync, |
| IMG_UINT32 *pui32FenceValue, |
| IMG_UINT32 *pui32UpdateValue, |
| IMG_UINT32 ui32SyncRequesterID, |
| IMG_BOOL bUpdate, |
| IMG_BOOL *pbFenceRequired) |
| { |
| |
| ServerSyncRef(psSync); |
| |
| /* |
| ServerSyncRef will acquire and release the lock but we need to |
| reacquire here to ensure the state that we're modifying below |
| will be consistent with itself. But it doesn't matter if another |
| thread acquires the lock in between as we've ensured the sync |
| wont go away |
| */ |
| OSLockAcquire(psSync->hLock); |
| _ServerSyncTakeOperation(psSync, |
| bUpdate, |
| pui32FenceValue, |
| pui32UpdateValue); |
| |
| /* |
| The caller want to know if a fence command is required |
| i.e. was the last operation done on this sync done by the |
| the same sync requestor |
| */ |
| if (pbFenceRequired) |
| { |
| if (ui32SyncRequesterID == psSync->ui32LastSyncRequesterID) |
| { |
| *pbFenceRequired = IMG_FALSE; |
| } |
| else |
| { |
| *pbFenceRequired = IMG_TRUE; |
| } |
| } |
| /* |
| If we're transitioning from a HW operation to a SW operation we |
| need to save the last update the HW will do so that when we PDump |
| we can issue a POL for it before the next HW operation and then |
| LDB in the last SW fence update |
| */ |
| if (psSync->bSWOperation == IMG_FALSE) |
| { |
| psSync->bSWOperation = IMG_TRUE; |
| psSync->ui32LastHWUpdate = *pui32FenceValue; |
| PDumpIsCaptureFrameKM(&psSync->bSWOpStartedInCaptRange); |
| } |
| |
| if (pbFenceRequired) |
| { |
| if (*pbFenceRequired) |
| { |
| SYNC_UPDATES_PRINT("%s: sync: %p, fence: %d, value: %d", __FUNCTION__, psSync, *pui32FenceValue, *pui32UpdateValue); |
| } |
| } |
| |
| /* Only update the last requester id if we are make changes to this sync |
| * object. */ |
| if (bUpdate) |
| psSync->ui32LastSyncRequesterID = ui32SyncRequesterID; |
| |
| OSLockRelease(psSync->hLock); |
| |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVServerSyncQueueHWOpKM(SERVER_SYNC_PRIMITIVE *psSync, |
| IMG_BOOL bUpdate, |
| IMG_UINT32 *pui32FenceValue, |
| IMG_UINT32 *pui32UpdateValue) |
| { |
| /* |
| For HW operations the client is required to ensure the |
| operation has completed before freeing the sync as we |
| no way of dropping the refcount if we where to acquire it |
| here. |
| |
| Take the lock to ensure the state that we're modifying below |
| will be consistent with itself. |
| */ |
| OSLockAcquire(psSync->hLock); |
| _ServerSyncTakeOperation(psSync, |
| bUpdate, |
| pui32FenceValue, |
| pui32UpdateValue); |
| |
| /* |
| Note: |
| |
| We might want to consider optimising the fences that we write for |
| HW operations but for now just clear it back to unknown |
| */ |
| psSync->ui32LastSyncRequesterID = SYNC_REQUESTOR_UNKNOWN; |
| |
| if (psSync->bSWOperation) |
| { |
| IMG_CHAR azTmp[256]; |
| OSSNPrintf(azTmp, |
| sizeof(azTmp), |
| "Wait for HW ops and dummy update for SW ops (0x%p, FW VAddr = 0x%08x, value = 0x%08x)\n", |
| psSync, |
| SyncPrimGetFirmwareAddr(psSync->psSync), |
| *pui32FenceValue); |
| PDumpCommentKM(azTmp, 0); |
| |
| if (psSync->bSWOpStartedInCaptRange) |
| { |
| /* Dump a POL for the previous HW operation */ |
| SyncPrimPDumpPol(psSync->psSync, |
| psSync->ui32LastHWUpdate, |
| 0xffffffff, |
| PDUMP_POLL_OPERATOR_EQUAL, |
| 0); |
| } |
| |
| /* Dump the expected value (i.e. the value after all the SW operations) */ |
| SyncPrimPDumpValue(psSync->psSync, *pui32FenceValue); |
| |
| /* Reset the state as we've just done a HW operation */ |
| psSync->bSWOperation = IMG_FALSE; |
| } |
| OSLockRelease(psSync->hLock); |
| |
| SYNC_UPDATES_PRINT("%s: sync: %p, fence: %d, value: %d", __FUNCTION__, psSync, *pui32FenceValue, *pui32UpdateValue); |
| |
| return PVRSRV_OK; |
| } |
| |
| IMG_BOOL ServerSyncFenceIsMet(SERVER_SYNC_PRIMITIVE *psSync, |
| IMG_UINT32 ui32FenceValue) |
| { |
| SYNC_UPDATES_PRINT("%s: sync: %p, value(%d) == fence(%d)?", __FUNCTION__, psSync, *psSync->psSync->pui32LinAddr, ui32FenceValue); |
| return (*psSync->psSync->pui32LinAddr >= ui32FenceValue); |
| } |
| |
| IMG_VOID |
| ServerSyncCompleteOp(SERVER_SYNC_PRIMITIVE *psSync, |
| IMG_BOOL bDoUpdate, |
| IMG_UINT32 ui32UpdateValue) |
| { |
| if (bDoUpdate) |
| { |
| SYNC_UPDATES_PRINT("%s: sync: %p (%d) = %d", __FUNCTION__, psSync, *psSync->psSync->pui32LinAddr, ui32UpdateValue); |
| |
| *psSync->psSync->pui32LinAddr = ui32UpdateValue; |
| } |
| |
| ServerSyncUnref(psSync); |
| } |
| |
| IMG_UINT32 ServerSyncGetId(SERVER_SYNC_PRIMITIVE *psSync) |
| { |
| return psSync->ui32UID; |
| } |
| |
| IMG_UINT32 ServerSyncGetFWAddr(SERVER_SYNC_PRIMITIVE *psSync) |
| { |
| return SyncPrimGetFirmwareAddr(psSync->psSync); |
| } |
| |
| IMG_UINT32 ServerSyncGetValue(SERVER_SYNC_PRIMITIVE *psSync) |
| { |
| return *psSync->psSync->pui32LinAddr; |
| } |
| |
| IMG_UINT32 ServerSyncGetNextValue(SERVER_SYNC_PRIMITIVE *psSync) |
| { |
| return psSync->ui32NextOp; |
| } |
| |
| static IMG_BOOL _ServerSyncState(PDLLIST_NODE psNode, IMG_PVOID pvCallbackData) |
| { |
| SERVER_SYNC_PRIMITIVE *psSync = IMG_CONTAINER_OF(psNode, SERVER_SYNC_PRIMITIVE, sNode); |
| DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf = IMG_NULL; |
| |
| pfnDumpDebugPrintf = g_pfnDumpDebugPrintf; |
| |
| if (*psSync->psSync->pui32LinAddr != psSync->ui32NextOp) |
| { |
| PVR_DUMPDEBUG_LOG(("\tPending server sync (ID = %d, FWAddr = 0x%08x): Current = 0x%08x, NextOp = 0x%08x (%s)", |
| psSync->ui32UID, |
| ServerSyncGetFWAddr(psSync), |
| ServerSyncGetValue(psSync), |
| psSync->ui32NextOp, |
| psSync->szClassName)); |
| } |
| return IMG_TRUE; |
| } |
| |
| static IMG_VOID _ServerSyncDebugRequest(PVRSRV_DBGREQ_HANDLE hDebugRequestHandle, IMG_UINT32 ui32VerbLevel) |
| { |
| |
| DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf = IMG_NULL; |
| |
| PVR_UNREFERENCED_PARAMETER(hDebugRequestHandle); |
| |
| pfnDumpDebugPrintf = g_pfnDumpDebugPrintf; |
| if (ui32VerbLevel == DEBUG_REQUEST_VERBOSITY_HIGH) |
| { |
| PVR_DUMPDEBUG_LOG(("Dumping all pending server syncs")); |
| OSLockAcquire(g_hListLock); |
| dllist_foreach_node(&g_sAllServerSyncs, _ServerSyncState, IMG_NULL); |
| OSLockRelease(g_hListLock); |
| } |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimOpCreateKM(IMG_UINT32 ui32SyncBlockCount, |
| SYNC_PRIMITIVE_BLOCK **papsSyncPrimBlock, |
| IMG_UINT32 ui32ClientSyncCount, |
| IMG_UINT32 *paui32SyncBlockIndex, |
| IMG_UINT32 *paui32Index, |
| IMG_UINT32 ui32ServerSyncCount, |
| SERVER_SYNC_PRIMITIVE **papsServerSync, |
| SERVER_OP_COOKIE **ppsServerCookie) |
| { |
| SERVER_OP_COOKIE *psNewCookie; |
| IMG_UINT32 ui32BlockAllocSize; |
| IMG_UINT32 ui32ServerAllocSize; |
| IMG_UINT32 ui32ClientAllocSize; |
| IMG_UINT32 ui32TotalAllocSize; |
| IMG_UINT32 i; |
| IMG_CHAR *pcPtr; |
| PVRSRV_ERROR eError; |
| |
| /* Allocate space for all the sync block list */ |
| ui32BlockAllocSize = ui32SyncBlockCount * (sizeof(SYNC_PRIMITIVE_BLOCK *)); |
| |
| /* Allocate space for all the client sync size elements */ |
| ui32ClientAllocSize = ui32ClientSyncCount * (5 * sizeof(IMG_UINT32)); |
| |
| /* Allocate space for all the server sync size elements */ |
| ui32ServerAllocSize = ui32ServerSyncCount * (sizeof(SERVER_SYNC_PRIMITIVE *) |
| + (2 * sizeof(IMG_UINT32))); |
| |
| ui32TotalAllocSize = sizeof(SERVER_OP_COOKIE) + |
| ui32BlockAllocSize + |
| ui32ServerAllocSize + |
| ui32ClientAllocSize; |
| |
| psNewCookie = OSAllocMem(ui32TotalAllocSize); |
| pcPtr = (IMG_CHAR *) psNewCookie; |
| |
| if (!psNewCookie) |
| { |
| eError = PVRSRV_ERROR_OUT_OF_MEMORY; |
| goto e0; |
| } |
| OSMemSet(psNewCookie, 0, ui32TotalAllocSize); |
| |
| /* Setup the pointers */ |
| pcPtr += sizeof(SERVER_OP_COOKIE); |
| psNewCookie->papsSyncPrimBlock = (SYNC_PRIMITIVE_BLOCK **) pcPtr; |
| |
| pcPtr += sizeof(SYNC_PRIMITIVE_BLOCK *) * ui32SyncBlockCount; |
| psNewCookie->paui32SyncBlockIndex = (IMG_UINT32 *) pcPtr; |
| |
| pcPtr += sizeof(IMG_UINT32) * ui32ClientSyncCount; |
| psNewCookie->paui32Index = (IMG_UINT32 *) pcPtr; |
| |
| pcPtr += sizeof(IMG_UINT32) * ui32ClientSyncCount; |
| psNewCookie->paui32Flags = (IMG_UINT32 *) pcPtr; |
| |
| pcPtr += sizeof(IMG_UINT32) * ui32ClientSyncCount; |
| psNewCookie->paui32FenceValue = (IMG_UINT32 *) pcPtr; |
| |
| pcPtr += sizeof(IMG_UINT32) * ui32ClientSyncCount; |
| psNewCookie->paui32UpdateValue = (IMG_UINT32 *) pcPtr; |
| |
| pcPtr += sizeof(IMG_UINT32) * ui32ClientSyncCount; |
| psNewCookie->papsServerSync =(SERVER_SYNC_PRIMITIVE **) pcPtr; |
| |
| pcPtr += sizeof(SERVER_SYNC_PRIMITIVE *) * ui32ServerSyncCount; |
| psNewCookie->paui32ServerFenceValue = (IMG_UINT32 *) pcPtr; |
| |
| pcPtr += sizeof(IMG_UINT32) * ui32ServerSyncCount; |
| psNewCookie->paui32ServerUpdateValue = (IMG_UINT32 *) pcPtr; |
| |
| pcPtr += sizeof(IMG_UINT32) * ui32ServerSyncCount; |
| |
| /* Check the pointer setup went ok */ |
| PVR_ASSERT(pcPtr == (((IMG_CHAR *) psNewCookie) + ui32TotalAllocSize)); |
| |
| psNewCookie->ui32SyncBlockCount= ui32SyncBlockCount; |
| psNewCookie->ui32ServerSyncCount = ui32ServerSyncCount; |
| psNewCookie->ui32ClientSyncCount = ui32ClientSyncCount; |
| psNewCookie->bActive = IMG_FALSE; |
| |
| /* Copy all the data into our server cookie */ |
| OSMemCopy(psNewCookie->papsSyncPrimBlock, |
| papsSyncPrimBlock, |
| sizeof(SYNC_PRIMITIVE_BLOCK *) * ui32SyncBlockCount); |
| |
| OSMemCopy(psNewCookie->paui32SyncBlockIndex, |
| paui32SyncBlockIndex, |
| sizeof(IMG_UINT32) * ui32ClientSyncCount); |
| OSMemCopy(psNewCookie->paui32Index, |
| paui32Index, |
| sizeof(IMG_UINT32) * ui32ClientSyncCount); |
| |
| OSMemCopy(psNewCookie->papsServerSync, |
| papsServerSync, |
| sizeof(SERVER_SYNC_PRIMITIVE *) *ui32ServerSyncCount); |
| |
| /* |
| Take a reference on all the sync blocks and server syncs so they can't |
| be freed while we're using them |
| */ |
| for (i=0;i<ui32SyncBlockCount;i++) |
| { |
| _SyncPrimitiveBlockRef(psNewCookie->papsSyncPrimBlock[i]); |
| } |
| |
| for (i=0;i<ui32ServerSyncCount;i++) |
| { |
| ServerSyncRef(psNewCookie->papsServerSync[i]); |
| } |
| |
| *ppsServerCookie = psNewCookie; |
| return PVRSRV_OK; |
| |
| e0: |
| return eError; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimOpTakeKM(SERVER_OP_COOKIE *psServerCookie, |
| IMG_UINT32 ui32ClientSyncCount, |
| IMG_UINT32 *paui32Flags, |
| IMG_UINT32 *paui32FenceValue, |
| IMG_UINT32 *paui32UpdateValue, |
| IMG_UINT32 ui32ServerSyncCount, |
| IMG_UINT32 *paui32ServerFlags) |
| { |
| IMG_UINT32 i; |
| |
| if ((ui32ClientSyncCount != psServerCookie->ui32ClientSyncCount) || |
| (ui32ServerSyncCount != psServerCookie->ui32ServerSyncCount)) |
| { |
| /* The bridge layer should have stopped us getting here but check incase */ |
| PVR_DPF((PVR_DBG_ERROR, "%s: Invalid sync counts", __FUNCTION__)); |
| return PVRSRV_ERROR_INVALID_PARAMS; |
| } |
| |
| for (i=0;i<ui32ServerSyncCount;i++) |
| { |
| /* Server syncs must fence */ |
| if ((paui32ServerFlags[i] & PVRSRV_CLIENT_SYNC_PRIM_OP_CHECK) == 0) |
| { |
| return PVRSRV_ERROR_INVALID_SYNC_PRIM_OP; |
| } |
| } |
| |
| /* |
| For client syncs all we need to do is save the values |
| that we've been passed |
| */ |
| OSMemCopy(psServerCookie->paui32Flags, |
| paui32Flags, |
| sizeof(IMG_UINT32) * ui32ClientSyncCount); |
| OSMemCopy(psServerCookie->paui32FenceValue, |
| paui32FenceValue, |
| sizeof(IMG_UINT32) * ui32ClientSyncCount); |
| OSMemCopy(psServerCookie->paui32UpdateValue, |
| paui32UpdateValue, |
| sizeof(IMG_UINT32) * ui32ClientSyncCount); |
| |
| /* |
| For server syncs we just take an operation |
| */ |
| for (i=0;i<ui32ServerSyncCount;i++) |
| { |
| /* |
| Take op can only take one operation at a time so we can't |
| optimise away fences so just report the requestor as unknown |
| */ |
| PVRSRVServerSyncQueueSWOpKM(psServerCookie->papsServerSync[i], |
| &psServerCookie->paui32ServerFenceValue[i], |
| &psServerCookie->paui32ServerUpdateValue[i], |
| SYNC_REQUESTOR_UNKNOWN, |
| (paui32ServerFlags[i] & PVRSRV_CLIENT_SYNC_PRIM_OP_UPDATE) ? IMG_TRUE:IMG_FALSE, |
| IMG_NULL); |
| } |
| |
| psServerCookie->bActive = IMG_TRUE; |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimOpReadyKM(SERVER_OP_COOKIE *psServerCookie, |
| IMG_BOOL *pbReady) |
| { |
| IMG_UINT32 i; |
| IMG_BOOL bReady = IMG_TRUE; |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| if (!psServerCookie->bActive) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: Operation cookie not active (no take operation performed)", __FUNCTION__)); |
| |
| bReady = IMG_FALSE; |
| eError = PVRSRV_ERROR_BAD_SYNC_STATE; |
| goto e0; |
| } |
| |
| /* Check the client syncs */ |
| for (i=0;i<psServerCookie->ui32ClientSyncCount;i++) |
| { |
| if (psServerCookie->paui32Flags[i] & PVRSRV_CLIENT_SYNC_PRIM_OP_CHECK) |
| { |
| IMG_UINT32 ui32BlockIndex = psServerCookie->paui32SyncBlockIndex[i]; |
| IMG_UINT32 ui32Index = psServerCookie->paui32Index[i]; |
| SYNC_PRIMITIVE_BLOCK *psSyncBlock = psServerCookie->papsSyncPrimBlock[ui32BlockIndex]; |
| |
| if (psSyncBlock->pui32LinAddr[ui32Index] != |
| psServerCookie->paui32FenceValue[i]) |
| { |
| bReady = IMG_FALSE; |
| goto e0; |
| } |
| } |
| } |
| |
| for (i=0;i<psServerCookie->ui32ServerSyncCount;i++) |
| { |
| bReady = ServerSyncFenceIsMet(psServerCookie->papsServerSync[i], |
| psServerCookie->paui32ServerFenceValue[i]); |
| if (!bReady) |
| { |
| break; |
| } |
| } |
| |
| e0: |
| *pbReady = bReady; |
| return eError; |
| } |
| |
| static |
| PVRSRV_ERROR _SyncPrimOpComplete(SERVER_OP_COOKIE *psServerCookie) |
| { |
| IMG_UINT32 i; |
| |
| for (i=0;i<psServerCookie->ui32ClientSyncCount;i++) |
| { |
| if (psServerCookie->paui32Flags[i] & PVRSRV_CLIENT_SYNC_PRIM_OP_UPDATE) |
| { |
| IMG_UINT32 ui32BlockIndex = psServerCookie->paui32SyncBlockIndex[i]; |
| IMG_UINT32 ui32Index = psServerCookie->paui32Index[i]; |
| SYNC_PRIMITIVE_BLOCK *psSyncBlock = psServerCookie->papsSyncPrimBlock[ui32BlockIndex]; |
| |
| psSyncBlock->pui32LinAddr[ui32Index] = psServerCookie->paui32UpdateValue[i]; |
| } |
| } |
| |
| for (i=0;i<psServerCookie->ui32ServerSyncCount;i++) |
| { |
| ServerSyncCompleteOp(psServerCookie->papsServerSync[i], |
| (psServerCookie->paui32ServerFenceValue[i] != psServerCookie->paui32ServerUpdateValue[i]), |
| psServerCookie->paui32ServerUpdateValue[i]); |
| } |
| |
| psServerCookie->bActive = IMG_FALSE; |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimOpCompleteKM(SERVER_OP_COOKIE *psServerCookie) |
| { |
| IMG_BOOL bReady; |
| |
| PVRSRVSyncPrimOpReadyKM(psServerCookie, &bReady); |
| |
| /* Check the client is playing ball */ |
| if (!bReady) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: sync op still not ready", __FUNCTION__)); |
| |
| return PVRSRV_ERROR_BAD_SYNC_STATE; |
| } |
| |
| return _SyncPrimOpComplete(psServerCookie); |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimOpDestroyKM(SERVER_OP_COOKIE *psServerCookie) |
| { |
| IMG_UINT32 i; |
| |
| /* If the operation is still active then check if it's finished yet */ |
| if (psServerCookie->bActive) |
| { |
| if (PVRSRVSyncPrimOpCompleteKM(psServerCookie) == PVRSRV_ERROR_BAD_SYNC_STATE) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: Not ready, ask for retry", __FUNCTION__)); |
| return PVRSRV_ERROR_RETRY; |
| } |
| } |
| |
| /* Drop our references on the sync blocks and server syncs*/ |
| for (i = 0; i < psServerCookie->ui32SyncBlockCount; i++) |
| { |
| _SyncPrimitiveBlockUnref(psServerCookie->papsSyncPrimBlock[i]); |
| } |
| |
| for (i = 0; i < psServerCookie->ui32ServerSyncCount; i++) |
| { |
| ServerSyncUnref(psServerCookie->papsServerSync[i]); |
| } |
| |
| OSFreeMem(psServerCookie); |
| return PVRSRV_OK; |
| } |
| |
| #if defined(PDUMP) |
| PVRSRV_ERROR |
| PVRSRVSyncPrimPDumpValueKM(SYNC_PRIMITIVE_BLOCK *psSyncBlk, IMG_UINT32 ui32Offset, IMG_UINT32 ui32Value) |
| { |
| /* |
| We might be ask to PDump sync state outside of capture range |
| (e.g. texture uploads) so make this continuous. |
| */ |
| DevmemPDumpLoadMemValue32(psSyncBlk->psMemDesc, |
| ui32Offset, |
| ui32Value, |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimPDumpKM(SYNC_PRIMITIVE_BLOCK *psSyncBlk, IMG_UINT32 ui32Offset) |
| { |
| /* |
| We might be ask to PDump sync state outside of capture range |
| (e.g. texture uploads) so make this continuous. |
| */ |
| DevmemPDumpLoadMem(psSyncBlk->psMemDesc, |
| ui32Offset, |
| sizeof(IMG_UINT32), |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimPDumpPolKM(SYNC_PRIMITIVE_BLOCK *psSyncBlk, IMG_UINT32 ui32Offset, |
| IMG_UINT32 ui32Value, IMG_UINT32 ui32Mask, |
| PDUMP_POLL_OPERATOR eOperator, |
| PDUMP_FLAGS_T ui32PDumpFlags) |
| { |
| DevmemPDumpDevmemPol32(psSyncBlk->psMemDesc, |
| ui32Offset, |
| ui32Value, |
| ui32Mask, |
| eOperator, |
| ui32PDumpFlags); |
| |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimOpPDumpPolKM(SERVER_OP_COOKIE *psServerCookie, |
| PDUMP_POLL_OPERATOR eOperator, |
| PDUMP_FLAGS_T ui32PDumpFlags) |
| { |
| IMG_UINT32 i; |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| if (!psServerCookie->bActive) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: Operation cookie not active (no take operation performed)", __FUNCTION__)); |
| |
| eError = PVRSRV_ERROR_BAD_SYNC_STATE; |
| goto e0; |
| } |
| |
| /* PDump POL on the client syncs */ |
| for (i = 0; i < psServerCookie->ui32ClientSyncCount; i++) |
| { |
| if (psServerCookie->paui32Flags[i] & PVRSRV_CLIENT_SYNC_PRIM_OP_CHECK) |
| { |
| IMG_UINT32 ui32BlockIndex = psServerCookie->paui32SyncBlockIndex[i]; |
| IMG_UINT32 ui32Index = psServerCookie->paui32Index[i]; |
| SYNC_PRIMITIVE_BLOCK *psSyncBlock = psServerCookie->papsSyncPrimBlock[ui32BlockIndex]; |
| |
| PVRSRVSyncPrimPDumpPolKM(psSyncBlock, |
| ui32Index*sizeof(IMG_UINT32), |
| psServerCookie->paui32FenceValue[i], |
| 0xFFFFFFFFU, |
| eOperator, |
| ui32PDumpFlags); |
| } |
| } |
| |
| /* PDump POL on the server syncs */ |
| for (i = 0; i < psServerCookie->ui32ServerSyncCount; i++) |
| { |
| SERVER_SYNC_PRIMITIVE *psServerSync = psServerCookie->papsServerSync[i]; |
| IMG_UINT32 ui32FenceValue = psServerCookie->paui32ServerFenceValue[i]; |
| |
| SyncPrimPDumpPol(psServerSync->psSync, |
| ui32FenceValue, |
| 0xFFFFFFFFU, |
| PDUMP_POLL_OPERATOR_EQUAL, |
| ui32PDumpFlags); |
| } |
| |
| e0: |
| return eError; |
| } |
| |
| PVRSRV_ERROR |
| PVRSRVSyncPrimPDumpCBPKM(SYNC_PRIMITIVE_BLOCK *psSyncBlk, IMG_UINT64 ui32Offset, |
| IMG_UINT64 uiWriteOffset, IMG_UINT64 uiPacketSize, |
| IMG_UINT64 uiBufferSize) |
| { |
| DevmemPDumpCBP(psSyncBlk->psMemDesc, |
| ui32Offset, |
| uiWriteOffset, |
| uiPacketSize, |
| uiBufferSize); |
| return PVRSRV_OK; |
| } |
| #endif |
| |
| /* SyncRegisterConnection */ |
| PVRSRV_ERROR SyncRegisterConnection(SYNC_CONNECTION_DATA **ppsSyncConnectionData) |
| { |
| SYNC_CONNECTION_DATA *psSyncConnectionData; |
| PVRSRV_ERROR eError; |
| |
| psSyncConnectionData = OSAllocMem(sizeof(SYNC_CONNECTION_DATA)); |
| if (psSyncConnectionData == IMG_NULL) |
| { |
| eError = PVRSRV_ERROR_OUT_OF_MEMORY; |
| goto fail_alloc; |
| } |
| |
| eError = OSLockCreate(&psSyncConnectionData->hLock, LOCK_TYPE_PASSIVE); |
| if (eError != PVRSRV_OK) |
| { |
| goto fail_lockcreate; |
| } |
| dllist_init(&psSyncConnectionData->sListHead); |
| psSyncConnectionData->ui32RefCount = 1; |
| |
| *ppsSyncConnectionData = psSyncConnectionData; |
| return PVRSRV_OK; |
| |
| fail_lockcreate: |
| OSFreeMem(psSyncConnectionData); |
| fail_alloc: |
| PVR_ASSERT(eError != PVRSRV_OK); |
| return eError; |
| } |
| |
| /* SyncUnregisterConnection */ |
| IMG_VOID SyncUnregisterConnection(SYNC_CONNECTION_DATA *psSyncConnectionData) |
| { |
| _SyncConnectionUnref(psSyncConnectionData); |
| } |
| |
| static |
| IMG_BOOL _PDumpSyncBlock(PDLLIST_NODE psNode, IMG_PVOID pvCallbackData) |
| { |
| SYNC_PRIMITIVE_BLOCK *psSyncBlock = IMG_CONTAINER_OF(psNode, SYNC_PRIMITIVE_BLOCK, sConnectionNode); |
| PVR_UNREFERENCED_PARAMETER(pvCallbackData); |
| |
| DevmemPDumpLoadMem(psSyncBlock->psMemDesc, |
| 0, |
| psSyncBlock->ui32BlockSize, |
| PDUMP_FLAGS_CONTINUOUS); |
| return IMG_TRUE; |
| } |
| |
| IMG_VOID SyncConnectionPDumpSyncBlocks(SYNC_CONNECTION_DATA *psSyncConnectionData) |
| { |
| OSLockAcquire(psSyncConnectionData->hLock); |
| |
| PDUMPCOMMENT("Dump client Sync Prim state"); |
| dllist_foreach_node(&psSyncConnectionData->sListHead, |
| _PDumpSyncBlock, |
| IMG_NULL); |
| |
| OSLockRelease(psSyncConnectionData->hLock); |
| } |
| |
| PVRSRV_ERROR ServerSyncInit(IMG_VOID) |
| { |
| PVRSRV_ERROR eError; |
| |
| eError = OSLockCreate(&g_hListLock, LOCK_TYPE_NONE); |
| if (eError != PVRSRV_OK) |
| { |
| goto fail_lock_create; |
| } |
| dllist_init(&g_sAllServerSyncs); |
| |
| eError = PVRSRVRegisterDbgRequestNotify(&g_hNotify, |
| _ServerSyncDebugRequest, |
| DEBUG_REQUEST_SERVERSYNC, |
| IMG_NULL); |
| if (eError != PVRSRV_OK) |
| { |
| goto fail_dbg_register; |
| } |
| |
| return PVRSRV_OK; |
| |
| fail_dbg_register: |
| OSLockDestroy(g_hListLock);; |
| fail_lock_create: |
| return eError; |
| } |
| |
| IMG_VOID ServerSyncDeinit(IMG_VOID) |
| { |
| PVRSRVUnregisterDbgRequestNotify(g_hNotify); |
| OSLockDestroy(g_hListLock); |
| } |