1 /*************************************************************************/ /*!
3 @Title Server side connection management
4 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @Description Handles connections coming from the client and the management
6 connection based information
7 @License Dual MIT/GPLv2
9 The contents of this file are subject to the MIT license as set out below.
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
18 The above copyright notice and this permission notice shall be included in
19 all copies or substantial portions of the Software.
21 Alternatively, the contents of this file may be used under the terms of
22 the GNU General Public License Version 2 ("GPL") in which case the provisions
23 of GPL are applicable instead of those above.
25 If you wish to allow use of your version of this file only under the terms of
26 GPL, and not to allow others to use your version of this file under the terms
27 of the MIT license, indicate your decision by deleting the provisions above
28 and replace them with the notice and other provisions required by GPL as set
29 out in the file called "GPL-COPYING" included in this distribution. If you do
30 not delete the provisions above, a recipient may use your version of this file
31 under the terms of either the MIT license or GPL.
33 This License is also included in this distribution in the file called
36 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
37 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
38 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
39 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
40 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
41 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
42 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43 */ /**************************************************************************/
47 #include "connection_server.h"
48 #include "osconnection_server.h"
50 #include "pvr_debug.h"
51 #include "sync_server.h"
52 #include "process_stats.h"
58 /* PID associated with Connection currently being purged by Cleanup thread */
59 static IMG_PID gCurrentPurgeConnectionPid = 0;
61 static PVRSRV_ERROR ConnectionDataDestroy(CONNECTION_DATA *psConnection)
64 PROCESS_HANDLE_BASE *psProcessHandleBase;
65 IMG_UINT64 ui64MaxBridgeTime;
66 PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
68 if(psPVRSRVData->bUnload)
70 /* driver is unloading so do not allow the bridge lock to be released */
71 ui64MaxBridgeTime = 0;
75 ui64MaxBridgeTime = CONNECTION_DEFERRED_CLEANUP_TIMESLICE_NS;
78 if (psConnection == NULL)
80 PVR_DPF((PVR_DBG_ERROR, "ConnectionDestroy: Missing connection!"));
82 return PVRSRV_ERROR_INVALID_PARAMS;
85 /* Close the process statistics */
86 #if defined(PVRSRV_ENABLE_PROCESS_STATS) && !defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS)
87 if (psConnection->hProcessStats != NULL)
89 PVRSRVStatsDeregisterProcess(psConnection->hProcessStats);
90 psConnection->hProcessStats = NULL;
94 /* Close HWPerfClient stream here even though we created it in
95 * PVRSRVConnectKM(). */
96 if (psConnection->hClientTLStream)
98 TLStreamClose(psConnection->hClientTLStream);
99 psConnection->hClientTLStream = NULL;
100 PVR_DPF((PVR_DBG_MESSAGE, "Destroyed private stream."));
103 /* Get process handle base to decrement the refcount */
104 psProcessHandleBase = psConnection->psProcessHandleBase;
106 if (psProcessHandleBase != NULL)
108 /* In case the refcount becomes 0 we can remove the process handle base */
109 if (OSAtomicDecrement(&psProcessHandleBase->iRefCount) == 0)
111 uintptr_t uiHashValue;
113 OSLockAcquire(psPVRSRVData->hProcessHandleBase_Lock);
114 uiHashValue = HASH_Remove(psPVRSRVData->psProcessHandleBase_Table, psConnection->pid);
115 OSLockRelease(psPVRSRVData->hProcessHandleBase_Lock);
119 PVR_DPF((PVR_DBG_ERROR,
120 "%s: Failed to remove handle base from hash table.",
122 return PVRSRV_ERROR_UNABLE_TO_REMOVE_HASH_VALUE;
125 eError = PVRSRVFreeHandleBase(psProcessHandleBase->psHandleBase, ui64MaxBridgeTime);
126 if (eError != PVRSRV_OK)
128 if (eError != PVRSRV_ERROR_RETRY)
130 PVR_DPF((PVR_DBG_ERROR,
131 "ConnectionDataDestroy: Couldn't free handle base for process (%d)",
138 OSFreeMem(psProcessHandleBase);
141 psConnection->psProcessHandleBase = NULL;
144 /* Free handle base for this connection */
145 if (psConnection->psHandleBase != NULL)
147 eError = PVRSRVFreeHandleBase(psConnection->psHandleBase, ui64MaxBridgeTime);
148 if (eError != PVRSRV_OK)
150 if (eError != PVRSRV_ERROR_RETRY)
152 PVR_DPF((PVR_DBG_ERROR,
153 "ConnectionDataDestroy: Couldn't free handle base for connection (%d)",
160 psConnection->psHandleBase = NULL;
163 if (psConnection->psSyncConnectionData != NULL)
165 SyncUnregisterConnection(psConnection->psSyncConnectionData);
166 psConnection->psSyncConnectionData = NULL;
169 if (psConnection->psPDumpConnectionData != NULL)
171 PDumpUnregisterConnection(psConnection->psPDumpConnectionData);
172 psConnection->psPDumpConnectionData = NULL;
175 /* Call environment specific connection data deinit function */
176 if (psConnection->hOsPrivateData != NULL)
178 eError = OSConnectionPrivateDataDeInit(psConnection->hOsPrivateData);
179 if (eError != PVRSRV_OK)
181 PVR_DPF((PVR_DBG_ERROR,
182 "PVRSRVConnectionDataDestroy: OSConnectionPrivateDataDeInit failed (%d)",
188 psConnection->hOsPrivateData = NULL;
191 OSFreeMem(psConnection);
196 PVRSRV_ERROR PVRSRVConnectionConnect(void **ppvPrivData, void *pvOSData)
198 CONNECTION_DATA *psConnection;
200 PROCESS_HANDLE_BASE *psProcessHandleBase;
201 PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
203 /* Allocate connection data area */
204 psConnection = OSAllocZMem(sizeof(*psConnection));
205 if (psConnection == NULL)
207 PVR_DPF((PVR_DBG_ERROR,
208 "PVRSRVConnectionConnect: Couldn't allocate connection data"));
209 return PVRSRV_ERROR_OUT_OF_MEMORY;
212 /* Call environment specific connection data init function */
213 eError = OSConnectionPrivateDataInit(&psConnection->hOsPrivateData, pvOSData);
214 if (eError != PVRSRV_OK)
216 PVR_DPF((PVR_DBG_ERROR,
217 "PVRSRVConnectionConnect: OSConnectionPrivateDataInit failed (%d)",
222 psConnection->pid = OSGetCurrentClientProcessIDKM();
224 /* Register this connection with the sync core */
225 eError = SyncRegisterConnection(&psConnection->psSyncConnectionData);
226 if (eError != PVRSRV_OK)
228 PVR_DPF((PVR_DBG_ERROR,
229 "PVRSRVConnectionConnect: Couldn't register the sync data"));
234 * Register this connection with the pdump core. Pass in the sync connection data
235 * as it will be needed later when we only get passed in the PDump connection data.
237 eError = PDumpRegisterConnection(psConnection->psSyncConnectionData,
238 &psConnection->psPDumpConnectionData);
239 if (eError != PVRSRV_OK)
241 PVR_DPF((PVR_DBG_ERROR,
242 "PVRSRVConnectionConnect: Couldn't register the PDump data"));
246 /* Allocate handle base for this connection */
247 eError = PVRSRVAllocHandleBase(&psConnection->psHandleBase,
248 PVRSRV_HANDLE_BASE_TYPE_CONNECTION);
249 if (eError != PVRSRV_OK)
251 PVR_DPF((PVR_DBG_ERROR,
252 "PVRSRVConnectionConnect: Couldn't allocate handle base for connection (%d)",
257 /* Try to get process handle base if it already exists */
258 OSLockAcquire(psPVRSRVData->hProcessHandleBase_Lock);
259 psProcessHandleBase = (PROCESS_HANDLE_BASE*) HASH_Retrieve(PVRSRVGetPVRSRVData()->psProcessHandleBase_Table,
262 /* In case there is none we are going to allocate one */
263 if (psProcessHandleBase == NULL)
265 psProcessHandleBase = OSAllocZMem(sizeof(PROCESS_HANDLE_BASE));
266 if (psProcessHandleBase == NULL)
268 PVR_DPF((PVR_DBG_ERROR,
269 "%s: Failed to allocate handle base, oom.",
271 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
275 /* Allocate handle base for this process */
276 eError = PVRSRVAllocHandleBase(&psProcessHandleBase->psHandleBase,
277 PVRSRV_HANDLE_BASE_TYPE_PROCESS);
278 if (eError != PVRSRV_OK)
280 PVR_DPF((PVR_DBG_ERROR,
281 "%s: Couldn't allocate handle base for process (%d)",
284 OSFreeMem(psProcessHandleBase);
288 /* Insert the handle base into the global hash table */
289 if (!HASH_Insert(PVRSRVGetPVRSRVData()->psProcessHandleBase_Table,
291 (uintptr_t) psProcessHandleBase))
294 eError = PVRSRV_ERROR_UNABLE_TO_INSERT_HASH_VALUE;
296 PVRSRVFreeHandleBase(psProcessHandleBase->psHandleBase, 0);
298 OSFreeMem(psProcessHandleBase);
302 OSLockRelease(psPVRSRVData->hProcessHandleBase_Lock);
304 psConnection->psProcessHandleBase = psProcessHandleBase;
306 OSAtomicIncrement(&psProcessHandleBase->iRefCount);
308 /* Allocate process statistics */
309 #if defined(PVRSRV_ENABLE_PROCESS_STATS) && !defined(PVRSRV_DEBUG_LINUX_MEMORY_STATS)
310 eError = PVRSRVStatsRegisterProcess(&psConnection->hProcessStats);
311 if (eError != PVRSRV_OK)
313 PVR_DPF((PVR_DBG_ERROR,
314 "PVRSRVConnectionConnect: Couldn't register process statistics (%d)",
320 *ppvPrivData = psConnection;
325 OSLockRelease(psPVRSRVData->hProcessHandleBase_Lock);
327 ConnectionDataDestroy(psConnection);
332 static PVRSRV_ERROR _CleanupThreadPurgeConnectionData(void *pvConnectionData)
334 PVRSRV_ERROR eErrorConnection, eErrorKernel;
335 CONNECTION_DATA *psConnectionData = pvConnectionData;
337 OSAcquireBridgeLock();
339 gCurrentPurgeConnectionPid = psConnectionData->pid;
341 eErrorConnection = ConnectionDataDestroy(psConnectionData);
342 if (eErrorConnection != PVRSRV_OK)
344 if (eErrorConnection == PVRSRV_ERROR_RETRY)
346 PVR_DPF((PVR_DBG_MESSAGE,
347 "_CleanupThreadPurgeConnectionData: Failed to purge connection data %p "
348 "(deferring destruction)",
354 PVR_DPF((PVR_DBG_MESSAGE,
355 "_CleanupThreadPurgeConnectionData: Connection data %p deferred destruction finished",
359 /* Check if possible resize the global handle base */
360 eErrorKernel = PVRSRVPurgeHandles(KERNEL_HANDLE_BASE);
361 if (eErrorKernel != PVRSRV_OK)
363 PVR_DPF((PVR_DBG_ERROR,
364 "_CleanupThreadPurgeConnectionData: Purge of global handle pool failed (%d)",
368 gCurrentPurgeConnectionPid = 0;
370 OSReleaseBridgeLock();
372 return eErrorConnection;
375 void PVRSRVConnectionDisconnect(void *pvDataPtr)
377 CONNECTION_DATA *psConnectionData = pvDataPtr;
379 /* Notify the PDump core if the pdump control client is disconnecting */
380 if (psConnectionData->ui32ClientFlags & SRV_FLAGS_PDUMPCTRL)
382 PDumpDisconnectionNotify();
384 #if defined(PVRSRV_FORCE_UNLOAD_IF_BAD_STATE)
385 if (PVRSRVGetPVRSRVData()->eServicesState == PVRSRV_SERVICES_STATE_OK)
388 /* Defer the release of the connection data */
389 psConnectionData->sCleanupThreadFn.pfnFree = _CleanupThreadPurgeConnectionData;
390 psConnectionData->sCleanupThreadFn.pvData = psConnectionData;
391 psConnectionData->sCleanupThreadFn.ui32RetryCount = CLEANUP_THREAD_RETRY_COUNT_DEFAULT;
392 psConnectionData->sCleanupThreadFn.bDependsOnHW = IMG_FALSE;
393 PVRSRVCleanupThreadAddWork(&psConnectionData->sCleanupThreadFn);
397 IMG_PID PVRSRVGetPurgeConnectionPid(void)
399 return gCurrentPurgeConnectionPid;