1 /*************************************************************************/ /*!
3 @Title Transport Layer kernel side API implementation.
4 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @Description Transport Layer API implementation.
6 These functions are provided to driver components.
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 */ /**************************************************************************/
45 //#define PVR_DPF_FUNCTION_TRACE_ON 1
46 #undef PVR_DPF_FUNCTION_TRACE_ON
47 #include "pvr_debug.h"
50 #include "devicemem.h"
51 #include "pvrsrv_error.h"
55 #include "pvrsrv_tlcommon.h"
59 /* To debug buffer utilisation enable this macro here and
60 * define PVRSRV_NEED_PVR_TRACE in the server pvr_debug.c and in tutils.c
61 * before the inclusion of pvr_debug.h. Issue pvrtutils 6 on target to see
62 * stream buffer utilisation. */
63 //#define TL_BUFFER_UTILIZATION 1
65 #define EVENT_OBJECT_TIMEOUT_US 1000000ULL
67 /* Given the state of the buffer it returns a number of bytes that the client
68 * can use for a successful allocation. */
69 static INLINE IMG_UINT32 suggestAllocSize(IMG_UINT32 ui32LRead,
70 IMG_UINT32 ui32LWrite,
71 IMG_UINT32 ui32CBSize,
72 IMG_UINT32 ui32ReqSizeMin)
74 IMG_UINT32 ui32AvSpace = 0;
76 /* This could be written in fewer lines using the ? operator but it
77 would not be kind to potential readers of this source at all. */
78 if ( ui32LRead > ui32LWrite ) /* Buffer WRAPPED */
80 if ( (ui32LRead - ui32LWrite) > (sizeof(PVRSRVTL_PACKETHDR) + ui32ReqSizeMin + (IMG_INT) BUFFER_RESERVED_SPACE) )
82 ui32AvSpace = ui32LRead - ui32LWrite - sizeof(PVRSRVTL_PACKETHDR) - (IMG_INT) BUFFER_RESERVED_SPACE;
85 else /* Normal, no wrap */
87 if ( (ui32CBSize - ui32LWrite) > (sizeof(PVRSRVTL_PACKETHDR) + ui32ReqSizeMin + (IMG_INT) BUFFER_RESERVED_SPACE) )
89 ui32AvSpace = ui32CBSize - ui32LWrite - sizeof(PVRSRVTL_PACKETHDR) - (IMG_INT) BUFFER_RESERVED_SPACE;
91 else if ( (ui32LRead - 0) > (sizeof(PVRSRVTL_PACKETHDR) + ui32ReqSizeMin + (IMG_INT) BUFFER_RESERVED_SPACE) )
93 ui32AvSpace = ui32LRead - sizeof(PVRSRVTL_PACKETHDR) - (IMG_INT) BUFFER_RESERVED_SPACE;
96 /* The max size of a TL packet currently is UINT16. adjust accordingly */
97 return MIN(ui32AvSpace, PVRSRVTL_MAX_PACKET_SIZE);
100 /* Returns bytes left in the buffer. Negative if there is not any.
101 * two 4b aligned values are reserved, one for the write failed buffer flag
102 * and one to be able to distinguish the buffer full state to the buffer
104 * Always returns free space -8 even when the "write failed" packet may be
105 * already in the stream before this write. */
106 static INLINE IMG_INT
107 cbSpaceLeft(IMG_UINT32 ui32Read, IMG_UINT32 ui32Write, IMG_UINT32 ui32size)
109 /* We need to reserve 4b (one packet) in the buffer to be able to tell empty
110 * buffers from full buffers and one more for packet write fail packet */
111 if ( ui32Read > ui32Write )
113 return (IMG_INT) ui32Read - (IMG_INT)ui32Write - (IMG_INT) BUFFER_RESERVED_SPACE;
117 return (IMG_INT)ui32size - ((IMG_INT)ui32Write - (IMG_INT)ui32Read) - (IMG_INT) BUFFER_RESERVED_SPACE;
121 PVRSRV_ERROR TLAllocSharedMemIfNull(IMG_HANDLE hStream)
123 PTL_STREAM psStream = (PTL_STREAM) hStream;
126 IMG_CHAR pszBufferLabel[PRVSRVTL_MAX_STREAM_NAME_SIZE + 20];
127 DEVMEM_FLAGS_T uiMemFlags = PVRSRV_MEMALLOCFLAG_CPU_READABLE |
128 PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE |
129 PVRSRV_MEMALLOCFLAG_GPU_READABLE |
130 PVRSRV_MEMALLOCFLAG_CPU_UNCACHED |
131 PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE;
133 /* Exit if memory has already been allocated. */
134 if (psStream->pbyBuffer != NULL)
137 OSSNPrintf(pszBufferLabel, sizeof(pszBufferLabel), "TLStreamBuf-%s",
140 eError = DevmemAllocateExportable((IMG_HANDLE) TLGetGlobalRgxDevice(),
141 (IMG_DEVMEM_SIZE_T) psStream->ui32Size,
142 (IMG_DEVMEM_ALIGN_T) OSGetPageSize(),
143 ExactLog2(OSGetPageSize()),
146 &psStream->psStreamMemDesc);
147 PVR_LOGG_IF_ERROR(eError, "DevmemAllocateExportable", e0);
149 eError = DevmemAcquireCpuVirtAddr(psStream->psStreamMemDesc,
150 (void**) &psStream->pbyBuffer);
151 PVR_LOGG_IF_ERROR(eError, "DevmemAcquireCpuVirtAddr", e1);
156 DevmemFree(psStream->psStreamMemDesc);
161 void TLFreeSharedMem(IMG_HANDLE hStream)
163 PTL_STREAM psStream = (PTL_STREAM) hStream;
165 if (psStream->pbyBuffer != NULL)
167 DevmemReleaseCpuVirtAddr(psStream->psStreamMemDesc);
168 psStream->pbyBuffer = NULL;
170 if (psStream->psStreamMemDesc != NULL)
172 DevmemFree(psStream->psStreamMemDesc);
173 psStream->psStreamMemDesc = NULL;
177 /*******************************************************************************
178 * TL Server public API implementation.
179 ******************************************************************************/
181 TLStreamCreate(IMG_HANDLE *phStream,
182 IMG_CHAR *szStreamName,
184 IMG_UINT32 ui32StreamFlags,
185 TL_STREAM_ONREADEROPENCB pfOnReaderOpenCB,
186 void *pvOnRederOpenUD,
187 TL_STREAM_SOURCECB pfProducerCB,
192 IMG_HANDLE hEventList;
197 /* non NULL handler required */
198 if ( NULL == phStream )
200 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
202 if (szStreamName == NULL || *szStreamName == '\0' ||
203 OSStringLength(szStreamName) >= PRVSRVTL_MAX_STREAM_NAME_SIZE)
205 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
208 /* Acquire TL_GLOBAL_DATA lock here because, if the following TLFindStreamNodeByName()
209 * returns NULL, a new TL_SNODE will be added to TL_GLOBAL_DATA's TL_SNODE list */
210 OSLockAcquire (TLGGD()->hTLGDLock);
212 /* Check if there already exists a stream with this name. */
213 psn = TLFindStreamNodeByName( szStreamName );
216 eError = PVRSRV_ERROR_ALREADY_EXISTS;
220 /* Allocate stream structure container (stream struct) for the new stream */
221 psTmp = OSAllocZMem(sizeof(TL_STREAM)) ;
224 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
228 OSStringCopy(psTmp->szName, szStreamName);
230 if ( ui32StreamFlags & TL_FLAG_FORCE_FLUSH )
232 psTmp->bWaitForEmptyOnDestroy = IMG_TRUE;
235 psTmp->bNoSignalOnCommit = (ui32StreamFlags&TL_FLAG_NO_SIGNAL_ON_COMMIT) ? IMG_TRUE : IMG_FALSE;
237 if ( ui32StreamFlags & TL_FLAG_RESERVE_DROP_NEWER )
239 if ( ui32StreamFlags & TL_FLAG_RESERVE_BLOCK )
241 eError = PVRSRV_ERROR_INVALID_PARAMS;
244 psTmp->bDrop = IMG_TRUE;
246 else if ( ui32StreamFlags & TL_FLAG_RESERVE_BLOCK )
247 { /* Additional synchronization object required for this kind of stream */
248 psTmp->bBlock = IMG_TRUE;
251 eError = OSEventObjectCreate(NULL, &psTmp->hProducerEventObj);
252 if (eError != PVRSRV_OK)
256 /* Create an event handle for this kind of stream */
257 eError = OSEventObjectOpen(psTmp->hProducerEventObj, &psTmp->hProducerEvent);
258 if (eError != PVRSRV_OK)
263 psTmp->pfOnReaderOpenCallback = pfOnReaderOpenCB;
264 psTmp->pvOnReaderOpenUserData = pvOnRederOpenUD;
265 /* Remember producer supplied CB and data for later */
266 psTmp->pfProducerCallback = (void(*)(void))pfProducerCB;
267 psTmp->pvProducerUserData = pvProducerUD;
269 /* Round the requested bytes to a multiple of array elements' size, eg round 3 to 4 */
270 psTmp->ui32Size = PVRSRVTL_ALIGN(ui32Size);
272 psTmp->ui32Write = 0;
273 psTmp->ui32Pending = NOTHING_PENDING;
275 /* Memory will be allocated on first connect to the stream */
276 if (!(ui32StreamFlags & TL_FLAG_ALLOCATE_ON_FIRST_OPEN))
278 /* Allocate memory for the circular buffer and export it to user space. */
279 eError = TLAllocSharedMemIfNull(psTmp);
280 PVR_LOGG_IF_ERROR(eError, "TLAllocSharedMem", e3);
283 /* Synchronisation object to synchronise with user side data transfers. */
284 eError = OSEventObjectCreate(psTmp->szName, &hEventList);
285 if (eError != PVRSRV_OK)
290 eError = OSLockCreate (&psTmp->hStreamLock, LOCK_TYPE_PASSIVE);
291 if (eError != PVRSRV_OK)
296 /* Now remember the stream in the global TL structures */
297 psn = TLMakeSNode(hEventList, (TL_STREAM *)psTmp, 0);
300 eError=PVRSRV_ERROR_OUT_OF_MEMORY;
304 /* Stream node created, now reset the write reference count to 1
305 * (i.e. this context's reference) */
306 psn->uiWRefCount = 1;
308 TLAddStreamNode(psn);
310 /* Release TL_GLOBAL_DATA lock as the new TL_SNODE is now added to the list */
311 OSLockRelease (TLGGD()->hTLGDLock);
313 /* Best effort signal, client wait timeout will ultimately let it find the
314 * new stream if this fails, acceptable to avoid cleanup as it is tricky
316 (void) OSEventObjectSignal(TLGGD()->hTLEventObj);
318 /* Pass the newly created stream handle back to caller */
319 *phStream = (IMG_HANDLE)psTmp;
323 OSLockDestroy(psTmp->hStreamLock);
325 OSEventObjectDestroy(hEventList);
327 TLFreeSharedMem(psTmp);
329 OSEventObjectClose(psTmp->hProducerEvent);
331 OSEventObjectDestroy(psTmp->hProducerEventObj);
335 OSLockRelease (TLGGD()->hTLGDLock);
337 PVR_DPF_RETURN_RC(eError);
343 IMG_UINT32 ui32StreamFlags)
345 PVRSRV_ERROR eError = PVRSRV_OK;
350 if ( NULL == hStream )
352 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
355 psTmp = (PTL_STREAM)hStream;
357 /* Prevent the TL Stream buffer from being written to
358 * while its mode is being reconfigured
360 OSLockAcquire (psTmp->hStreamLock);
361 if ( NOTHING_PENDING != psTmp->ui32Pending )
363 OSLockRelease (psTmp->hStreamLock);
364 PVR_DPF_RETURN_RC(PVRSRV_ERROR_NOT_READY);
366 psTmp->ui32Pending = 0;
367 OSLockRelease (psTmp->hStreamLock);
369 if ( ui32StreamFlags & TL_FLAG_RESERVE_DROP_NEWER )
371 if ( ui32StreamFlags & TL_FLAG_RESERVE_BLOCK )
373 eError = PVRSRV_ERROR_INVALID_PARAMS;
376 psTmp->bDrop = IMG_TRUE;
377 psTmp->bBlock = IMG_FALSE;
379 else if ( ui32StreamFlags & TL_FLAG_RESERVE_BLOCK )
381 psTmp->bBlock = IMG_TRUE;
382 psTmp->bDrop = IMG_FALSE;
386 OSLockAcquire (psTmp->hStreamLock);
387 psTmp->ui32Pending = NOTHING_PENDING;
388 OSLockRelease (psTmp->hStreamLock);
390 PVR_DPF_RETURN_RC(eError);
394 TLStreamOpen(IMG_HANDLE *phStream,
395 IMG_CHAR *szStreamName)
397 PTL_SNODE psTmpSNode;
401 if ( NULL == phStream || NULL == szStreamName )
403 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
406 /* Acquire the TL_GLOBAL_DATA lock first to ensure,
407 * the TL_STREAM while returned and being modified,
408 * is not deleted by some other context */
409 OSLockAcquire (TLGGD()->hTLGDLock);
411 /* Search for a stream node with a matching stream name */
412 psTmpSNode = TLFindStreamNodeByName(szStreamName);
414 if ( NULL == psTmpSNode )
416 OSLockRelease (TLGGD()->hTLGDLock);
417 PVR_DPF_RETURN_RC(PVRSRV_ERROR_NOT_FOUND);
420 /* The TL_SNODE->uiWRefCount governs the presence of this node in the
421 * TL_GLOBAL_DATA list i.e. when uiWRefCount falls to zero we try removing
422 * this node from the TL_GLOBAL_DATA list. Hence, is protected using the
423 * TL_GLOBAL_DATA lock and not TL_STREAM lock */
424 psTmpSNode->uiWRefCount++;
426 OSLockRelease (TLGGD()->hTLGDLock);
428 /* Return the stream handle to the caller */
429 *phStream = (IMG_HANDLE)psTmpSNode->psStream;
431 PVR_DPF_RETURN_VAL(PVRSRV_OK);
435 TLStreamClose(IMG_HANDLE hStream)
438 IMG_BOOL bDestroyStream;
442 if ( NULL == hStream )
444 PVR_DPF((PVR_DBG_WARNING,
445 "TLStreamClose failed as NULL stream handler passed, nothing done."));
449 psTmp = (PTL_STREAM)hStream;
451 /* Acquire TL_GLOBAL_DATA lock for updating the reference count as this will be required
452 * in-case this TL_STREAM node is to be deleted */
453 OSLockAcquire (TLGGD()->hTLGDLock);
455 /* Decrement write reference counter of the stream */
456 psTmp->psNode->uiWRefCount--;
458 if ( 0 != psTmp->psNode->uiWRefCount )
459 { /* The stream is still being used in other context(s) do not destroy anything */
460 OSLockRelease (TLGGD()->hTLGDLock);
465 /* Now we try removing this TL_STREAM from TL_GLOBAL_DATA */
467 if ( psTmp->bWaitForEmptyOnDestroy == IMG_TRUE )
469 /* We won't require the TL_STREAM lock to be acquired here for accessing its read
470 * and write offsets. REASON: We are here because there is no producer context
471 * referencing this TL_STREAM, hence its ui32Write offset won't be changed now.
472 * Also, the updation of ui32Read offset is not protected by locks */
473 while (psTmp->ui32Read != psTmp->ui32Write)
475 /* Release lock before sleeping */
476 OSLockRelease (TLGGD()->hTLGDLock);
478 OSEventObjectWaitTimeout(psTmp->hProducerEvent, EVENT_OBJECT_TIMEOUT_US);
480 OSLockAcquire (TLGGD()->hTLGDLock);
482 /* Ensure destruction of stream is still required */
483 if (0 != psTmp->psNode->uiWRefCount)
485 OSLockRelease (TLGGD()->hTLGDLock);
491 /* Try removing the stream from TL_GLOBAL_DATA */
492 bDestroyStream = TLTryRemoveStreamAndFreeStreamNode (psTmp->psNode);
494 OSLockRelease (TLGGD()->hTLGDLock);
498 /* Destroy the stream if it was removed from TL_GLOBAL_DATA */
499 TLStreamDestroy (psTmp);
507 DoTLStreamReserve(IMG_HANDLE hStream,
508 IMG_UINT8 **ppui8Data,
509 IMG_UINT32 ui32ReqSize,
510 IMG_UINT32 ui32ReqSizeMin,
511 PVRSRVTL_PACKETTYPE ePacketType,
512 IMG_UINT32* pui32AvSpace)
515 IMG_UINT32 *pui32Buf, ui32LRead, ui32LWrite, ui32LPending, lReqSizeAligned, lReqSizeActual;
516 IMG_INT pad, iFreeSpace;
519 if (pui32AvSpace) *pui32AvSpace = 0;
521 if (( NULL == hStream ))
523 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
525 psTmp = (PTL_STREAM)hStream;
527 /* Assert used as the packet type parameter is currently only provided
528 * by the TL APIs, not the calling client */
529 PVR_ASSERT((PVRSRVTL_PACKETTYPE_UNDEF < ePacketType) && (PVRSRVTL_PACKETTYPE_LAST >= ePacketType));
531 /* The buffer is only used in "rounded" (aligned) chunks */
532 lReqSizeAligned = PVRSRVTL_ALIGN(ui32ReqSize);
534 /* Lock the stream before reading it's pending value, because if pending is set
535 * to NOTHING_PENDING, we update the pending value such that subsequent calls to
536 * this function from other context(s) fail with PVRSRV_ERROR_NOT_READY */
537 OSLockAcquire (psTmp->hStreamLock);
539 /* Get a local copy of the stream buffer parameters */
540 ui32LRead = psTmp->ui32Read ;
541 ui32LWrite = psTmp->ui32Write ;
542 ui32LPending = psTmp->ui32Pending ;
544 /* Multiple pending reserves are not supported. */
545 if ( NOTHING_PENDING != ui32LPending )
547 OSLockRelease (psTmp->hStreamLock);
548 PVR_DPF_RETURN_RC(PVRSRV_ERROR_NOT_READY);
551 if ( PVRSRVTL_MAX_PACKET_SIZE < lReqSizeAligned )
553 psTmp->ui32Pending = NOTHING_PENDING;
556 *pui32AvSpace = suggestAllocSize(ui32LRead, ui32LWrite, psTmp->ui32Size, ui32ReqSizeMin);
558 OSLockRelease (psTmp->hStreamLock);
559 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_RESERVE_TOO_BIG);
562 /* Prevent other threads from entering this region before we are done updating
563 * the pending value and write offset (incase of padding). This is not exactly
564 * a lock but a signal for other contexts that there is a TLStreamCommit operation
565 * pending on this stream */
566 psTmp->ui32Pending = 0;
568 OSLockRelease (psTmp->hStreamLock);
570 /* If there is enough contiguous space following the current Write
571 * position then no padding is required */
573 < ui32LWrite + lReqSizeAligned + sizeof(PVRSRVTL_PACKETHDR) )
575 pad = psTmp->ui32Size - ui32LWrite;
582 lReqSizeActual = lReqSizeAligned + sizeof(PVRSRVTL_PACKETHDR) + pad ;
583 /* If this is a blocking reserve and there is not enough space then wait. */
586 if( psTmp->ui32Size < lReqSizeActual )
588 /* Acquire stream lock for updating pending value */
589 OSLockAcquire (psTmp->hStreamLock);
590 psTmp->ui32Pending = NOTHING_PENDING;
591 OSLockRelease (psTmp->hStreamLock);
593 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_MISUSE);
595 while ( ( cbSpaceLeft(ui32LRead, ui32LWrite, psTmp->ui32Size)
596 <(IMG_INT) lReqSizeActual ) )
598 /* The TL should never drop the Bridge Lock as this can lead to
599 * deadlocks. See comment for TLStreamReconfigure.
601 OSEventObjectWaitAndHoldBridgeLock(psTmp->hProducerEvent);
602 // update local copies.
603 ui32LRead = psTmp->ui32Read ;
604 ui32LWrite = psTmp->ui32Write ;
608 iFreeSpace = cbSpaceLeft(ui32LRead, ui32LWrite, psTmp->ui32Size);
610 /* The easy case: buffer has enough space to hold the requested packet (data + header) */
611 if ( iFreeSpace >=(IMG_INT) lReqSizeActual )
615 /* Inserting padding packet. */
616 pui32Buf = (IMG_UINT32*)&psTmp->pbyBuffer[ui32LWrite];
617 *pui32Buf = PVRSRVTL_SET_PACKET_PADDING(pad-sizeof(PVRSRVTL_PACKETHDR)) ;
619 /* CAUTION: the used pad value should always result in a properly
620 * aligned ui32LWrite pointer, which in this case is 0 */
621 ui32LWrite = (ui32LWrite + pad) % psTmp->ui32Size;
622 /* Detect unaligned pad value */
623 PVR_ASSERT( ui32LWrite == 0);
625 /* Insert size-stamped packet header */
626 pui32Buf = (IMG_UINT32*) &psTmp->pbyBuffer[ui32LWrite];
628 *pui32Buf = PVRSRVTL_SET_PACKET_HDR(ui32ReqSize, ePacketType);
630 /* return the next position in the buffer to the user */
631 *ppui8Data = &psTmp->pbyBuffer[ ui32LWrite+sizeof(PVRSRVTL_PACKETHDR) ] ;
633 /* update pending offset: size stamp + data */
634 ui32LPending = lReqSizeAligned + sizeof(PVRSRVTL_PACKETHDR) ;
636 /* The not so easy case: not enough space, decide how to handle data */
641 /* Sanity check that the user is not trying to add more data than the
642 * buffer size. Conditionally compile it out to ensure this check has
643 * no impact to release performance */
644 if ( lReqSizeAligned+sizeof(PVRSRVTL_PACKETHDR) > psTmp->ui32Size )
646 OSLockAcquire (psTmp->hStreamLock);
647 psTmp->ui32Pending = NOTHING_PENDING;
648 OSLockRelease (psTmp->hStreamLock);
649 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_MISUSE);
653 /* No data overwriting, insert write_failed flag and return */
656 /* Caller should not try to use ppui8Data,
657 * NULLify to give user a chance of avoiding memory corruption */
660 /* This flag should not be inserted two consecutive times, so
661 * check the last ui32 in case it was a packet drop packet. */
662 pui32Buf = ui32LWrite
664 (IMG_UINT32*)&psTmp->pbyBuffer[ui32LWrite - sizeof(PVRSRVTL_PACKETHDR)]
665 : // Previous four bytes are not guaranteed to be a packet header...
666 (IMG_UINT32*)&psTmp->pbyBuffer[psTmp->ui32Size - PVRSRVTL_PACKET_ALIGNMENT];
668 if ( PVRSRVTL_PACKETTYPE_MOST_RECENT_WRITE_FAILED
670 GET_PACKET_TYPE( (PVRSRVTL_PACKETHDR*)pui32Buf ) )
672 /* Insert size-stamped packet header */
673 pui32Buf = (IMG_UINT32*)&psTmp->pbyBuffer[ui32LWrite];
674 *pui32Buf = PVRSRVTL_SET_PACKET_WRITE_FAILED ;
675 ui32LWrite += sizeof(PVRSRVTL_PACKETHDR);
676 ui32LWrite %= psTmp->ui32Size;
677 iFreeSpace -= sizeof(PVRSRVTL_PACKETHDR);
680 OSLockAcquire (psTmp->hStreamLock);
681 psTmp->ui32Write = ui32LWrite;
682 psTmp->ui32Pending = NOTHING_PENDING;
683 OSLockRelease (psTmp->hStreamLock);
687 *pui32AvSpace = suggestAllocSize(ui32LRead, ui32LWrite, psTmp->ui32Size, ui32ReqSizeMin);
689 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_RESERVE_TOO_BIG);
693 /* Acquire stream lock for updating stream parameters */
694 OSLockAcquire (psTmp->hStreamLock);
695 psTmp->ui32Write = ui32LWrite ;
696 psTmp->ui32Pending = ui32LPending ;
697 OSLockRelease (psTmp->hStreamLock);
703 TLStreamReserve(IMG_HANDLE hStream,
704 IMG_UINT8 **ppui8Data,
707 return DoTLStreamReserve(hStream, ppui8Data, ui32Size, ui32Size, PVRSRVTL_PACKETTYPE_DATA, NULL);
711 TLStreamReserve2(IMG_HANDLE hStream,
712 IMG_UINT8 **ppui8Data,
714 IMG_UINT32 ui32SizeMin,
715 IMG_UINT32* pui32Available)
717 return DoTLStreamReserve(hStream, ppui8Data, ui32Size, ui32SizeMin, PVRSRVTL_PACKETTYPE_DATA, pui32Available);
721 TLStreamCommit(IMG_HANDLE hStream, IMG_UINT32 ui32ReqSize)
724 IMG_UINT32 ui32LRead, ui32OldWrite, ui32LWrite, ui32LPending;
729 if ( NULL == hStream )
731 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
733 psTmp = (PTL_STREAM)hStream;
735 /* Get a local copy of the stream buffer parameters */
736 ui32LRead = psTmp->ui32Read ;
737 ui32LWrite = psTmp->ui32Write ;
738 ui32LPending = psTmp->ui32Pending ;
740 ui32OldWrite = ui32LWrite;
742 // Space in buffer is aligned
743 ui32ReqSize = PVRSRVTL_ALIGN(ui32ReqSize) + sizeof(PVRSRVTL_PACKETHDR);
745 /* Check pending reserver and ReqSize + packet header size. */
746 if ((ui32LPending == NOTHING_PENDING) || (ui32ReqSize > ui32LPending))
748 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_MISUSE);
751 /* Update pointer to written data. */
752 ui32LWrite = (ui32LWrite + ui32ReqSize) % psTmp->ui32Size;
754 /* and reset LPending to 0 since data are now submitted */
755 ui32LPending = NOTHING_PENDING;
757 /* Calculate high water mark for debug purposes */
758 #if defined(TL_BUFFER_UTILIZATION)
761 if (ui32LWrite > ui32LRead)
763 tmp = (ui32LWrite-ui32LRead);
765 else if (ui32LWrite < ui32LRead)
767 tmp = (psTmp->ui32Size-ui32LRead+ui32LWrite);
768 } /* else equal, ignore */
770 if (tmp > psTmp->ui32BufferUt)
772 psTmp->ui32BufferUt = tmp;
777 /* Acquire stream lock to ensure other context(s) (if any)
778 * wait on the lock (in DoTLStreamReserve) for consistent values
779 * of write offset and pending value */
780 OSLockAcquire (psTmp->hStreamLock);
782 /* Update stream buffer parameters to match local copies */
783 psTmp->ui32Write = ui32LWrite ;
784 psTmp->ui32Pending = ui32LPending ;
786 OSLockRelease (psTmp->hStreamLock);
788 /* If we have transitioned from an empty buffer to a non-empty buffer,
789 * signal any consumers that may be waiting */
790 if (ui32OldWrite == ui32LRead && !psTmp->bNoSignalOnCommit)
792 /* Signal consumers that may be waiting */
793 eError = OSEventObjectSignal(psTmp->psNode->hReadEventObj);
794 if ( eError != PVRSRV_OK)
796 PVR_DPF_RETURN_RC(eError);
804 TLStreamWrite(IMG_HANDLE hStream, IMG_UINT8 *pui8Src, IMG_UINT32 ui32Size)
806 IMG_BYTE *pbyDest = NULL;
811 if ( NULL == hStream )
813 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
816 eError = TLStreamReserve(hStream, &pbyDest, ui32Size);
817 if ( PVRSRV_OK != eError )
819 PVR_DPF_RETURN_RC(eError);
823 OSDeviceMemCopy((void*)pbyDest, (void*)pui8Src, ui32Size);
824 eError = TLStreamCommit(hStream, ui32Size);
825 if ( PVRSRV_OK != eError )
827 PVR_DPF_RETURN_RC(eError);
832 /* A NULL ptr returned from TLStreamReserve indicates the TL buffer is full */
833 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_RESERVE_TOO_BIG);
838 void TLStreamInfo(PTL_STREAM_INFO psInfo)
840 IMG_DEVMEM_SIZE_T actual_req_size;
841 IMG_DEVMEM_ALIGN_T align = 4; /* Low dummy value so the real value can be obtained */
844 DevmemExportalignAdjustSizeAndAlign(OSGetPageShift(), &actual_req_size, &align);
846 psInfo->headerSize = sizeof(PVRSRVTL_PACKETHDR);
847 psInfo->minReservationSize = sizeof(IMG_UINT32);
848 psInfo->pageSize = (IMG_UINT32)(actual_req_size);
849 psInfo->pageAlign = (IMG_UINT32)(align);
853 TLStreamMarkEOS(IMG_HANDLE psStream)
860 if ( NULL == psStream )
862 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
865 eError = DoTLStreamReserve(psStream, &pData, 0, 0, PVRSRVTL_PACKETTYPE_MARKER_EOS, NULL);
866 if ( PVRSRV_OK != eError )
868 PVR_DPF_RETURN_RC(eError);
871 PVR_DPF_RETURN_RC(TLStreamCommit(psStream, 0));
875 TLStreamSync(IMG_HANDLE psStream)
877 PVRSRV_ERROR eError = PVRSRV_OK;
882 if ( NULL == psStream )
884 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
886 psTmp = (PTL_STREAM)psStream;
888 /* If read client exists and has opened stream in blocking mode,
889 * signal when data is available to read. */
890 if (psTmp->psNode->psRDesc &&
891 (!(psTmp->psNode->psRDesc->ui32Flags & PVRSRV_STREAM_FLAG_ACQUIRE_NONBLOCKING)) &&
892 psTmp->ui32Read != psTmp->ui32Write)
894 eError = OSEventObjectSignal(psTmp->psNode->hReadEventObj);
897 PVR_DPF_RETURN_RC(eError);
901 * Internal stream APIs to server part of Transport Layer, declared in
902 * header tlintern.h. Direct pointers to stream objects are used here as
903 * these functions are internal.
906 TLStreamAcquireReadPos(PTL_STREAM psStream, IMG_UINT32* puiReadOffset)
908 IMG_UINT32 uiReadLen = 0;
909 IMG_UINT32 ui32LRead, ui32LWrite;
913 PVR_ASSERT(psStream);
914 PVR_ASSERT(puiReadOffset);
916 /* Grab a local copy */
917 ui32LRead = psStream->ui32Read;
918 ui32LWrite = psStream->ui32Write;
920 /* No data available and CB defined - try and get data */
921 if ((ui32LRead == ui32LWrite) && psStream->pfProducerCallback)
924 IMG_UINT32 ui32Resp = 0;
926 eRc = ((TL_STREAM_SOURCECB)psStream->pfProducerCallback)(psStream, TL_SOURCECB_OP_CLIENT_EOS,
927 &ui32Resp, psStream->pvProducerUserData);
928 PVR_LOG_IF_ERROR(eRc, "TLStream->pfProducerCallback");
930 ui32LWrite = psStream->ui32Write;
933 /* No data available... */
934 if (ui32LRead == ui32LWrite)
936 PVR_DPF_RETURN_VAL(0);
939 /* Data is available to read... */
940 *puiReadOffset = ui32LRead;
942 /*PVR_DPF((PVR_DBG_VERBOSE,
943 * "TLStreamAcquireReadPos Start before: Write:%d, Read:%d, size:%d",
944 * ui32LWrite, ui32LRead, psStream->ui32Size));
947 if ( ui32LRead > ui32LWrite )
948 { /* CB has wrapped around.
949 * Return the first contiguous piece of memory, ie [ReadLen,EndOfBuffer]
950 * and let a subsequent AcquireReadPos read the rest of the Buffer */
951 /*PVR_DPF((PVR_DBG_VERBOSE, "TLStreamAcquireReadPos buffer has wrapped"));*/
952 uiReadLen = psStream->ui32Size - ui32LRead;
955 { // CB has not wrapped
956 uiReadLen = ui32LWrite - ui32LRead;
959 PVR_DPF_RETURN_VAL(uiReadLen);
963 TLStreamAdvanceReadPos(PTL_STREAM psStream, IMG_UINT32 uiReadLen)
967 PVR_ASSERT(psStream);
969 /* Update the read offset by the length provided in a circular manner.
970 * Assuming the updation to be atomic hence, avoiding use of locks */
971 psStream->ui32Read = (psStream->ui32Read + uiReadLen) % psStream->ui32Size;
973 /* notify reserves that may be pending */
974 /* The producer event object is used to signal the StreamReserve if the TL
975 * Buffer is in blocking mode and is full.
976 * Previously this event was only signalled if the buffer was created in
977 * blocking mode. Since the buffer mode can now change dynamically the event
978 * is signalled every time to avoid any potential race where the signal is
979 * required, but not produced.
983 eError = OSEventObjectSignal(psStream->hProducerEventObj);
984 if ( eError != PVRSRV_OK)
986 PVR_DPF((PVR_DBG_WARNING,
987 "Error in TLStreamAdvanceReadPos: OSEventObjectSignal returned:%u",
992 PVR_DPF((PVR_DBG_VERBOSE,
993 "TLStreamAdvanceReadPos Read now at: %d",
994 psStream->ui32Read));
999 TLStreamDestroy (PTL_STREAM psStream)
1001 PVR_ASSERT (psStream);
1003 OSLockDestroy (psStream->hStreamLock);
1005 OSEventObjectClose(psStream->hProducerEvent);
1006 OSEventObjectDestroy(psStream->hProducerEventObj);
1008 TLFreeSharedMem(psStream);
1009 OSFreeMem(psStream);
1013 TLStreamGetBufferPointer(PTL_STREAM psStream)
1017 PVR_ASSERT(psStream);
1019 PVR_DPF_RETURN_VAL(psStream->psStreamMemDesc);
1023 TLStreamEOS(PTL_STREAM psStream)
1027 PVR_ASSERT(psStream);
1029 /* If both pointers are equal then the buffer is empty */
1030 PVR_DPF_RETURN_VAL( psStream->ui32Read == psStream->ui32Write );