1 /*************************************************************************/ /*!
3 @Title KM server Transport Layer implementation
4 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @Description Main bridge APIs for Transport Layer client functions
6 @License Dual MIT/GPLv2
8 The contents of this file are subject to the MIT license as set out below.
10 Permission is hereby granted, free of charge, to any person obtaining a copy
11 of this software and associated documentation files (the "Software"), to deal
12 in the Software without restriction, including without limitation the rights
13 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 copies of the Software, and to permit persons to whom the Software is
15 furnished to do so, subject to the following conditions:
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
20 Alternatively, the contents of this file may be used under the terms of
21 the GNU General Public License Version 2 ("GPL") in which case the provisions
22 of GPL are applicable instead of those above.
24 If you wish to allow use of your version of this file only under the terms of
25 GPL, and not to allow others to use your version of this file under the terms
26 of the MIT license, indicate your decision by deleting the provisions above
27 and replace them with the notice and other provisions required by GPL as set
28 out in the file called "GPL-COPYING" included in this distribution. If you do
29 not delete the provisions above, a recipient may use your version of this file
30 under the terms of either the MIT license or GPL.
32 This License is also included in this distribution in the file called
35 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
36 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
37 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
38 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
39 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
40 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
41 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 */ /**************************************************************************/
47 //#define PVR_DPF_FUNCTION_TRACE_ON 1
48 #undef PVR_DPF_FUNCTION_TRACE_ON
49 #include "pvr_debug.h"
51 #include "connection_server.h"
53 #include "devicemem.h"
59 #define NO_STREAM_WAIT_PERIOD 2000000ULL
60 #define NO_DATA_WAIT_PERIOD 1000000ULL
61 #define NO_ACQUIRE 0xffffffffU
63 #include "rgxhwperf.h"
66 * Transport Layer Client API Kernel-Mode bridge implementation
69 TLServerOpenStreamKM(const IMG_CHAR* pszName,
71 PTL_STREAM_DESC* ppsSD,
74 PVRSRV_ERROR eError = PVRSRV_OK;
75 PVRSRV_ERROR eErrorEO = PVRSRV_OK;
77 TL_STREAM_DESC* psNewSD = 0;
79 IMG_BOOL bIsWriteOnly = ui32Mode & PVRSRV_STREAM_FLAG_OPEN_WO ?
81 PTL_GLOBAL_DATA psGD = TLGGD();
83 #if defined(PVR_DPF_FUNCTION_TRACE_ON)
84 PVR_DPF((PVR_DBG_CALLTRACE, "--> %s:%d entered (%s, %x)", __func__, __LINE__, pszName, ui32Mode));
89 /* Acquire TL_GLOBAL_DATA lock here, as if the following TLFindStreamNodeByName
90 * returns NON NULL PTL_SNODE, we try updating the global data client count and
91 * PTL_SNODE's psRDesc and we want to make sure the TL_SNODE is valid (eg. has
92 * not been deleted) while we are updating it
94 OSLockAcquire (psGD->hTLGDLock);
96 psNode = TLFindStreamNodeByName(pszName);
97 if ((psNode == NULL) && (ui32Mode & PVRSRV_STREAM_FLAG_OPEN_WAIT))
98 { /* Blocking code to wait for stream to be created if it does not exist */
99 eError = OSEventObjectOpen(psGD->hTLEventObj, &hEvent);
100 PVR_LOGG_IF_ERROR (eError, "OSEventObjectOpen", e0);
104 if ((psNode = TLFindStreamNodeByName(pszName)) == NULL)
106 PVR_DPF((PVR_DBG_MESSAGE, "Stream %s does not exist, waiting...", pszName));
108 /* Release TL_GLOBAL_DATA lock before sleeping */
109 OSLockRelease (psGD->hTLGDLock);
111 /* Will exit OK or with timeout, both cases safe to ignore */
112 eErrorEO = OSEventObjectWaitTimeout(hEvent, NO_STREAM_WAIT_PERIOD);
114 /* Acquire lock after waking up */
115 OSLockAcquire (psGD->hTLGDLock);
118 while ((psNode == NULL) && (eErrorEO == PVRSRV_OK));
120 eError = OSEventObjectClose(hEvent);
121 PVR_LOGG_IF_ERROR (eError, "OSEventObjectClose", e0);
124 /* Make sure we have found a stream node after wait/search */
127 /* Did we exit the wait with timeout, inform caller */
128 if (eErrorEO == PVRSRV_ERROR_TIMEOUT)
134 eError = PVRSRV_ERROR_NOT_FOUND;
135 PVR_DPF((PVR_DBG_ERROR, "Stream \"%s\" does not exist", pszName));
140 /* Allocate memory for the stream. The memory will be allocated with the
142 eError = TLAllocSharedMemIfNull(psNode->psStream);
143 if (eError != PVRSRV_OK)
145 PVR_DPF((PVR_DBG_ERROR, "Failed to allocate memory for stream"
146 " \"%s\"", pszName));
153 /* If psWDesc == NULL it means that this is the first attempt
154 * to open stream for write. If yes create the descriptor or increment
155 * reference count otherwise. */
156 if (psNode->psWDesc == NULL)
158 psNewSD = TLMakeStreamDesc(psNode, ui32Mode, NULL);
159 psNode->psWDesc = psNewSD;
163 psNewSD = psNode->psWDesc;
164 psNode->psWDesc->uiRefCount++;
169 PVR_DPF((PVR_DBG_ERROR, "Not possible to make a new stream"
170 " writer descriptor"));
171 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
175 psNode->uiWRefCount++;
179 // Only one reader per stream supported
180 if (psNode->psRDesc != NULL)
182 PVR_DPF((PVR_DBG_ERROR, "Cannot open \"%s\" stream, stream already"
183 " opened", pszName));
184 eError = PVRSRV_ERROR_ALREADY_OPEN;
188 // Create an event handle for this client to wait on when no data in
190 eError = OSEventObjectOpen(psNode->hReadEventObj, &hEvent);
191 if (eError != PVRSRV_OK)
193 PVR_DPF((PVR_DBG_ERROR, "Not possible to open node's event object"));
194 eError = PVRSRV_ERROR_UNABLE_TO_CREATE_EVENT;
198 psNewSD = TLMakeStreamDesc(psNode, ui32Mode, hEvent);
199 psNode->psRDesc = psNewSD;
203 PVR_DPF((PVR_DBG_ERROR, "Not possible to make a new stream descriptor"));
204 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
208 PVR_DPF((PVR_DBG_VERBOSE,
209 "TLServerOpenStreamKM evList=%p, evObj=%p",
210 psNode->hReadEventObj,
211 psNode->psRDesc->hReadEvent));
214 // Copy the import handle back to the user mode API to enable access to
215 // the stream buffer from user-mode process.
216 eError = DevmemLocalGetImportHandle(TLStreamGetBufferPointer(psNode->psStream), (void**) ppsTLPMR);
217 PVR_LOGG_IF_ERROR(eError, "DevmemLocalGetImportHandle", e2);
221 /* Global data updated. Now release global lock */
222 OSLockRelease (psGD->hTLGDLock);
226 /* This callback is executed only on reader open. There are some actions
227 * executed on reader open that don't make much sense for writers e.g.
228 * injection on time synchronisation packet into the stream. */
229 if (!bIsWriteOnly && psNode->psStream->pfOnReaderOpenCallback != NULL)
231 psNode->psStream->pfOnReaderOpenCallback(
232 psNode->psStream->pvOnReaderOpenUserData);
237 /* Sending HWPerf event from TL is a temporary solution and this
238 * will change once TL is expanded by event allowing to signal
240 RGX_HWPERF_HOST_CTRL(CLIENT_STREAM_OPEN,
241 OSGetCurrentClientProcessIDKM());
244 PVR_DPF((PVR_DBG_MESSAGE, "%s: Stream %s opened for %s", __func__, pszName,
245 ui32Mode & PVRSRV_STREAM_FLAG_OPEN_WO ? "write" : "read"));
252 OSEventObjectClose(hEvent);
254 OSLockRelease (psGD->hTLGDLock);
255 PVR_DPF_RETURN_RC (eError);
259 TLServerCloseStreamKM(PTL_STREAM_DESC psSD)
261 PVRSRV_ERROR eError = PVRSRV_OK;
262 PTL_GLOBAL_DATA psGD = TLGGD();
263 PTL_SNODE psNode = 0;
265 IMG_BOOL bDestroyStream;
266 IMG_BOOL bIsWriteOnly = psSD->ui32Flags & PVRSRV_STREAM_FLAG_OPEN_WO ?
267 IMG_TRUE : IMG_FALSE;
273 // Sanity check, quick exit if there are no streams
274 if (psGD->psHead == NULL)
276 PVR_DPF_RETURN_RC(PVRSRV_ERROR_HANDLE_NOT_FOUND);
279 // Check stream still valid
280 psNode = TLFindStreamNodeByDesc(psSD);
281 if ((psNode == NULL) || (psNode != psSD->psNode))
283 PVR_DPF_RETURN_RC(PVRSRV_ERROR_HANDLE_NOT_FOUND);
286 /* Since the descriptor is valid, the stream should not have been made NULL */
287 PVR_ASSERT (psNode->psStream);
289 /* Save the stream's reference in-case its destruction is required after this
290 * client is removed */
291 psStream = psNode->psStream;
293 /* Acquire TL_GLOBAL_DATA lock as the following TLRemoveDescAndTryFreeStreamNode
294 * call will update the TL_SNODE's descriptor value */
295 OSLockAcquire (psGD->hTLGDLock);
297 /* Close event handle because event object list might be destroyed in
298 * TLUnrefDescAndTryFreeStreamNode(). */
301 // Close and free the event handle resource used by this descriptor
302 eError = OSEventObjectClose(psSD->hReadEvent);
303 if (eError != PVRSRV_OK)
305 // Log error but continue as it seems best
306 PVR_DPF((PVR_DBG_ERROR, "OSEventObjectClose() failed error %d",
308 eError = PVRSRV_ERROR_UNABLE_TO_DESTROY_EVENT;
313 /* Sending HWPerf event from TL is a temporary solution and this
314 * will change once TL is expanded by event allowing to signal
316 RGX_HWPERF_HOST_CTRL(CLIENT_STREAM_CLOSE,
317 OSGetCurrentClientProcessIDKM());
320 // Remove descriptor from stream object/list
321 bDestroyStream = TLUnrefDescAndTryFreeStreamNode (psNode, psSD);
323 // Assert the counter is sane after input data validated.
324 PVR_ASSERT(psGD->uiClientCnt > 0);
327 OSLockRelease (psGD->hTLGDLock);
329 /* Destroy the stream if its TL_SNODE was removed from TL_GLOBAL_DATA */
332 TLStreamDestroy (psStream);
336 PVR_DPF((PVR_DBG_VERBOSE, "%s: Stream closed", __func__));
338 /* Free the descriptor if ref count reaches 0. */
339 if (psSD->uiRefCount == 0)
341 // Free the stream descriptor object
345 PVR_DPF_RETURN_RC(eError);
349 TLServerReserveStreamKM(PTL_STREAM_DESC psSD,
350 IMG_UINT32* ui32BufferOffset,
352 IMG_UINT32 ui32SizeMin,
353 IMG_UINT32* pui32Available)
355 TL_GLOBAL_DATA* psGD = TLGGD();
356 PTL_SNODE psNode = 0;
357 IMG_UINT8* pui8Buffer = NULL;
364 if (!(psSD->ui32Flags & PVRSRV_STREAM_FLAG_OPEN_WO))
366 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
369 // Sanity check, quick exit if there are no streams
370 if (psGD->psHead == NULL)
372 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_ERROR);
375 /* Acquire the global lock. We have to be sure that no one modifies
376 * the list while we are looking for our stream. */
377 OSLockAcquire(psGD->hTLGDLock);
378 // Check stream still valid
379 psNode = TLFindAndGetStreamNodeByDesc(psSD);
380 OSLockRelease(psGD->hTLGDLock);
382 if ((psNode == NULL) || (psNode != psSD->psNode))
384 PVR_DPF_RETURN_RC(PVRSRV_ERROR_HANDLE_NOT_FOUND);
388 /* Since we have a valid stream descriptor, the stream should not have been
389 * made NULL by any producer context. */
390 PVR_ASSERT (psNode->psStream);
392 eError = TLStreamReserve2(psNode->psStream, &pui8Buffer, ui32Size,
393 ui32SizeMin, pui32Available);
394 if (eError != PVRSRV_OK)
396 PVR_DPF((PVR_DBG_WARNING, "Failed to reserve the stream (%d).", eError));
398 else if (pui8Buffer == NULL)
400 PVR_DPF((PVR_DBG_WARNING, "Not enough space in the stream."));
401 eError = PVRSRV_ERROR_STREAM_RESERVE_TOO_BIG;
405 *ui32BufferOffset = pui8Buffer - psNode->psStream->pbyBuffer;
406 PVR_ASSERT(*ui32BufferOffset < psNode->psStream->ui32Size);
409 OSLockAcquire(psGD->hTLGDLock);
410 TLReturnStreamNode(psNode);
411 OSLockRelease(psGD->hTLGDLock);
413 PVR_DPF_RETURN_RC(eError);
417 TLServerCommitStreamKM(PTL_STREAM_DESC psSD,
420 TL_GLOBAL_DATA* psGD = TLGGD();
421 PTL_SNODE psNode = 0;
428 if (!(psSD->ui32Flags & PVRSRV_STREAM_FLAG_OPEN_WO))
430 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
433 // Sanity check, quick exit if there are no streams
434 if (psGD->psHead == NULL)
436 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_ERROR);
439 /* Acquire the global lock. We have to be sure that no one modifies
440 * the list while we are looking for our stream. */
441 OSLockAcquire(psGD->hTLGDLock);
442 // Check stream still valid
443 psNode = TLFindAndGetStreamNodeByDesc(psSD);
444 OSLockRelease(psGD->hTLGDLock);
446 if ((psNode == NULL) || (psNode != psSD->psNode))
448 PVR_DPF_RETURN_RC(PVRSRV_ERROR_HANDLE_NOT_FOUND);
451 /* Since we have a valid stream descriptor, the stream should not have been
452 * made NULL by any producer context. */
453 PVR_ASSERT (psNode->psStream);
455 eError = TLStreamCommit(psNode->psStream, ui32Size);
456 if (eError != PVRSRV_OK)
458 PVR_DPF((PVR_DBG_ERROR, "Failed to commit data into stream."));
461 OSLockAcquire(psGD->hTLGDLock);
462 TLReturnStreamNode(psNode);
463 OSLockRelease(psGD->hTLGDLock);
465 PVR_DPF_RETURN_RC(eError);
469 TLServerDiscoverStreamsKM(const IMG_CHAR *pszNamePattern,
471 IMG_UINT32 *pui32Streams,
472 IMG_UINT32 *pui32NumFound)
474 if (*pszNamePattern == '\0')
475 return PVRSRV_ERROR_INVALID_PARAMS;
477 // Sanity check, quick exit if there are no streams
478 if (TLGGD()->psHead == NULL)
484 OSLockAcquire(TLGGD()->hTLGDLock);
485 *pui32NumFound = TLDiscoverStreamNodes(pszNamePattern, pui32Streams,
487 OSLockRelease(TLGGD()->hTLGDLock);
493 TLServerAcquireDataKM(PTL_STREAM_DESC psSD,
494 IMG_UINT32* puiReadOffset,
495 IMG_UINT32* puiReadLen)
497 PVRSRV_ERROR eError = PVRSRV_OK;
498 TL_GLOBAL_DATA* psGD = TLGGD();
499 IMG_UINT32 uiTmpOffset = NO_ACQUIRE;
500 IMG_UINT32 uiTmpLen = 0;
501 PTL_SNODE psNode = 0;
507 // Sanity check, quick exit if there are no streams
508 if (psGD->psHead == NULL)
510 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_ERROR);
513 // Check stream still valid
514 psNode = TLFindStreamNodeByDesc(psSD);
515 if ((psNode == NULL) || (psNode != psSD->psNode))
517 PVR_DPF_RETURN_RC(PVRSRV_ERROR_HANDLE_NOT_FOUND);
520 /* If we are here, the stream will never be made NULL until this context itself
521 * calls TLRemoveDescAndTryFreeStreamNode(). This is because the producer will
522 * fail to make the stream NULL (by calling TLTryRemoveStreamAndFreeStreamNode)
523 * when a valid stream descriptor is present (i.e. a client is connected).
524 * Hence, no checks for stream being NON NULL are required after this. */
525 PVR_ASSERT (psNode->psStream);
527 //PVR_DPF((PVR_DBG_VERBOSE, "TLServerAcquireDataKM evList=%p, evObj=%p", psSD->psNode->hReadEventObj, psSD->hReadEvent));
529 /* Check for data in the associated stream buffer, sleep/wait if none */
530 while (((uiTmpLen = TLStreamAcquireReadPos(psNode->psStream, &uiTmpOffset)) == 0) &&
531 (!(psSD->ui32Flags&PVRSRV_STREAM_FLAG_ACQUIRE_NONBLOCKING)) )
533 PVR_DPF((PVR_DBG_VERBOSE, "TLAcquireDataKM sleeping..."));
535 // Loop around if EndOfStream (nothing to read) and wait times out,
536 // exit loop if not time out but data is ready for client
537 while (TLStreamEOS(psNode->psStream))
539 eError = OSEventObjectWaitTimeout(psSD->hReadEvent, NO_DATA_WAIT_PERIOD);
540 if (eError != PVRSRV_OK)
542 /* Return timeout or other error condition to the caller who
543 * can choose to call again if desired. We don't block
544 * Indefinitely as we want the user mode application to have a
545 * chance to break out and end if it needs to, so we return the
546 * time out error code. */
547 PVR_DPF((PVR_DBG_VERBOSE, "TL Server timed out"));
548 PVR_DPF_RETURN_RC(eError);
552 PVR_DPF((PVR_DBG_VERBOSE, "TL Server signalled"));
557 /* Data available now if we reach here in blocking more or we take the
558 * values as is in non-blocking mode which might be all zeros. */
559 *puiReadOffset = uiTmpOffset;
560 *puiReadLen = uiTmpLen;
562 PVR_DPF((PVR_DBG_VERBOSE, "TLAcquireDataKM return offset=%d, len=%d bytes", *puiReadOffset, *puiReadLen));
568 TLServerReleaseDataKM(PTL_STREAM_DESC psSD,
569 IMG_UINT32 uiReadOffset,
570 IMG_UINT32 uiReadLen)
572 TL_GLOBAL_DATA* psGD = TLGGD();
573 PTL_SNODE psNode = 0;
577 /* Unreferenced in release builds */
578 PVR_UNREFERENCED_PARAMETER(uiReadOffset);
582 // Sanity check, quick exit if there are no streams
583 if (psGD->psHead == NULL)
585 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_ERROR);
588 // Check stream still valid
589 psNode = TLFindStreamNodeByDesc(psSD);
590 if ((psNode == NULL) || (psNode != psSD->psNode))
592 PVR_DPF_RETURN_RC(PVRSRV_ERROR_HANDLE_NOT_FOUND);
595 /* Since we have a valid stream descriptor, the stream should not have been
596 * made NULL by any producer context. */
597 PVR_ASSERT (psNode->psStream);
599 PVR_DPF((PVR_DBG_VERBOSE, "TLReleaseDataKM uiReadOffset=%d, uiReadLen=%d", uiReadOffset, uiReadLen));
601 // Move read position on to free up space in stream buffer
602 TLStreamAdvanceReadPos(psNode->psStream, uiReadLen);
608 TLServerWriteDataKM(PTL_STREAM_DESC psSD,
612 TL_GLOBAL_DATA* psGD = TLGGD();
613 PTL_SNODE psNode = 0;
620 if (!(psSD->ui32Flags & PVRSRV_STREAM_FLAG_OPEN_WO))
622 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
625 // Sanity check, quick exit if there are no streams
626 if (psGD->psHead == NULL)
628 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_ERROR);
631 OSLockAcquire(psGD->hTLGDLock);
632 // Check stream still valid
633 psNode = TLFindAndGetStreamNodeByDesc(psSD);
634 OSLockRelease(psGD->hTLGDLock);
636 if ((psNode == NULL) || (psNode != psSD->psNode))
638 PVR_DPF_RETURN_RC(PVRSRV_ERROR_HANDLE_NOT_FOUND);
641 /* Since we have a valid stream descriptor, the stream should not have been
642 * made NULL by any producer context. */
643 PVR_ASSERT (psNode->psStream);
645 eError = TLStreamWrite(psNode->psStream, pui8Data, ui32Size);
646 if (eError != PVRSRV_OK)
648 PVR_DPF((PVR_DBG_ERROR, "Failed to write data to the stream (%d).",
652 OSLockAcquire(psGD->hTLGDLock);
653 TLReturnStreamNode(psNode);
654 OSLockRelease(psGD->hTLGDLock);
656 PVR_DPF_RETURN_RC(eError);
659 /*****************************************************************************
660 End of file (tlserver.c)
661 *****************************************************************************/