RK3368 GPU: Rogue N Init.
[firefly-linux-kernel-4.4.55.git] / drivers / staging / imgtec / rogue / tlstream.c
1 /*************************************************************************/ /*!
2 @File
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
8
9 The contents of this file are subject to the MIT license as set out below.
10
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:
17
18 The above copyright notice and this permission notice shall be included in
19 all copies or substantial portions of the Software.
20
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.
24
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.
32
33 This License is also included in this distribution in the file called
34 "MIT-COPYING".
35
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 */ /**************************************************************************/
44
45 //#define PVR_DPF_FUNCTION_TRACE_ON 1
46 #undef PVR_DPF_FUNCTION_TRACE_ON
47 #include "pvr_debug.h"
48
49 #include "allocmem.h"
50 #include "devicemem.h"
51 #include "pvrsrv_error.h"
52 #include "osfunc.h"
53 #include "log2.h"
54
55 #include "pvrsrv_tlcommon.h"
56 #include "tlintern.h"
57 #include "tlstream.h"
58
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
64
65 #define EVENT_OBJECT_TIMEOUT_US 1000000ULL
66
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)
73 {
74         IMG_UINT32 ui32AvSpace = 0;
75         
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 */
79         {
80                 if ( (ui32LRead - ui32LWrite) > (sizeof(PVRSRVTL_PACKETHDR) + ui32ReqSizeMin + (IMG_INT) BUFFER_RESERVED_SPACE) )
81                 {
82                         ui32AvSpace =  ui32LRead - ui32LWrite - sizeof(PVRSRVTL_PACKETHDR) - (IMG_INT) BUFFER_RESERVED_SPACE;
83                 }
84         }
85         else                                                  /* Normal, no wrap */
86         {
87                 if ( (ui32CBSize - ui32LWrite) > (sizeof(PVRSRVTL_PACKETHDR) + ui32ReqSizeMin + (IMG_INT) BUFFER_RESERVED_SPACE) )
88                 {
89                         ui32AvSpace =  ui32CBSize - ui32LWrite - sizeof(PVRSRVTL_PACKETHDR) - (IMG_INT) BUFFER_RESERVED_SPACE;
90                 }
91                 else if ( (ui32LRead - 0) > (sizeof(PVRSRVTL_PACKETHDR) + ui32ReqSizeMin + (IMG_INT) BUFFER_RESERVED_SPACE) )
92                 {
93                         ui32AvSpace =  ui32LRead - sizeof(PVRSRVTL_PACKETHDR) - (IMG_INT) BUFFER_RESERVED_SPACE;
94                 }
95         }
96     /* The max size of a TL packet currently is UINT16. adjust accordingly */
97         return MIN(ui32AvSpace, PVRSRVTL_MAX_PACKET_SIZE);
98 }
99
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
103  * empty state.
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)
108 {
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 )
112         {
113                 return (IMG_INT) ui32Read - (IMG_INT)ui32Write - (IMG_INT) BUFFER_RESERVED_SPACE;
114         }
115         else
116         {
117                 return (IMG_INT)ui32size - ((IMG_INT)ui32Write - (IMG_INT)ui32Read) - (IMG_INT) BUFFER_RESERVED_SPACE;
118         }
119 }   
120
121 PVRSRV_ERROR TLAllocSharedMemIfNull(IMG_HANDLE hStream)
122 {
123         PTL_STREAM psStream = (PTL_STREAM) hStream;
124         PVRSRV_ERROR eError;
125
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;
132
133         /* Exit if memory has already been allocated. */
134         if (psStream->pbyBuffer != NULL)
135                 return PVRSRV_OK;
136
137         OSSNPrintf(pszBufferLabel, sizeof(pszBufferLabel), "TLStreamBuf-%s",
138                    psStream->szName);
139
140         eError = DevmemAllocateExportable((IMG_HANDLE) TLGetGlobalRgxDevice(),
141                                           (IMG_DEVMEM_SIZE_T) psStream->ui32Size,
142                                           (IMG_DEVMEM_ALIGN_T) OSGetPageSize(),
143                                           ExactLog2(OSGetPageSize()),
144                                           uiMemFlags,
145                                           pszBufferLabel,
146                                           &psStream->psStreamMemDesc);
147         PVR_LOGG_IF_ERROR(eError, "DevmemAllocateExportable", e0);
148
149         eError = DevmemAcquireCpuVirtAddr(psStream->psStreamMemDesc,
150                                           (void**) &psStream->pbyBuffer);
151         PVR_LOGG_IF_ERROR(eError, "DevmemAcquireCpuVirtAddr", e1);
152
153         return PVRSRV_OK;
154
155 e1:
156         DevmemFree(psStream->psStreamMemDesc);
157 e0:
158         return eError;
159 }
160
161 void TLFreeSharedMem(IMG_HANDLE hStream)
162 {
163         PTL_STREAM psStream = (PTL_STREAM) hStream;
164
165         if (psStream->pbyBuffer != NULL)
166         {
167                 DevmemReleaseCpuVirtAddr(psStream->psStreamMemDesc);
168                 psStream->pbyBuffer = NULL;
169         }
170         if (psStream->psStreamMemDesc != NULL)
171         {
172                 DevmemFree(psStream->psStreamMemDesc);
173                 psStream->psStreamMemDesc = NULL;
174         }
175 }
176
177 /******************************************************************************* 
178  * TL Server public API implementation.
179  ******************************************************************************/
180 PVRSRV_ERROR
181 TLStreamCreate(IMG_HANDLE *phStream,
182                            IMG_CHAR *szStreamName,
183                            IMG_UINT32 ui32Size,
184                            IMG_UINT32 ui32StreamFlags,
185                TL_STREAM_ONREADEROPENCB pfOnReaderOpenCB,
186                void *pvOnRederOpenUD,
187                TL_STREAM_SOURCECB pfProducerCB,
188                void *pvProducerUD)
189 {
190         PTL_STREAM     psTmp;
191         PVRSRV_ERROR   eError;
192         IMG_HANDLE     hEventList;
193         PTL_SNODE      psn = 0;
194
195         PVR_DPF_ENTERED;
196         /* Sanity checks:  */
197         /* non NULL handler required */
198         if ( NULL == phStream )
199         {
200                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
201         }
202         if (szStreamName == NULL || *szStreamName == '\0' ||
203             OSStringLength(szStreamName) >= PRVSRVTL_MAX_STREAM_NAME_SIZE)
204         {
205                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
206         }
207
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);
211
212         /* Check if there already exists a stream with this name. */
213         psn = TLFindStreamNodeByName( szStreamName );
214         if ( NULL != psn )
215         {
216                 eError = PVRSRV_ERROR_ALREADY_EXISTS;
217                 goto e0;
218         }
219
220         /* Allocate stream structure container (stream struct) for the new stream */
221         psTmp = OSAllocZMem(sizeof(TL_STREAM)) ;
222         if ( NULL == psTmp ) 
223         {
224                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
225                 goto e0;
226         }
227
228         OSStringCopy(psTmp->szName, szStreamName);
229
230         if ( ui32StreamFlags & TL_FLAG_FORCE_FLUSH )
231         {
232                 psTmp->bWaitForEmptyOnDestroy = IMG_TRUE;
233         }
234
235         psTmp->bNoSignalOnCommit = (ui32StreamFlags&TL_FLAG_NO_SIGNAL_ON_COMMIT) ?  IMG_TRUE : IMG_FALSE;
236
237         if ( ui32StreamFlags & TL_FLAG_RESERVE_DROP_NEWER ) 
238         {
239                 if ( ui32StreamFlags & TL_FLAG_RESERVE_BLOCK ) 
240                 {
241                         eError = PVRSRV_ERROR_INVALID_PARAMS;
242                         goto e1;
243                 }
244                 psTmp->bDrop = IMG_TRUE;
245         }
246         else if ( ui32StreamFlags & TL_FLAG_RESERVE_BLOCK ) 
247     {   /* Additional synchronization object required for this kind of stream */
248         psTmp->bBlock = IMG_TRUE;
249     }
250
251         eError = OSEventObjectCreate(NULL, &psTmp->hProducerEventObj);
252         if (eError != PVRSRV_OK)
253         {
254                 goto e1;
255         }
256         /* Create an event handle for this kind of stream */
257         eError = OSEventObjectOpen(psTmp->hProducerEventObj, &psTmp->hProducerEvent);
258         if (eError != PVRSRV_OK)
259         {
260                 goto e2;
261         }
262
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;
268
269         /* Round the requested bytes to a multiple of array elements' size, eg round 3 to 4 */
270         psTmp->ui32Size = PVRSRVTL_ALIGN(ui32Size);
271         psTmp->ui32Read = 0;
272         psTmp->ui32Write = 0;
273         psTmp->ui32Pending = NOTHING_PENDING;
274
275         /* Memory will be allocated on first connect to the stream */
276         if (!(ui32StreamFlags & TL_FLAG_ALLOCATE_ON_FIRST_OPEN))
277         {
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);
281         }
282
283         /* Synchronisation object to synchronise with user side data transfers. */
284         eError = OSEventObjectCreate(psTmp->szName, &hEventList);
285         if (eError != PVRSRV_OK)
286         {
287                 goto e4;
288         }
289
290         eError = OSLockCreate (&psTmp->hStreamLock, LOCK_TYPE_PASSIVE);
291         if (eError != PVRSRV_OK)
292         {
293                 goto e5;
294         }
295
296         /* Now remember the stream in the global TL structures */
297         psn = TLMakeSNode(hEventList, (TL_STREAM *)psTmp, 0);
298         if (psn == NULL)
299         {
300                 eError=PVRSRV_ERROR_OUT_OF_MEMORY;
301                 goto e6;
302         }
303
304         /* Stream node created, now reset the write reference count to 1
305          * (i.e. this context's reference) */
306         psn->uiWRefCount = 1;
307
308         TLAddStreamNode(psn);
309
310         /* Release TL_GLOBAL_DATA lock as the new TL_SNODE is now added to the list */
311         OSLockRelease (TLGGD()->hTLGDLock);
312
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
315          * at this point */
316         (void) OSEventObjectSignal(TLGGD()->hTLEventObj);
317
318         /* Pass the newly created stream handle back to caller */
319         *phStream = (IMG_HANDLE)psTmp;
320         PVR_DPF_RETURN_OK;
321
322 e6:
323         OSLockDestroy(psTmp->hStreamLock);
324 e5:
325         OSEventObjectDestroy(hEventList);
326 e4:
327         TLFreeSharedMem(psTmp);
328 e3:
329         OSEventObjectClose(psTmp->hProducerEvent);
330 e2:
331         OSEventObjectDestroy(psTmp->hProducerEventObj);
332 e1:
333         OSFreeMem(psTmp);
334 e0:
335         OSLockRelease (TLGGD()->hTLGDLock);
336
337         PVR_DPF_RETURN_RC(eError);
338 }
339
340 PVRSRV_ERROR
341 TLStreamReconfigure(
342                 IMG_HANDLE hStream,
343                 IMG_UINT32 ui32StreamFlags)
344 {
345         PVRSRV_ERROR eError = PVRSRV_OK;
346         PTL_STREAM psTmp;
347
348         PVR_DPF_ENTERED;
349
350         if ( NULL == hStream )
351         {
352                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
353         }
354
355         psTmp = (PTL_STREAM)hStream;
356
357         /* Prevent the TL Stream buffer from being written to
358          * while its mode is being reconfigured
359          */
360         OSLockAcquire (psTmp->hStreamLock);
361         if ( NOTHING_PENDING != psTmp->ui32Pending )
362         {
363                 OSLockRelease (psTmp->hStreamLock);
364                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_NOT_READY);
365         }
366         psTmp->ui32Pending = 0;
367         OSLockRelease (psTmp->hStreamLock);
368
369         if ( ui32StreamFlags & TL_FLAG_RESERVE_DROP_NEWER )
370         {
371                 if ( ui32StreamFlags & TL_FLAG_RESERVE_BLOCK )
372                 {
373                         eError = PVRSRV_ERROR_INVALID_PARAMS;
374                         goto e1;
375                 }
376                 psTmp->bDrop = IMG_TRUE;
377                 psTmp->bBlock = IMG_FALSE;
378         }
379         else if ( ui32StreamFlags & TL_FLAG_RESERVE_BLOCK )
380         {
381                 psTmp->bBlock = IMG_TRUE;
382                 psTmp->bDrop = IMG_FALSE;
383     }
384
385 e1:
386         OSLockAcquire (psTmp->hStreamLock);
387         psTmp->ui32Pending = NOTHING_PENDING;
388         OSLockRelease (psTmp->hStreamLock);
389
390         PVR_DPF_RETURN_RC(eError);
391 }
392
393 PVRSRV_ERROR
394 TLStreamOpen(IMG_HANDLE *phStream,
395              IMG_CHAR   *szStreamName)
396 {
397         PTL_SNODE  psTmpSNode;
398
399         PVR_DPF_ENTERED;
400
401         if ( NULL == phStream || NULL == szStreamName )
402         {
403                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
404         }
405
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);
410         
411         /* Search for a stream node with a matching stream name */
412         psTmpSNode = TLFindStreamNodeByName(szStreamName);
413
414         if ( NULL == psTmpSNode )
415         {
416                 OSLockRelease (TLGGD()->hTLGDLock);
417                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_NOT_FOUND);
418         }
419
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++;
425         
426         OSLockRelease (TLGGD()->hTLGDLock);
427
428         /* Return the stream handle to the caller */
429         *phStream = (IMG_HANDLE)psTmpSNode->psStream;
430
431         PVR_DPF_RETURN_VAL(PVRSRV_OK);
432 }
433
434 void
435 TLStreamClose(IMG_HANDLE hStream)
436 {
437         PTL_STREAM      psTmp;
438         IMG_BOOL        bDestroyStream;
439
440         PVR_DPF_ENTERED;
441
442         if ( NULL == hStream )
443         {
444                 PVR_DPF((PVR_DBG_WARNING,
445                                  "TLStreamClose failed as NULL stream handler passed, nothing done."));
446                 PVR_DPF_RETURN;
447         }
448
449         psTmp = (PTL_STREAM)hStream;
450
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);
454         
455         /* Decrement write reference counter of the stream */
456         psTmp->psNode->uiWRefCount--;
457
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);
461                 PVR_DPF_RETURN;
462         }
463         else
464         {
465                 /* Now we try removing this TL_STREAM from TL_GLOBAL_DATA */
466
467                 if ( psTmp->bWaitForEmptyOnDestroy == IMG_TRUE )
468                 {
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)
474                         {
475                                 /* Release lock before sleeping */
476                                 OSLockRelease (TLGGD()->hTLGDLock);
477                                 
478                                 OSEventObjectWaitTimeout(psTmp->hProducerEvent, EVENT_OBJECT_TIMEOUT_US);
479                                 
480                                 OSLockAcquire (TLGGD()->hTLGDLock);
481
482                                 /* Ensure destruction of stream is still required */
483                                 if (0 != psTmp->psNode->uiWRefCount)
484                                 {
485                                         OSLockRelease (TLGGD()->hTLGDLock);
486                                         PVR_DPF_RETURN;
487                                 }
488                         }
489                 }
490
491                 /* Try removing the stream from TL_GLOBAL_DATA */
492                 bDestroyStream = TLTryRemoveStreamAndFreeStreamNode (psTmp->psNode);
493                 
494                 OSLockRelease (TLGGD()->hTLGDLock);
495                 
496                 if (bDestroyStream)
497                 {
498                         /* Destroy the stream if it was removed from TL_GLOBAL_DATA */
499                         TLStreamDestroy (psTmp);
500                         psTmp = NULL;
501                 }
502                 PVR_DPF_RETURN;
503         }
504 }
505
506 static PVRSRV_ERROR
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)
513 {
514         PTL_STREAM psTmp;
515         IMG_UINT32 *pui32Buf, ui32LRead, ui32LWrite, ui32LPending, lReqSizeAligned, lReqSizeActual;
516         IMG_INT pad, iFreeSpace;
517
518         PVR_DPF_ENTERED;
519         if (pui32AvSpace) *pui32AvSpace = 0;
520
521         if (( NULL == hStream ))
522         {
523                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
524         }
525         psTmp = (PTL_STREAM)hStream;
526
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));
530
531         /* The buffer is only used in "rounded" (aligned) chunks */
532         lReqSizeAligned = PVRSRVTL_ALIGN(ui32ReqSize);
533
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);
538
539         /* Get a local copy of the stream buffer parameters */
540         ui32LRead  = psTmp->ui32Read ;
541         ui32LWrite = psTmp->ui32Write ;
542         ui32LPending = psTmp->ui32Pending ;
543
544         /*  Multiple pending reserves are not supported. */
545         if ( NOTHING_PENDING != ui32LPending )
546         {
547                 OSLockRelease (psTmp->hStreamLock);
548                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_NOT_READY);
549         }
550
551         if ( PVRSRVTL_MAX_PACKET_SIZE < lReqSizeAligned )
552         {
553                 psTmp->ui32Pending = NOTHING_PENDING;
554                 if (pui32AvSpace)
555                 {
556                         *pui32AvSpace = suggestAllocSize(ui32LRead, ui32LWrite, psTmp->ui32Size, ui32ReqSizeMin);
557                 }
558                 OSLockRelease (psTmp->hStreamLock);
559                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_RESERVE_TOO_BIG);
560         }
561
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;
567
568         OSLockRelease (psTmp->hStreamLock);
569
570         /* If there is enough contiguous space following the current Write
571          * position then no padding is required */
572         if (  psTmp->ui32Size
573                 < ui32LWrite + lReqSizeAligned + sizeof(PVRSRVTL_PACKETHDR) )
574         {
575                 pad = psTmp->ui32Size - ui32LWrite;
576         }
577         else
578         {
579                 pad = 0 ;
580         }
581
582         lReqSizeActual = lReqSizeAligned + sizeof(PVRSRVTL_PACKETHDR) + pad ;
583         /* If this is a blocking reserve and there is not enough space then wait. */
584         if( psTmp->bBlock )
585         {
586                 if( psTmp->ui32Size < lReqSizeActual )
587                 {
588                         /* Acquire stream lock for updating pending value */
589                         OSLockAcquire (psTmp->hStreamLock);
590                         psTmp->ui32Pending = NOTHING_PENDING;
591                         OSLockRelease (psTmp->hStreamLock);
592                         
593                         PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_MISUSE);
594                 }
595                 while ( ( cbSpaceLeft(ui32LRead, ui32LWrite, psTmp->ui32Size)
596                          <(IMG_INT) lReqSizeActual ) )
597                 {
598                         /* The TL should never drop the Bridge Lock as this can lead to
599                          * deadlocks.  See comment for TLStreamReconfigure.
600                          */
601                         OSEventObjectWaitAndHoldBridgeLock(psTmp->hProducerEvent);
602                         // update local copies.
603                         ui32LRead  = psTmp->ui32Read ;
604                         ui32LWrite = psTmp->ui32Write ;
605                 }
606         }
607
608         iFreeSpace = cbSpaceLeft(ui32LRead, ui32LWrite, psTmp->ui32Size);
609         
610         /* The easy case: buffer has enough space to hold the requested packet (data + header) */
611         if (  iFreeSpace >=(IMG_INT) lReqSizeActual )
612         {
613                 if ( pad ) 
614                 { 
615                         /* Inserting padding packet. */
616                         pui32Buf = (IMG_UINT32*)&psTmp->pbyBuffer[ui32LWrite];
617                         *pui32Buf = PVRSRVTL_SET_PACKET_PADDING(pad-sizeof(PVRSRVTL_PACKETHDR)) ;
618
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);
624                 }
625                 /* Insert size-stamped packet header */
626                 pui32Buf = (IMG_UINT32*) &psTmp->pbyBuffer[ui32LWrite];
627
628                 *pui32Buf = PVRSRVTL_SET_PACKET_HDR(ui32ReqSize, ePacketType);
629
630                 /* return the next position in the buffer to the user */
631                 *ppui8Data =  &psTmp->pbyBuffer[ ui32LWrite+sizeof(PVRSRVTL_PACKETHDR) ] ;
632
633                 /* update pending offset: size stamp + data  */
634                 ui32LPending = lReqSizeAligned + sizeof(PVRSRVTL_PACKETHDR) ;
635         }
636         /* The not so easy case: not enough space, decide how to handle data */
637         else
638         {
639
640 #if defined(DEBUG)
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 )
645                 {
646                         OSLockAcquire (psTmp->hStreamLock);
647                         psTmp->ui32Pending = NOTHING_PENDING;
648                         OSLockRelease (psTmp->hStreamLock);
649                         PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_MISUSE);
650                 }
651 #endif
652
653                 /* No data overwriting, insert write_failed flag and return */
654                 if (psTmp->bDrop) 
655                 {
656                         /* Caller should not try to use ppui8Data,
657                          * NULLify to give user a chance of avoiding memory corruption */
658                         ppui8Data = NULL;
659
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 
663                                           ? 
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];
667
668                         if ( PVRSRVTL_PACKETTYPE_MOST_RECENT_WRITE_FAILED
669                                  != 
670                                  GET_PACKET_TYPE( (PVRSRVTL_PACKETHDR*)pui32Buf ) )
671                         {
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);
678                         }
679
680                         OSLockAcquire (psTmp->hStreamLock);
681                         psTmp->ui32Write = ui32LWrite;
682                         psTmp->ui32Pending = NOTHING_PENDING;
683                         OSLockRelease (psTmp->hStreamLock);
684                         
685                         if (pui32AvSpace)
686                         {
687                                 *pui32AvSpace = suggestAllocSize(ui32LRead, ui32LWrite, psTmp->ui32Size, ui32ReqSizeMin);
688                         }
689                         PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_RESERVE_TOO_BIG);
690                 } 
691         }
692
693         /* Acquire stream lock for updating stream parameters */
694         OSLockAcquire (psTmp->hStreamLock);
695         psTmp->ui32Write = ui32LWrite ;
696         psTmp->ui32Pending = ui32LPending ;
697         OSLockRelease (psTmp->hStreamLock);
698
699         PVR_DPF_RETURN_OK;
700 }
701
702 PVRSRV_ERROR
703 TLStreamReserve(IMG_HANDLE hStream,
704                                 IMG_UINT8 **ppui8Data,
705                                 IMG_UINT32 ui32Size)
706 {
707         return DoTLStreamReserve(hStream, ppui8Data, ui32Size, ui32Size, PVRSRVTL_PACKETTYPE_DATA, NULL);
708 }
709
710 PVRSRV_ERROR
711 TLStreamReserve2(IMG_HANDLE hStream,
712                 IMG_UINT8  **ppui8Data,
713                 IMG_UINT32 ui32Size,
714                 IMG_UINT32 ui32SizeMin,
715                 IMG_UINT32* pui32Available)
716 {
717         return DoTLStreamReserve(hStream, ppui8Data, ui32Size, ui32SizeMin, PVRSRVTL_PACKETTYPE_DATA, pui32Available);
718 }
719
720 PVRSRV_ERROR
721 TLStreamCommit(IMG_HANDLE hStream, IMG_UINT32 ui32ReqSize)
722 {
723         PTL_STREAM psTmp;
724         IMG_UINT32 ui32LRead, ui32OldWrite, ui32LWrite, ui32LPending;
725         PVRSRV_ERROR eError;
726
727         PVR_DPF_ENTERED;
728
729         if ( NULL == hStream )
730         {
731                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
732         }
733         psTmp = (PTL_STREAM)hStream;
734
735         /* Get a local copy of the stream buffer parameters */
736         ui32LRead = psTmp->ui32Read ;
737         ui32LWrite = psTmp->ui32Write ;
738         ui32LPending = psTmp->ui32Pending ;
739
740         ui32OldWrite = ui32LWrite;
741
742         // Space in buffer is aligned
743         ui32ReqSize = PVRSRVTL_ALIGN(ui32ReqSize) + sizeof(PVRSRVTL_PACKETHDR);
744
745         /* Check pending reserver and ReqSize + packet header size. */
746         if ((ui32LPending == NOTHING_PENDING) || (ui32ReqSize > ui32LPending))
747         {
748                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_MISUSE);
749         }
750
751         /* Update pointer to written data. */
752         ui32LWrite = (ui32LWrite + ui32ReqSize) % psTmp->ui32Size;
753
754         /* and reset LPending to 0 since data are now submitted  */
755         ui32LPending = NOTHING_PENDING;
756
757         /* Calculate high water mark for debug purposes */
758 #if defined(TL_BUFFER_UTILIZATION)
759         {
760                 IMG_UINT32 tmp = 0;
761                 if (ui32LWrite > ui32LRead)
762                 {
763                         tmp = (ui32LWrite-ui32LRead);
764                 }
765                 else if (ui32LWrite < ui32LRead)
766                 {
767                         tmp = (psTmp->ui32Size-ui32LRead+ui32LWrite);
768                 } /* else equal, ignore */
769
770                 if (tmp > psTmp->ui32BufferUt)
771                 {
772                         psTmp->ui32BufferUt = tmp;
773                 }
774         }
775 #endif
776
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);
781
782         /* Update stream buffer parameters to match local copies */
783         psTmp->ui32Write = ui32LWrite ;
784         psTmp->ui32Pending = ui32LPending ;
785
786         OSLockRelease (psTmp->hStreamLock);
787
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)
791         {
792                 /* Signal consumers that may be waiting */
793                 eError = OSEventObjectSignal(psTmp->psNode->hReadEventObj);
794                 if ( eError != PVRSRV_OK)
795                 {
796                         PVR_DPF_RETURN_RC(eError);
797                 }
798         }
799         
800         PVR_DPF_RETURN_OK;
801 }
802
803 PVRSRV_ERROR
804 TLStreamWrite(IMG_HANDLE hStream, IMG_UINT8 *pui8Src, IMG_UINT32 ui32Size)
805 {
806         IMG_BYTE *pbyDest = NULL;
807         PVRSRV_ERROR eError;
808
809         PVR_DPF_ENTERED;
810
811         if ( NULL == hStream )
812         {
813                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
814         }
815
816         eError = TLStreamReserve(hStream, &pbyDest, ui32Size);
817         if ( PVRSRV_OK != eError ) 
818         {       
819                 PVR_DPF_RETURN_RC(eError);
820         }
821         else if ( pbyDest )
822         {
823                 OSDeviceMemCopy((void*)pbyDest, (void*)pui8Src, ui32Size);
824                 eError = TLStreamCommit(hStream, ui32Size);
825                 if ( PVRSRV_OK != eError ) 
826                 {       
827                         PVR_DPF_RETURN_RC(eError);
828                 }
829         }
830         else
831         {
832                 /* A NULL ptr returned from TLStreamReserve indicates the TL buffer is full */
833                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_STREAM_RESERVE_TOO_BIG);
834         }
835         PVR_DPF_RETURN_OK;
836 }
837
838 void TLStreamInfo(PTL_STREAM_INFO psInfo)
839 {
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 */
842
843         actual_req_size = 2; 
844         DevmemExportalignAdjustSizeAndAlign(OSGetPageShift(), &actual_req_size, &align);
845
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);
850 }
851
852 PVRSRV_ERROR
853 TLStreamMarkEOS(IMG_HANDLE psStream)
854 {
855         PVRSRV_ERROR eError;
856         IMG_UINT8* pData;
857
858         PVR_DPF_ENTERED;
859
860         if ( NULL == psStream )
861         {
862                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
863         }
864
865         eError = DoTLStreamReserve(psStream, &pData, 0, 0, PVRSRVTL_PACKETTYPE_MARKER_EOS, NULL);
866         if ( PVRSRV_OK !=  eError )
867         {
868                 PVR_DPF_RETURN_RC(eError);
869         }
870
871         PVR_DPF_RETURN_RC(TLStreamCommit(psStream, 0));
872 }
873
874 PVRSRV_ERROR
875 TLStreamSync(IMG_HANDLE psStream)
876 {
877         PVRSRV_ERROR eError = PVRSRV_OK;
878         PTL_STREAM   psTmp;
879
880         PVR_DPF_ENTERED;
881
882         if ( NULL == psStream )
883         {
884                 PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
885         }
886         psTmp = (PTL_STREAM)psStream;
887         
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)
893         {
894                 eError = OSEventObjectSignal(psTmp->psNode->hReadEventObj);
895         }
896
897         PVR_DPF_RETURN_RC(eError);
898 }
899
900 /*
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.
904  */
905 IMG_UINT32
906 TLStreamAcquireReadPos(PTL_STREAM psStream, IMG_UINT32* puiReadOffset)
907 {
908         IMG_UINT32 uiReadLen = 0;
909         IMG_UINT32 ui32LRead, ui32LWrite;
910
911         PVR_DPF_ENTERED;
912
913         PVR_ASSERT(psStream);
914         PVR_ASSERT(puiReadOffset);
915
916         /* Grab a local copy */
917         ui32LRead = psStream->ui32Read;
918         ui32LWrite = psStream->ui32Write;
919
920         /* No data available and CB defined - try and get data */
921         if ((ui32LRead == ui32LWrite) && psStream->pfProducerCallback)
922         {
923                 PVRSRV_ERROR eRc;
924                 IMG_UINT32   ui32Resp = 0;
925
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");
929
930                 ui32LWrite = psStream->ui32Write;
931         }
932
933         /* No data available... */
934         if (ui32LRead == ui32LWrite)
935         {
936                 PVR_DPF_RETURN_VAL(0);
937         }
938
939         /* Data is available to read... */
940         *puiReadOffset = ui32LRead;
941
942         /*PVR_DPF((PVR_DBG_VERBOSE,
943          *              "TLStreamAcquireReadPos Start before: Write:%d, Read:%d, size:%d",
944          *              ui32LWrite, ui32LRead, psStream->ui32Size));
945          */
946
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;
953         }
954         else
955         {       // CB has not wrapped
956                 uiReadLen = ui32LWrite - ui32LRead;
957         }
958
959         PVR_DPF_RETURN_VAL(uiReadLen);
960 }
961
962 void
963 TLStreamAdvanceReadPos(PTL_STREAM psStream, IMG_UINT32 uiReadLen)
964 {
965         PVR_DPF_ENTERED;
966
967         PVR_ASSERT(psStream);
968
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;
972
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.
980          */
981         {
982                 PVRSRV_ERROR eError;
983                 eError = OSEventObjectSignal(psStream->hProducerEventObj);
984                 if ( eError != PVRSRV_OK)
985                 {
986                         PVR_DPF((PVR_DBG_WARNING,
987                                          "Error in TLStreamAdvanceReadPos: OSEventObjectSignal returned:%u",
988                                          eError));
989                 }
990         }
991
992         PVR_DPF((PVR_DBG_VERBOSE,
993                          "TLStreamAdvanceReadPos Read now at: %d",
994                         psStream->ui32Read));
995         PVR_DPF_RETURN;
996 }
997
998 void
999 TLStreamDestroy (PTL_STREAM psStream)
1000 {
1001         PVR_ASSERT (psStream);
1002         
1003         OSLockDestroy (psStream->hStreamLock);
1004
1005         OSEventObjectClose(psStream->hProducerEvent);
1006         OSEventObjectDestroy(psStream->hProducerEventObj);
1007
1008         TLFreeSharedMem(psStream);
1009         OSFreeMem(psStream);
1010 }
1011
1012 DEVMEM_MEMDESC*
1013 TLStreamGetBufferPointer(PTL_STREAM psStream)
1014 {
1015         PVR_DPF_ENTERED;
1016
1017         PVR_ASSERT(psStream);
1018
1019         PVR_DPF_RETURN_VAL(psStream->psStreamMemDesc);
1020 }
1021
1022 IMG_BOOL
1023 TLStreamEOS(PTL_STREAM psStream)
1024 {
1025         PVR_DPF_ENTERED;
1026
1027         PVR_ASSERT(psStream);
1028
1029         /* If both pointers are equal then the buffer is empty */
1030         PVR_DPF_RETURN_VAL( psStream->ui32Read == psStream->ui32Write );
1031 }
1032