RK3368 GPU: Rogue N Init.
[firefly-linux-kernel-4.4.55.git] / drivers / staging / imgtec / rogue / handle.c
1 /*************************************************************************/ /*!
2 @File
3 @Title          Resource Handle Manager
4 @Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @Description    Provide resource handle management
6 @License        Dual MIT/GPLv2
7
8 The contents of this file are subject to the MIT license as set out below.
9
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:
16
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
19
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.
23
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.
31
32 This License is also included in this distribution in the file called
33 "MIT-COPYING".
34
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 */ /***************************************************************************/
43
44 /* See handle.h for a description of the handle API. */
45
46 /*
47  * The implmentation supports movable handle structures, allowing the address
48  * of a handle structure to change without having to fix up pointers in
49  * any of the handle structures.  For example, the linked list mechanism
50  * used to link subhandles together uses handle array indices rather than
51  * pointers to the structures themselves.
52  */
53
54 #include <stddef.h>
55
56 #include "handle.h"
57 #include "handle_impl.h"
58 #include "allocmem.h"
59 #include "pvr_debug.h"
60 #include "connection_server.h"
61
62 #define HANDLE_HASH_TAB_INIT_SIZE               32
63
64 #define SET_FLAG(v, f)                          ((void)((v) |= (f)))
65 #define CLEAR_FLAG(v, f)                        ((void)((v) &= (IMG_UINT)~(f)))
66 #define TEST_FLAG(v, f)                         ((IMG_BOOL)(((v) & (f)) != 0))
67
68 #define TEST_ALLOC_FLAG(psHandleData, f)        TEST_FLAG((psHandleData)->eFlag, f)
69
70 #if !defined(ARRAY_SIZE)
71 #define ARRAY_SIZE(a)                           (sizeof(a) / sizeof((a)[0]))
72 #endif
73
74
75 /* Linked list structure. Used for both the list head and list items */
76 typedef struct _HANDLE_LIST_
77 {
78         IMG_HANDLE hPrev;
79         IMG_HANDLE hNext;
80         IMG_HANDLE hParent;
81 } HANDLE_LIST;
82
83 typedef struct _HANDLE_DATA_
84 {
85         /* The handle that represents this structure */
86         IMG_HANDLE hHandle;
87
88         /* Handle type */
89         PVRSRV_HANDLE_TYPE eType;
90
91         /* Flags specified when the handle was allocated */
92         PVRSRV_HANDLE_ALLOC_FLAG eFlag;
93
94         /* Pointer to the data that the handle represents */
95         void *pvData;
96
97         /*
98          * Callback specified at handle allocation time to
99          * release/destroy/free the data represented by the
100          * handle when it's reference count reaches 0. This
101          * should always be NULL for subhandles.
102          */
103         PFN_HANDLE_RELEASE pfnReleaseData;
104
105         /* List head for subhandles of this handle */
106         HANDLE_LIST sChildren;
107
108         /* List entry for sibling subhandles */
109         HANDLE_LIST sSiblings;
110
111         /* Reference count. The pfnReleaseData callback gets called when the
112          * reference count hits zero
113          */
114         IMG_UINT32 ui32RefCount;
115 } HANDLE_DATA;
116
117 struct _HANDLE_BASE_
118 {
119         /* Pointer to a handle implementations base structure */
120         HANDLE_IMPL_BASE *psImplBase;
121
122         /*
123          * Pointer to handle hash table.
124          * The hash table is used to do reverse lookups, converting data
125          * pointers to handles.
126          */
127         HASH_TABLE *psHashTab;
128
129         /* Can be connection, process, global */
130         PVRSRV_HANDLE_BASE_TYPE eType;
131 };
132
133 /*
134  * The key for the handle hash table is an array of three elements, the
135  * pointer to the resource, the resource type and the parent handle (or 
136  * NULL if there is no parent). The eHandKey enumeration gives the
137  * array indices of the elements making up the key.
138  */
139 enum eHandKey
140 {
141         HAND_KEY_DATA = 0,
142         HAND_KEY_TYPE,
143         HAND_KEY_PARENT,
144         HAND_KEY_LEN            /* Must be last item in list */
145 };
146
147 /* HAND_KEY is the type of the hash table key */
148 typedef uintptr_t HAND_KEY[HAND_KEY_LEN];
149
150 /* Stores a pointer to the function table of the handle back-end in use */
151 static HANDLE_IMPL_FUNCTAB const *gpsHandleFuncs = NULL;
152
153 /* 
154  * Global lock added to avoid to call the handling functions
155  * only in a single threaded context.
156  */
157 static POS_LOCK gHandleLock;
158 static IMG_BOOL gbLockInitialised = IMG_FALSE;
159
160 void LockHandle(void)
161 {
162         OSLockAcquire(gHandleLock);
163 }
164
165 void UnlockHandle(void)
166 {
167         OSLockRelease(gHandleLock);
168 }
169
170 /*
171  * Kernel handle base structure. This is used for handles that are not 
172  * allocated on behalf of a particular process.
173  */
174 PVRSRV_HANDLE_BASE *gpsKernelHandleBase = NULL;
175
176 /* Increase the reference count on the given handle.
177  * The handle lock must already be acquired.
178  * Returns: the reference count after the increment
179  */
180 static inline IMG_UINT32 _HandleRef(HANDLE_DATA *psHandleData)
181 {
182 #if defined PVRSRV_DEBUG_HANDLE_LOCK
183         if(!OSLockIsLocked(gHandleLock))
184         {
185                 PVR_DPF((PVR_DBG_ERROR, "%s: Handle lock is not locked", __func__));
186                 OSDumpStack();
187         }
188 #endif
189         psHandleData->ui32RefCount++;
190         return psHandleData->ui32RefCount;
191 }
192
193 /* Decrease the reference count on the given handle.
194  * The handle lock must already be acquired.
195  * Returns: the reference count after the decrement
196  */
197 static inline IMG_UINT32 _HandleUnref(HANDLE_DATA *psHandleData)
198 {
199 #if defined PVRSRV_DEBUG_HANDLE_LOCK
200         if(!OSLockIsLocked(gHandleLock))
201         {
202                 PVR_DPF((PVR_DBG_ERROR, "%s: Handle lock is not locked", __func__));
203                 OSDumpStack();
204         }
205 #endif
206         PVR_ASSERT(psHandleData->ui32RefCount > 0);
207         psHandleData->ui32RefCount--;
208
209         return psHandleData->ui32RefCount;
210 }
211
212 /*!
213 ******************************************************************************
214
215  @Function      GetHandleData
216
217  @Description   Get the handle data structure for a given handle
218
219  @Input         psBase - pointer to handle base structure
220                 ppsHandleData - location to return pointer to handle data structure
221                 hHandle - handle from client
222                 eType - handle type or PVRSRV_HANDLE_TYPE_NONE if the
223                         handle type is not to be checked.
224
225  @Output        ppsHandleData - points to a pointer to the handle data structure
226
227  @Return        Error code or PVRSRV_OK
228
229 ******************************************************************************/
230 #ifdef INLINE_IS_PRAGMA
231 #pragma inline(GetHandleData)
232 #endif
233 static INLINE
234 PVRSRV_ERROR GetHandleData(PVRSRV_HANDLE_BASE *psBase,
235                            HANDLE_DATA **ppsHandleData,
236                            IMG_HANDLE hHandle,
237                            PVRSRV_HANDLE_TYPE eType)
238 {
239         HANDLE_DATA *psHandleData;
240         PVRSRV_ERROR eError;
241
242         eError = gpsHandleFuncs->pfnGetHandleData(psBase->psImplBase, 
243                                                   hHandle, 
244                                                   (void **)&psHandleData);
245         if (eError != PVRSRV_OK)
246         {
247                 return eError;
248         }
249
250         /*
251          * Unless PVRSRV_HANDLE_TYPE_NONE was passed in to this function,
252          * check handle is of the correct type.
253          */
254         if (eType != PVRSRV_HANDLE_TYPE_NONE && eType != psHandleData->eType)
255         {
256                 PVR_DPF((PVR_DBG_ERROR,
257                          "GetHandleData: Handle type mismatch (%d != %d)",
258                          eType, psHandleData->eType));
259                 return PVRSRV_ERROR_HANDLE_TYPE_MISMATCH;
260         }
261
262         /* Return the handle structure */
263         *ppsHandleData = psHandleData;
264
265         return PVRSRV_OK;
266 }
267
268 /*!
269 ******************************************************************************
270
271  @Function      HandleListInit
272
273  @Description   Initialise a linked list structure embedded in a handle
274                 structure.
275
276  @Input         hHandle - handle containing the linked list structure
277                 psList - pointer to linked list structure
278                 hParent - parent handle or NULL
279
280 ******************************************************************************/
281 #ifdef INLINE_IS_PRAGMA
282 #pragma inline(HandleListInit)
283 #endif
284 static INLINE
285 void HandleListInit(IMG_HANDLE hHandle, HANDLE_LIST *psList, IMG_HANDLE hParent)
286 {
287         psList->hPrev = hHandle;
288         psList->hNext = hHandle;
289         psList->hParent = hParent;
290 }
291
292 /*!
293 ******************************************************************************
294
295  @Function      InitParentList
296
297  @Description   Initialise the children list head in a handle structure.
298                 The children are the subhandles of this handle.
299
300  @Input         psHandleData - pointer to handle data structure
301
302 ******************************************************************************/
303 #ifdef INLINE_IS_PRAGMA
304 #pragma inline(InitParentList)
305 #endif
306 static INLINE
307 void InitParentList(HANDLE_DATA *psHandleData)
308 {
309         IMG_HANDLE hParent = psHandleData->hHandle;
310
311         HandleListInit(hParent, &psHandleData->sChildren, hParent);
312 }
313
314 /*!
315 ******************************************************************************
316
317  @Function      InitChildEntry
318
319  @Description   Initialise the child list entry in a handle structure.
320                 The list entry is used to link together subhandles of
321                 a given handle.
322
323  @Input         psHandleData - pointer to handle data structure
324
325 ******************************************************************************/
326 #ifdef INLINE_IS_PRAGMA
327 #pragma inline(InitChildEntry)
328 #endif
329 static INLINE
330 void InitChildEntry(HANDLE_DATA *psHandleData)
331 {
332         HandleListInit(psHandleData->hHandle, &psHandleData->sSiblings, NULL);
333 }
334
335 /*!
336 ******************************************************************************
337
338  @Function      HandleListIsEmpty
339
340  @Description   Determine whether a given linked list is empty.
341
342  @Input         hHandle - handle containing the list head
343                 psList - pointer to the list head
344
345  @Return        IMG_TRUE if the list is empty, IMG_FALSE if it isn't.
346
347 ******************************************************************************/
348 #ifdef INLINE_IS_PRAGMA
349 #pragma inline(HandleListIsEmpty)
350 #endif
351 static INLINE
352 IMG_BOOL HandleListIsEmpty(IMG_HANDLE hHandle, HANDLE_LIST *psList) /* Instead of passing in the handle can we not just do (psList->hPrev == psList->hNext) ? IMG_TRUE : IMG_FALSE ??? */
353 {
354         IMG_BOOL bIsEmpty;
355
356         bIsEmpty = (IMG_BOOL)(psList->hNext == hHandle);
357
358 #ifdef  DEBUG
359         {
360                 IMG_BOOL bIsEmpty2;
361
362                 bIsEmpty2 = (IMG_BOOL)(psList->hPrev == hHandle);
363                 PVR_ASSERT(bIsEmpty == bIsEmpty2);
364         }
365 #endif
366
367         return bIsEmpty;
368 }
369
370 #ifdef DEBUG
371 /*!
372 ******************************************************************************
373
374  @Function      NoChildren
375
376  @Description   Determine whether a handle has any subhandles
377
378  @Input         psHandleData - pointer to handle data structure
379
380  @Return        IMG_TRUE if the handle has no subhandles, IMG_FALSE if it does.
381
382 ******************************************************************************/
383 #ifdef INLINE_IS_PRAGMA
384 #pragma inline(NoChildren)
385 #endif
386 static INLINE
387 IMG_BOOL NoChildren(HANDLE_DATA *psHandleData)
388 {
389         PVR_ASSERT(psHandleData->sChildren.hParent == psHandleData->hHandle);
390
391         return HandleListIsEmpty(psHandleData->hHandle, &psHandleData->sChildren);
392 }
393
394 /*!
395 ******************************************************************************
396
397  @Function      NoParent
398
399  @Description   Determine whether a handle is a subhandle
400
401  @Input         psHandleData - pointer to handle data structure
402
403  @Return        IMG_TRUE if the handle is not a subhandle, IMG_FALSE if it is.
404
405 ******************************************************************************/
406 #ifdef INLINE_IS_PRAGMA
407 #pragma inline(NoParent)
408 #endif
409 static INLINE
410 IMG_BOOL NoParent(HANDLE_DATA *psHandleData)
411 {
412         if (HandleListIsEmpty(psHandleData->hHandle, &psHandleData->sSiblings))
413         {
414                 PVR_ASSERT(psHandleData->sSiblings.hParent == NULL);
415
416                 return IMG_TRUE;
417         }
418         else
419         {
420                 PVR_ASSERT(psHandleData->sSiblings.hParent != NULL);
421         }
422         return IMG_FALSE;
423 }
424 #endif /*DEBUG*/
425
426 /*!
427 ******************************************************************************
428
429  @Function      ParentHandle
430
431  @Description   Determine the parent of a handle
432
433  @Input         psHandleData - pointer to handle data structure
434
435  @Return        Parent handle, or NULL if the handle is not a subhandle.
436
437 ******************************************************************************/
438 #ifdef INLINE_IS_PRAGMA
439 #pragma inline(ParentHandle)
440 #endif
441 static INLINE
442 IMG_HANDLE ParentHandle(HANDLE_DATA *psHandleData)
443 {
444         return psHandleData->sSiblings.hParent;
445 }
446
447 /*
448  * GetHandleListFromHandleAndOffset is used to generate either a
449  * pointer to the subhandle list head, or a pointer to the linked list
450  * structure of an item on a subhandle list.
451  * The list head is itself on the list, but is at a different offset
452  * in the handle structure to the linked list structure for items on
453  * the list.  The two linked list structures are differentiated by
454  * the third parameter, containing the parent handle.  The parent field
455  * in the list head structure references the handle structure that contains
456  * it.  For items on the list, the parent field in the linked list structure
457  * references the parent handle, which will be different from the handle
458  * containing the linked list structure.
459  */
460 #ifdef INLINE_IS_PRAGMA
461 #pragma inline(GetHandleListFromHandleAndOffset)
462 #endif
463 static INLINE
464 HANDLE_LIST *GetHandleListFromHandleAndOffset(PVRSRV_HANDLE_BASE *psBase, 
465                                               IMG_HANDLE hEntry, 
466                                               IMG_HANDLE hParent, 
467                                               size_t uiParentOffset,
468                                               size_t uiEntryOffset)
469 {
470         HANDLE_DATA *psHandleData = NULL;
471         PVRSRV_ERROR eError;
472
473         PVR_ASSERT(psBase != NULL);
474
475         eError = GetHandleData(psBase, 
476                                &psHandleData, 
477                                hEntry, 
478                                PVRSRV_HANDLE_TYPE_NONE);
479         if (eError != PVRSRV_OK)
480         {
481                 return NULL;
482         }
483
484         if (hEntry == hParent)
485         {
486                 return (HANDLE_LIST *)((IMG_CHAR *)psHandleData + uiParentOffset);
487         }
488         else
489         {
490                 return (HANDLE_LIST *)((IMG_CHAR *)psHandleData + uiEntryOffset);
491         }
492 }
493
494 /*!
495 ******************************************************************************
496
497  @Function      HandleListInsertBefore
498
499  @Description   Insert a handle before a handle currently on the list.
500
501  @Input         hEntry - handle to be inserted after
502                 psEntry - pointer to handle structure to be inserted after
503                 uiParentOffset - offset to list head struct in handle structure
504                 hNewEntry - handle to be inserted
505                 psNewEntry - pointer to handle structure of item to be inserted
506                 uiEntryOffset - offset of list item struct in handle structure
507                 hParent - parent handle of hNewEntry
508
509  @Return        Error code or PVRSRV_OK
510
511 ******************************************************************************/
512 #ifdef INLINE_IS_PRAGMA
513 #pragma inline(HandleListInsertBefore)
514 #endif
515 static INLINE
516 PVRSRV_ERROR HandleListInsertBefore(PVRSRV_HANDLE_BASE *psBase,
517                                     IMG_HANDLE hEntry,
518                                     HANDLE_LIST *psEntry,
519                                     size_t uiParentOffset,
520                                     IMG_HANDLE hNewEntry,
521                                     HANDLE_LIST *psNewEntry,
522                                     size_t uiEntryOffset,
523                                     IMG_HANDLE hParent)
524 {
525         HANDLE_LIST *psPrevEntry;
526
527         if (psBase == NULL || psEntry == NULL || psNewEntry == NULL)
528         {
529                 return PVRSRV_ERROR_INVALID_PARAMS;
530         }
531
532         psPrevEntry = GetHandleListFromHandleAndOffset(psBase, 
533                                                        psEntry->hPrev, 
534                                                        hParent, 
535                                                        uiParentOffset, 
536                                                        uiEntryOffset);
537         if (psPrevEntry == NULL)
538         {
539                 return PVRSRV_ERROR_HANDLE_INDEX_OUT_OF_RANGE;
540         }
541
542         PVR_ASSERT(psNewEntry->hParent == NULL);
543         PVR_ASSERT(hEntry == psPrevEntry->hNext);
544
545 #if defined(DEBUG)
546         {
547                 HANDLE_LIST *psParentList;
548
549                 psParentList = GetHandleListFromHandleAndOffset(psBase, 
550                                                                 hParent, 
551                                                                 hParent, 
552                                                                 uiParentOffset, 
553                                                                 uiParentOffset);
554                 PVR_ASSERT(psParentList && psParentList->hParent == hParent);
555         }
556 #endif /* defined(DEBUG) */
557
558         psNewEntry->hPrev = psEntry->hPrev;
559         psEntry->hPrev = hNewEntry;
560
561         psNewEntry->hNext = hEntry;
562         psPrevEntry->hNext = hNewEntry;
563
564         psNewEntry->hParent = hParent;
565
566         return PVRSRV_OK;
567 }
568
569 /*!
570 ******************************************************************************
571
572  @Function      AdoptChild
573
574  @Description   Assign a subhandle to a handle
575
576  @Input         psParentData - pointer to handle structure of parent handle
577                 psChildData - pointer to handle structure of child subhandle
578
579  @Return        Error code or PVRSRV_OK
580
581 ******************************************************************************/
582 #ifdef INLINE_IS_PRAGMA
583 #pragma inline(AdoptChild)
584 #endif
585 static INLINE
586 PVRSRV_ERROR AdoptChild(PVRSRV_HANDLE_BASE *psBase,
587                         HANDLE_DATA *psParentData,
588                         HANDLE_DATA *psChildData)
589 {
590         IMG_HANDLE hParent = psParentData->sChildren.hParent;
591
592         PVR_ASSERT(hParent == psParentData->hHandle);
593
594         return HandleListInsertBefore(psBase, 
595                                       hParent, 
596                                       &psParentData->sChildren, 
597                                       offsetof(HANDLE_DATA, sChildren), 
598                                       psChildData->hHandle, 
599                                       &psChildData->sSiblings, 
600                                       offsetof(HANDLE_DATA, sSiblings), 
601                                       hParent);
602 }
603
604 /*!
605 ******************************************************************************
606
607  @Function      HandleListRemove
608
609  @Description   Remove a handle from a list
610
611  @Input         hEntry - handle to be removed
612                 psEntry - pointer to handle structure of item to be removed
613                 uiEntryOffset - offset of list item struct in handle structure
614                 uiParentOffset - offset to list head struct in handle structure
615
616  @Return        Error code or PVRSRV_OK
617
618 ******************************************************************************/
619 #ifdef INLINE_IS_PRAGMA
620 #pragma inline(HandleListRemove)
621 #endif
622 static INLINE
623 PVRSRV_ERROR HandleListRemove(PVRSRV_HANDLE_BASE *psBase,
624                               IMG_HANDLE hEntry,
625                               HANDLE_LIST *psEntry,
626                               size_t uiEntryOffset,
627                               size_t uiParentOffset)
628 {
629         if (psBase == NULL || psEntry == NULL)
630         {
631                 return PVRSRV_ERROR_INVALID_PARAMS;
632         }
633
634         if (!HandleListIsEmpty(hEntry, psEntry))
635         {
636                 HANDLE_LIST *psPrev;
637                 HANDLE_LIST *psNext;
638
639                 psPrev = GetHandleListFromHandleAndOffset(psBase, 
640                                                           psEntry->hPrev, 
641                                                           psEntry->hParent, 
642                                                           uiParentOffset, 
643                                                           uiEntryOffset);
644                 if (psPrev == NULL)
645                 {
646                         return PVRSRV_ERROR_HANDLE_INDEX_OUT_OF_RANGE;
647                 }
648
649                 psNext = GetHandleListFromHandleAndOffset(psBase, 
650                                                           psEntry->hNext, 
651                                                           psEntry->hParent, 
652                                                           uiParentOffset, 
653                                                           uiEntryOffset);
654                 if (psNext == NULL)
655                 {
656                         return PVRSRV_ERROR_HANDLE_INDEX_OUT_OF_RANGE;
657                 }
658
659                 /*
660                  * The list head is on the list, and we don't want to
661                  * remove it.
662                  */
663                 PVR_ASSERT(psEntry->hParent != NULL);
664
665                 psPrev->hNext = psEntry->hNext;
666                 psNext->hPrev = psEntry->hPrev;
667
668                 HandleListInit(hEntry, psEntry, NULL);
669         }
670
671         return PVRSRV_OK;
672 }
673
674 /*!
675 ******************************************************************************
676
677  @Function      UnlinkFromParent
678
679  @Description   Remove a subhandle from its parents list
680
681  @Input         psHandleData - pointer to handle data structure of child subhandle
682
683  @Return        Error code or PVRSRV_OK
684
685 ******************************************************************************/
686 #ifdef INLINE_IS_PRAGMA
687 #pragma inline(UnlinkFromParent)
688 #endif
689 static INLINE
690 PVRSRV_ERROR UnlinkFromParent(PVRSRV_HANDLE_BASE *psBase,
691                               HANDLE_DATA *psHandleData)
692 {
693         return HandleListRemove(psBase, 
694                                 psHandleData->hHandle, 
695                                 &psHandleData->sSiblings, 
696                                 offsetof(HANDLE_DATA, sSiblings), 
697                                 offsetof(HANDLE_DATA, sChildren));
698 }
699
700 /*!
701 ******************************************************************************
702
703  @Function      HandleListIterate
704
705  @Description   Iterate over the items in a list
706
707  @Input         psHead - pointer to list head
708                 uiParentOffset - offset to list head struct in handle structure
709                 uiEntryOffset - offset of list item struct in handle structure
710                 pfnIterFunc - function to be called for each handle in the list
711
712  @Return        Error code or PVRSRV_OK
713
714 ******************************************************************************/
715 #ifdef INLINE_IS_PRAGMA
716 #pragma inline(HandleListIterate)
717 #endif
718 static INLINE
719 PVRSRV_ERROR HandleListIterate(PVRSRV_HANDLE_BASE *psBase,
720                                HANDLE_LIST *psHead,
721                                size_t uiParentOffset,
722                                size_t uiEntryOffset,
723                                PVRSRV_ERROR (*pfnIterFunc)(PVRSRV_HANDLE_BASE *, IMG_HANDLE))
724 {
725         IMG_HANDLE hHandle = psHead->hNext;
726         IMG_HANDLE hParent = psHead->hParent;
727         IMG_HANDLE hNext;
728
729         PVR_ASSERT(psHead->hParent != NULL);
730
731         /*
732          * Follow the next chain from the list head until we reach
733          * the list head again, which signifies the end of the list.
734          */
735         while (hHandle != hParent)
736         {
737                 HANDLE_LIST *psEntry;
738                 PVRSRV_ERROR eError;
739
740                 psEntry = GetHandleListFromHandleAndOffset(psBase, 
741                                                            hHandle, 
742                                                            hParent, 
743                                                            uiParentOffset, 
744                                                            uiEntryOffset);
745                 if (psEntry == NULL)
746                 {
747                         return PVRSRV_ERROR_HANDLE_INDEX_OUT_OF_RANGE;
748                 }
749
750                 PVR_ASSERT(psEntry->hParent == psHead->hParent);
751
752                 /*
753                  * Get the next index now, in case the list item is
754                  * modified by the iteration function.
755                  */
756                 hNext = psEntry->hNext;
757
758                 eError = (*pfnIterFunc)(psBase, hHandle);
759                 if (eError != PVRSRV_OK)
760                 {
761                         return eError;
762                 }
763
764                 hHandle = hNext;
765         }
766
767         return PVRSRV_OK;
768 }
769
770 /*!
771 ******************************************************************************
772
773  @Function      IterateOverChildren
774
775  @Description   Iterate over the subhandles of a parent handle
776
777  @Input         psParentData - pointer to parent handle structure
778                 pfnIterFunc - function to be called for each subhandle
779
780  @Return        Error code or PVRSRV_OK
781
782 ******************************************************************************/
783 #ifdef INLINE_IS_PRAGMA
784 #pragma inline(IterateOverChildren)
785 #endif
786 static INLINE
787 PVRSRV_ERROR IterateOverChildren(PVRSRV_HANDLE_BASE *psBase,
788                                  HANDLE_DATA *psParentData,
789                                  PVRSRV_ERROR (*pfnIterFunc)(PVRSRV_HANDLE_BASE *, IMG_HANDLE))
790 {
791          return HandleListIterate(psBase,
792                                   &psParentData->sChildren,
793                                   offsetof(HANDLE_DATA, sChildren),
794                                   offsetof(HANDLE_DATA, sSiblings),
795                                   pfnIterFunc);
796 }
797
798 /*!
799 ******************************************************************************
800
801  @Function      ParentIfPrivate
802
803  @Description   Return the parent handle if the handle was allocated
804                 with PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE, else return
805                 NULL
806
807  @Input         psHandleData - pointer to handle data structure
808
809  @Return        Parent handle, or NULL
810
811 ******************************************************************************/
812 #ifdef INLINE_IS_PRAGMA
813 #pragma inline(ParentIfPrivate)
814 #endif
815 static INLINE
816 IMG_HANDLE ParentIfPrivate(HANDLE_DATA *psHandleData)
817 {
818         return TEST_ALLOC_FLAG(psHandleData, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ?
819                         ParentHandle(psHandleData) : NULL;
820 }
821
822 /*!
823 ******************************************************************************
824
825  @Function      InitKey
826
827  @Description   Initialise a hash table key for the current process
828
829  @Input         psBase - pointer to handle base structure
830                 aKey - pointer to key
831                 pvData - pointer to the resource the handle represents
832                 eType - type of resource
833
834 ******************************************************************************/
835 #ifdef INLINE_IS_PRAGMA
836 #pragma inline(InitKey)
837 #endif
838 static INLINE
839 void InitKey(HAND_KEY aKey,
840              PVRSRV_HANDLE_BASE *psBase,
841              void *pvData,
842              PVRSRV_HANDLE_TYPE eType,
843              IMG_HANDLE hParent)
844 {
845         PVR_UNREFERENCED_PARAMETER(psBase);
846
847         aKey[HAND_KEY_DATA] = (uintptr_t)pvData;
848         aKey[HAND_KEY_TYPE] = (uintptr_t)eType;
849         aKey[HAND_KEY_PARENT] = (uintptr_t)hParent;
850 }
851
852 static PVRSRV_ERROR FreeHandleWrapper(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE hHandle);
853
854 /*!
855 ******************************************************************************
856
857  @Function      FreeHandle
858
859  @Description   Free a handle data structure.
860
861  @Input         psBase - Pointer to handle base structure
862                 hHandle - Handle to be freed
863                 eType - Type of the handle to be freed
864                 ppvData - Location for data associated with the freed handle
865
866  @Output                ppvData - Points to data that was associated with the freed handle
867
868  @Return        PVRSRV_OK or PVRSRV_ERROR
869
870 ******************************************************************************/
871 static PVRSRV_ERROR FreeHandle(PVRSRV_HANDLE_BASE *psBase,
872                                IMG_HANDLE hHandle,
873                                PVRSRV_HANDLE_TYPE eType,
874                                void **ppvData)
875 {
876         HANDLE_DATA *psHandleData = NULL;
877         HANDLE_DATA *psReleasedHandleData;
878         PVRSRV_ERROR eError;
879
880         eError = GetHandleData(psBase, &psHandleData, hHandle, eType);
881         if (eError != PVRSRV_OK)
882         {
883                 return eError;
884         }
885
886         if(_HandleUnref(psHandleData) > 0)
887         {
888                 /* this handle still has references so do not destroy it
889                  * or the underlying object yet
890                  */
891                 return PVRSRV_OK;
892         }
893
894         /* Call the release data callback for each reference on the handle */
895         if (psHandleData->pfnReleaseData != NULL)
896         {
897                 eError = psHandleData->pfnReleaseData(psHandleData->pvData);
898                 if (eError == PVRSRV_ERROR_RETRY)
899                 {
900                         PVR_DPF((PVR_DBG_MESSAGE,
901                                  "FreeHandle: "
902                                  "Got retry while calling release data callback for %p (type = %d)",
903                                  hHandle,
904                                  (IMG_UINT32)psHandleData->eType));
905
906                         /* the caller should retry, so retain a reference on the handle */
907                         _HandleRef(psHandleData);
908
909                         return eError;
910                 }
911                 else if (eError != PVRSRV_OK)
912                 {
913                         return eError;
914                 }
915         }
916
917         if (!TEST_ALLOC_FLAG(psHandleData, PVRSRV_HANDLE_ALLOC_FLAG_MULTI))
918         {
919                 HAND_KEY aKey;
920                 IMG_HANDLE hRemovedHandle;
921
922                 InitKey(aKey, psBase, psHandleData->pvData, psHandleData->eType, ParentIfPrivate(psHandleData));
923
924                 hRemovedHandle = (IMG_HANDLE)HASH_Remove_Extended(psBase->psHashTab, aKey);
925
926                 PVR_ASSERT(hRemovedHandle != NULL);
927                 PVR_ASSERT(hRemovedHandle == psHandleData->hHandle);
928                 PVR_UNREFERENCED_PARAMETER(hRemovedHandle);
929         }
930
931         eError = UnlinkFromParent(psBase, psHandleData);
932         if (eError != PVRSRV_OK)
933         {
934                 PVR_DPF((PVR_DBG_ERROR,
935                          "FreeHandle: Error whilst unlinking from parent handle (%s)", 
936                          PVRSRVGetErrorStringKM(eError)));
937                 return eError;
938         }
939
940         /* Free children */
941         eError = IterateOverChildren(psBase, psHandleData, FreeHandleWrapper);
942         if (eError != PVRSRV_OK)
943         {
944                 PVR_DPF((PVR_DBG_ERROR,
945                          "FreeHandle: Error whilst freeing subhandles (%s)",
946                          PVRSRVGetErrorStringKM(eError)));
947                 return eError;
948         }
949
950         eError = gpsHandleFuncs->pfnReleaseHandle(psBase->psImplBase,
951                                                   psHandleData->hHandle,
952                                                   (void **)&psReleasedHandleData);
953         if (eError == PVRSRV_OK)
954         {
955                 PVR_ASSERT(psReleasedHandleData == psHandleData);
956         }
957
958         if (ppvData)
959         {
960                 *ppvData = psHandleData->pvData;
961         }
962
963         OSFreeMem(psHandleData);
964
965         return eError;
966 }
967
968 static PVRSRV_ERROR FreeHandleWrapper(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE hHandle)
969 {
970         return FreeHandle(psBase, hHandle, PVRSRV_HANDLE_TYPE_NONE, NULL);
971 }
972
973 /*!
974 ******************************************************************************
975
976  @Function      FindHandle
977
978  @Description   Find handle corresponding to a resource pointer
979
980  @Input         psBase - pointer to handle base structure
981                 pvData - pointer to resource to be associated with the handle
982                 eType - the type of resource
983
984  @Return        the handle, or NULL if not found
985
986 ******************************************************************************/
987 #ifdef INLINE_IS_PRAGMA
988 #pragma inline(FindHandle)
989 #endif
990 static INLINE
991 IMG_HANDLE FindHandle(PVRSRV_HANDLE_BASE *psBase,
992                       void *pvData,
993                       PVRSRV_HANDLE_TYPE eType,
994                       IMG_HANDLE hParent)
995 {
996         HAND_KEY aKey;
997
998         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
999
1000         InitKey(aKey, psBase, pvData, eType, hParent);
1001
1002         return (IMG_HANDLE) HASH_Retrieve_Extended(psBase->psHashTab, aKey);
1003 }
1004
1005 /*!
1006 ******************************************************************************
1007
1008  @Function      AllocHandle
1009
1010  @Description   Allocate a new handle
1011
1012  @Input         phHandle - location for new handle
1013                 pvData - pointer to resource to be associated with the handle
1014                 eType - the type of resource
1015                 hParent - parent handle or NULL
1016                 pfnReleaseData - Function to release resource at handle release
1017                                  time
1018
1019  @Output        phHandle - points to new handle
1020
1021  @Return        Error code or PVRSRV_OK
1022
1023 ******************************************************************************/
1024 static PVRSRV_ERROR AllocHandle(PVRSRV_HANDLE_BASE *psBase,
1025                                 IMG_HANDLE *phHandle,
1026                                 void *pvData,
1027                                 PVRSRV_HANDLE_TYPE eType,
1028                                 PVRSRV_HANDLE_ALLOC_FLAG eFlag,
1029                                 IMG_HANDLE hParent,
1030                                 PFN_HANDLE_RELEASE pfnReleaseData)
1031 {
1032         HANDLE_DATA *psNewHandleData;
1033         IMG_HANDLE hHandle;
1034         PVRSRV_ERROR eError;
1035
1036         /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */
1037         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1038         PVR_ASSERT(psBase != NULL && psBase->psHashTab != NULL);
1039         PVR_ASSERT(gpsHandleFuncs);
1040
1041         if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI))
1042         {
1043                 /* Handle must not already exist */
1044                 PVR_ASSERT(FindHandle(psBase, pvData, eType, hParent) == NULL);
1045         }
1046
1047         psNewHandleData = OSAllocZMem(sizeof(*psNewHandleData));
1048         if (psNewHandleData == NULL)
1049         {
1050                 PVR_DPF((PVR_DBG_ERROR, "AllocHandle: Couldn't allocate handle data"));
1051                 return PVRSRV_ERROR_OUT_OF_MEMORY;
1052         }
1053
1054         eError = gpsHandleFuncs->pfnAcquireHandle(psBase->psImplBase, &hHandle, psNewHandleData);
1055         if (eError != PVRSRV_OK)
1056         {
1057                 PVR_DPF((PVR_DBG_ERROR, "AllocHandle: Failed to acquire a handle"));
1058                 goto ErrorFreeHandleData;
1059         }
1060
1061         /*
1062          * If a data pointer can be associated with multiple handles, we
1063          * don't put the handle in the hash table, as the data pointer
1064          * may not map to a unique handle
1065          */
1066         if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI))
1067         {
1068                 HAND_KEY aKey;
1069
1070                 /* Initialise hash key */
1071                 InitKey(aKey, psBase, pvData, eType, hParent);
1072
1073                 /* Put the new handle in the hash table */
1074                 if (!HASH_Insert_Extended(psBase->psHashTab, aKey, (uintptr_t)hHandle))
1075                 {
1076                         PVR_DPF((PVR_DBG_ERROR, "AllocHandle: Couldn't add handle to hash table"));
1077                         eError = PVRSRV_ERROR_UNABLE_TO_ADD_HANDLE;
1078                         goto ErrorReleaseHandle;
1079                 }
1080         }
1081
1082         psNewHandleData->hHandle = hHandle;
1083         psNewHandleData->eType = eType;
1084         psNewHandleData->eFlag = eFlag;
1085         psNewHandleData->pvData = pvData;
1086         psNewHandleData->pfnReleaseData = pfnReleaseData;
1087         psNewHandleData->ui32RefCount = 1;
1088
1089         InitParentList(psNewHandleData);
1090 #if defined(DEBUG)
1091         PVR_ASSERT(NoChildren(psNewHandleData));
1092 #endif
1093
1094         InitChildEntry(psNewHandleData);
1095 #if defined(DEBUG)
1096         PVR_ASSERT(NoParent(psNewHandleData));
1097 #endif
1098
1099         /* Return the new handle to the client */
1100         *phHandle = psNewHandleData->hHandle;
1101
1102         return PVRSRV_OK;
1103
1104 ErrorReleaseHandle:
1105         (void)gpsHandleFuncs->pfnReleaseHandle(psBase->psImplBase, hHandle, NULL);
1106
1107 ErrorFreeHandleData:
1108         OSFreeMem(psNewHandleData);
1109
1110         return eError;
1111 }
1112
1113 /*!
1114 ******************************************************************************
1115
1116  @Function      PVRSRVAllocHandle
1117
1118  @Description   Allocate a handle
1119
1120  @Input         phHandle - location for new handle
1121                 pvData - pointer to resource to be associated with the handle
1122                 eType - the type of resource
1123                 pfnReleaseData - Function to release resource at handle release
1124                                  time
1125
1126  @Output        phHandle - points to new handle
1127
1128  @Return        Error code or PVRSRV_OK
1129
1130 ******************************************************************************/
1131 PVRSRV_ERROR PVRSRVAllocHandle(PVRSRV_HANDLE_BASE *psBase,
1132                                IMG_HANDLE *phHandle,
1133                                void *pvData,
1134                                PVRSRV_HANDLE_TYPE eType,
1135                                PVRSRV_HANDLE_ALLOC_FLAG eFlag,
1136                                PFN_HANDLE_RELEASE pfnReleaseData)
1137 {
1138         PVRSRV_ERROR eError;
1139
1140         LockHandle();
1141         eError = PVRSRVAllocHandleUnlocked(psBase, phHandle, pvData, eType, eFlag, pfnReleaseData);
1142         UnlockHandle();
1143
1144         return eError;
1145 }
1146
1147 /*!
1148 ******************************************************************************
1149
1150  @Function      PVRSRVAllocHandleUnlocked
1151
1152  @Description   Allocate a handle without acquiring/releasing the handle
1153                 lock. The function assumes you hold the lock when called.
1154
1155  @Input         phHandle - location for new handle
1156                 pvData - pointer to resource to be associated with the handle
1157                 eType - the type of resource
1158                 pfnReleaseData - Function to release resource at handle release
1159                                  time
1160
1161  @Output        phHandle - points to new handle
1162
1163  @Return        Error code or PVRSRV_OK
1164
1165 ******************************************************************************/
1166 PVRSRV_ERROR PVRSRVAllocHandleUnlocked(PVRSRV_HANDLE_BASE *psBase,
1167                                IMG_HANDLE *phHandle,
1168                                void *pvData,
1169                                PVRSRV_HANDLE_TYPE eType,
1170                                PVRSRV_HANDLE_ALLOC_FLAG eFlag,
1171                                PFN_HANDLE_RELEASE pfnReleaseData)
1172 {
1173         PVRSRV_ERROR eError;
1174
1175         *phHandle = NULL;
1176
1177         /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */
1178         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1179         PVR_ASSERT(gpsHandleFuncs);
1180
1181         if (psBase == NULL)
1182         {
1183                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandle: Missing handle base"));
1184                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1185                 goto Exit;
1186         }
1187
1188         if (pfnReleaseData == NULL)
1189         {
1190                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandle: Missing release function"));
1191                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1192                 goto Exit;
1193         }
1194
1195         eError = AllocHandle(psBase, phHandle, pvData, eType, eFlag, NULL, pfnReleaseData);
1196
1197 Exit:
1198         return eError;
1199 }
1200
1201 /*!
1202 ******************************************************************************
1203
1204  @Function      PVRSRVAllocSubHandle
1205
1206  @Description   Allocate a subhandle
1207
1208  @Input         phHandle - location for new subhandle
1209                 pvData - pointer to resource to be associated with the subhandle
1210                 eType - the type of resource
1211                 hParent - parent handle
1212
1213  @Output        phHandle - points to new subhandle
1214
1215  @Return        Error code or PVRSRV_OK
1216
1217 ******************************************************************************/
1218 PVRSRV_ERROR PVRSRVAllocSubHandle(PVRSRV_HANDLE_BASE *psBase,
1219                                   IMG_HANDLE *phHandle,
1220                                   void *pvData,
1221                                   PVRSRV_HANDLE_TYPE eType,
1222                                   PVRSRV_HANDLE_ALLOC_FLAG eFlag,
1223                                   IMG_HANDLE hParent)
1224 {
1225         PVRSRV_ERROR eError;
1226
1227         LockHandle();
1228         eError = PVRSRVAllocSubHandleUnlocked(psBase, phHandle, pvData, eType, eFlag, hParent);
1229         UnlockHandle();
1230
1231         return eError;
1232 }
1233
1234 /*!
1235 ******************************************************************************
1236
1237  @Function      PVRSRVAllocSubHandleUnlocked
1238
1239  @Description   Allocate a subhandle without acquiring/releasing the
1240                 handle lock. The function assumes you hold the lock when called.
1241
1242  @Input         phHandle - location for new subhandle
1243                 pvData - pointer to resource to be associated with the subhandle
1244                 eType - the type of resource
1245                 hParent - parent handle
1246
1247  @Output        phHandle - points to new subhandle
1248
1249  @Return        Error code or PVRSRV_OK
1250
1251 ******************************************************************************/
1252 PVRSRV_ERROR PVRSRVAllocSubHandleUnlocked(PVRSRV_HANDLE_BASE *psBase,
1253                                   IMG_HANDLE *phHandle,
1254                                   void *pvData,
1255                                   PVRSRV_HANDLE_TYPE eType,
1256                                   PVRSRV_HANDLE_ALLOC_FLAG eFlag,
1257                                   IMG_HANDLE hParent)
1258 {
1259         HANDLE_DATA *psPHandleData = NULL;
1260         HANDLE_DATA *psCHandleData = NULL;
1261         IMG_HANDLE hParentKey;
1262         IMG_HANDLE hHandle;
1263         PVRSRV_ERROR eError;
1264
1265         *phHandle = NULL;
1266
1267         /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */
1268         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1269         PVR_ASSERT(gpsHandleFuncs);
1270
1271         if (psBase == NULL)
1272         {
1273                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocSubHandle: Missing handle base"));
1274                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1275                 goto Exit;
1276         }
1277
1278         hParentKey = TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ? hParent : NULL;
1279
1280         /* Lookup the parent handle */
1281         eError = GetHandleData(psBase, &psPHandleData, hParent, PVRSRV_HANDLE_TYPE_NONE);
1282         if (eError != PVRSRV_OK)
1283         {
1284                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocSubHandle: Failed to get parent handle structure"));
1285                 goto Exit;
1286         }
1287
1288         eError = AllocHandle(psBase, &hHandle, pvData, eType, eFlag, hParentKey, NULL);
1289         if (eError != PVRSRV_OK)
1290         {
1291                 goto Exit;
1292         }
1293
1294         eError = GetHandleData(psBase, &psCHandleData, hHandle, PVRSRV_HANDLE_TYPE_NONE);
1295         if (eError != PVRSRV_OK)
1296         {
1297                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocSubHandle: Failed to get parent handle structure"));
1298
1299                 /* If we were able to allocate the handle then there should be no reason why we 
1300                    can't also get it's handle structure. Otherwise something has gone badly wrong. */
1301                 PVR_ASSERT(eError == PVRSRV_OK);
1302
1303                 goto Exit;
1304         }
1305
1306         /*
1307          * Get the parent handle structure again, in case the handle
1308          * structure has moved (depending on the implementation
1309          * of AllocHandle).
1310          */
1311         eError = GetHandleData(psBase, &psPHandleData, hParent, PVRSRV_HANDLE_TYPE_NONE);
1312         if (eError != PVRSRV_OK)
1313         {
1314                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocSubHandle: Failed to get parent handle structure"));
1315
1316                 (void)FreeHandle(psBase, hHandle, eType, NULL);
1317                 goto Exit;
1318         }
1319
1320         eError = AdoptChild(psBase, psPHandleData, psCHandleData);
1321         if (eError != PVRSRV_OK)
1322         {
1323                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocSubHandle: Parent handle failed to adopt subhandle"));
1324
1325                 (void)FreeHandle(psBase, hHandle, eType, NULL);
1326                 goto Exit;
1327         }
1328
1329         *phHandle = hHandle;
1330
1331         eError = PVRSRV_OK;
1332
1333 Exit:
1334         return eError;
1335 }
1336
1337 /*!
1338 ******************************************************************************
1339
1340  @Function      PVRSRVFindHandle
1341
1342  @Description   Find handle corresponding to a resource pointer
1343
1344  @Input         phHandle - location for returned handle
1345                 pvData - pointer to resource to be associated with the handle
1346                 eType - the type of resource
1347
1348  @Output        phHandle - points to handle
1349
1350  @Return        Error code or PVRSRV_OK
1351
1352 ******************************************************************************/
1353 PVRSRV_ERROR PVRSRVFindHandle(PVRSRV_HANDLE_BASE *psBase,
1354                               IMG_HANDLE *phHandle,
1355                               void *pvData,
1356                               PVRSRV_HANDLE_TYPE eType)
1357 {
1358         PVRSRV_ERROR eError;
1359
1360         LockHandle();
1361         eError = PVRSRVFindHandleUnlocked(psBase, phHandle, pvData, eType);
1362         UnlockHandle();
1363
1364         return eError;
1365 }
1366
1367 /*!
1368 ******************************************************************************
1369
1370  @Function      PVRSRVFindHandleUnlocked
1371
1372  @Description   Find handle corresponding to a resource pointer without
1373                 acquiring/releasing the handle lock. The function assumes you hold
1374                 the lock when called.
1375
1376  @Input         phHandle - location for returned handle
1377                 pvData - pointer to resource to be associated with the handle
1378                 eType - the type of resource
1379
1380  @Output        phHandle - points to handle
1381
1382  @Return        Error code or PVRSRV_OK
1383
1384 ******************************************************************************/
1385 PVRSRV_ERROR PVRSRVFindHandleUnlocked(PVRSRV_HANDLE_BASE *psBase,
1386                               IMG_HANDLE *phHandle,
1387                               void *pvData,
1388                               PVRSRV_HANDLE_TYPE eType)
1389 {
1390         IMG_HANDLE hHandle;
1391         PVRSRV_ERROR eError;
1392
1393         /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */
1394         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1395         PVR_ASSERT(gpsHandleFuncs);
1396
1397         if (psBase == NULL)
1398         {
1399                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVFindHandle: Missing handle base"));
1400                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1401                 goto Exit;
1402         }
1403
1404         /* See if there is a handle for this data pointer */
1405         hHandle = FindHandle(psBase, pvData, eType, NULL);
1406         if (hHandle == NULL)
1407         {
1408                 PVR_DPF((PVR_DBG_ERROR,
1409                          "PVRSRVFindHandle: Error finding handle. Type %u",
1410                          eType));
1411
1412                 eError = PVRSRV_ERROR_HANDLE_NOT_FOUND;
1413                 goto Exit;
1414         }
1415
1416         *phHandle = hHandle;
1417
1418         eError = PVRSRV_OK;
1419
1420 Exit:
1421         return eError;
1422
1423 }
1424
1425 /*!
1426 ******************************************************************************
1427
1428  @Function      PVRSRVLookupHandle
1429
1430  @Description   Lookup the data pointer corresponding to a handle
1431
1432  @Input         ppvData - location to return data pointer
1433                 hHandle - handle from client
1434                 eType - handle type
1435                 bRef - If TRUE, a reference will be added on the handle if the
1436                        lookup is successful.
1437
1438  @Output        ppvData - points to the data pointer
1439
1440  @Return        Error code or PVRSRV_OK
1441
1442 ******************************************************************************/
1443 PVRSRV_ERROR PVRSRVLookupHandle(PVRSRV_HANDLE_BASE *psBase,
1444                                 void **ppvData,
1445                                 IMG_HANDLE hHandle,
1446                                 PVRSRV_HANDLE_TYPE eType,
1447                                 IMG_BOOL bRef)
1448 {
1449         PVRSRV_ERROR eError;
1450
1451         LockHandle();
1452         eError = PVRSRVLookupHandleUnlocked(psBase, ppvData, hHandle, eType, bRef);
1453         UnlockHandle();
1454
1455         return eError;
1456 }
1457
1458 /*!
1459 ******************************************************************************
1460
1461  @Function      PVRSRVLookupHandleUnlocked
1462
1463  @Description   Lookup the data pointer corresponding to a handle without
1464                 acquiring/releasing the handle lock. The function assumes you
1465                 hold the lock when called.
1466
1467  @Input         ppvData - location to return data pointer
1468                 hHandle - handle from client
1469                 eType - handle type
1470                 bRef - If TRUE, a reference will be added on the handle if the
1471                        lookup is successful.
1472
1473  @Output        ppvData - points to the data pointer
1474
1475  @Return        Error code or PVRSRV_OK
1476
1477 ******************************************************************************/
1478 PVRSRV_ERROR PVRSRVLookupHandleUnlocked(PVRSRV_HANDLE_BASE *psBase,
1479                                 void **ppvData,
1480                                 IMG_HANDLE hHandle,
1481                                 PVRSRV_HANDLE_TYPE eType,
1482                                 IMG_BOOL bRef)
1483 {
1484         HANDLE_DATA *psHandleData = NULL;
1485         PVRSRV_ERROR eError;
1486
1487         /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */
1488         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1489         PVR_ASSERT(gpsHandleFuncs);
1490
1491         if (psBase == NULL)
1492         {
1493                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupHandle: Missing handle base"));
1494                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1495                 goto Exit;
1496         }
1497
1498         eError = GetHandleData(psBase, &psHandleData, hHandle, eType);
1499         if (eError != PVRSRV_OK)
1500         {
1501                 PVR_DPF((PVR_DBG_ERROR,
1502                          "PVRSRVLookupHandle: Error looking up handle (%s). Handle %p, type %u",
1503                          PVRSRVGetErrorStringKM(eError),
1504                          (void*) hHandle,
1505                          eType));
1506 #if defined(DEBUG) || defined(PVRSRV_NEED_PVR_DPF)
1507                 OSDumpStack();
1508 #endif
1509                 goto Exit;
1510         }
1511
1512         if(bRef)
1513         {
1514                 _HandleRef(psHandleData);
1515         }
1516
1517         *ppvData = psHandleData->pvData;
1518
1519         eError = PVRSRV_OK;
1520
1521 Exit:
1522
1523         return eError;
1524 }
1525
1526 /*!
1527 ******************************************************************************
1528
1529  @Function      PVRSRVLookupSubHandle
1530
1531  @Description   Lookup the data pointer corresponding to a subhandle
1532
1533  @Input         ppvData - location to return data pointer
1534                 hHandle - handle from client
1535                 eType - handle type
1536                 hAncestor - ancestor handle
1537
1538  @Output        ppvData - points to the data pointer
1539
1540  @Return        Error code or PVRSRV_OK
1541
1542 ******************************************************************************/
1543 PVRSRV_ERROR PVRSRVLookupSubHandle(PVRSRV_HANDLE_BASE *psBase,
1544                                    void **ppvData,
1545                                    IMG_HANDLE hHandle,
1546                                    PVRSRV_HANDLE_TYPE eType,
1547                                    IMG_HANDLE hAncestor)
1548 {
1549         HANDLE_DATA *psPHandleData = NULL;
1550         HANDLE_DATA *psCHandleData = NULL;
1551         PVRSRV_ERROR eError;
1552
1553         /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */
1554         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1555         PVR_ASSERT(gpsHandleFuncs);
1556
1557         LockHandle();
1558
1559         if (psBase == NULL)
1560         {
1561                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupSubHandle: Missing handle base"));
1562                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1563                 goto ExitUnlock;
1564         }
1565
1566         eError = GetHandleData(psBase, &psCHandleData, hHandle, eType);
1567         if (eError != PVRSRV_OK)
1568         {
1569                 PVR_DPF((PVR_DBG_ERROR,
1570                          "PVRSRVLookupSubHandle: Error looking up subhandle (%s). Handle %p, type %u",
1571                          PVRSRVGetErrorStringKM(eError),
1572                          (void*) hHandle,
1573                          eType));
1574                 OSDumpStack();
1575                 goto ExitUnlock;
1576         }
1577
1578         /* Look for hAncestor among the handle's ancestors */
1579         for (psPHandleData = psCHandleData; ParentHandle(psPHandleData) != hAncestor; )
1580         {
1581                 eError = GetHandleData(psBase, &psPHandleData, ParentHandle(psPHandleData), PVRSRV_HANDLE_TYPE_NONE);
1582                 if (eError != PVRSRV_OK)
1583                 {
1584                         PVR_DPF((PVR_DBG_ERROR,"PVRSRVLookupSubHandle: Subhandle doesn't belong to given ancestor"));
1585                         eError = PVRSRV_ERROR_INVALID_SUBHANDLE;
1586                         goto ExitUnlock;
1587                 }
1588         }
1589
1590         *ppvData = psCHandleData->pvData;
1591
1592         eError = PVRSRV_OK;
1593
1594 ExitUnlock:
1595         UnlockHandle();
1596
1597         return eError;
1598 }
1599
1600 /*!
1601 ******************************************************************************
1602
1603  @Function      PVRSRVGetParentHandle
1604
1605  @Description   Lookup the parent of a handle
1606
1607  @Input         phParent - location for returning parent handle
1608                 hHandle - handle for which the parent handle is required
1609                 eType - handle type
1610                 hParent - parent handle
1611
1612  @Output        *phParent - parent handle, or NULL if there is no parent
1613
1614  @Return        Error code or PVRSRV_OK.  Note that not having a parent is
1615                 not regarded as an error.
1616
1617 ******************************************************************************/
1618 PVRSRV_ERROR PVRSRVGetParentHandle(PVRSRV_HANDLE_BASE *psBase,
1619                                    IMG_HANDLE *phParent,
1620                                    IMG_HANDLE hHandle,
1621                                    PVRSRV_HANDLE_TYPE eType)
1622 {
1623         HANDLE_DATA *psHandleData = NULL;
1624         PVRSRV_ERROR eError;
1625
1626         /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */
1627         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1628         PVR_ASSERT(gpsHandleFuncs);
1629
1630         LockHandle();
1631
1632         if (psBase == NULL)
1633         {
1634                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetParentHandle: Missing handle base"));
1635                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1636                 goto ExitUnlock;
1637         }
1638
1639         eError = GetHandleData(psBase, &psHandleData, hHandle, eType);
1640         if (eError != PVRSRV_OK)
1641         {
1642                 PVR_DPF((PVR_DBG_ERROR,
1643                          "PVRSRVGetParentHandle: Error looking up subhandle (%s). Type %u",
1644                          PVRSRVGetErrorStringKM(eError),
1645                          eType));
1646                 OSDumpStack();
1647                 goto ExitUnlock;
1648         }
1649
1650         *phParent = ParentHandle(psHandleData);
1651
1652         eError = PVRSRV_OK;
1653
1654 ExitUnlock:
1655         UnlockHandle();
1656
1657         return eError;
1658 }
1659
1660 /*!
1661 ******************************************************************************
1662
1663  @Function      PVRSRVReleaseHandle
1664
1665  @Description   Release a handle that is no longer needed
1666
1667  @Input         hHandle - handle from client
1668                 eType - handle type
1669
1670  @Return        Error code or PVRSRV_OK
1671
1672 ******************************************************************************/
1673 PVRSRV_ERROR PVRSRVReleaseHandle(PVRSRV_HANDLE_BASE *psBase,
1674                                  IMG_HANDLE hHandle,
1675                                  PVRSRV_HANDLE_TYPE eType)
1676 {
1677         PVRSRV_ERROR eError;
1678
1679         LockHandle();
1680         eError = PVRSRVReleaseHandleUnlocked(psBase, hHandle, eType);
1681         UnlockHandle();
1682
1683         return eError;
1684 }
1685
1686
1687 /*!
1688 ******************************************************************************
1689
1690  @Function      PVRSRVReleaseHandleUnlocked
1691
1692  @Description   Release a handle that is no longer needed without
1693                 acquiring/releasing the handle lock. The function assumes you
1694                 hold the lock when called.
1695
1696  @Input         hHandle - handle from client
1697                 eType - handle type
1698
1699  @Return        Error code or PVRSRV_OK
1700
1701 ******************************************************************************/
1702 PVRSRV_ERROR PVRSRVReleaseHandleUnlocked(PVRSRV_HANDLE_BASE *psBase,
1703                                  IMG_HANDLE hHandle,
1704                                  PVRSRV_HANDLE_TYPE eType)
1705 {
1706         PVRSRV_ERROR eError;
1707
1708         /* PVRSRV_HANDLE_TYPE_NONE is reserved for internal use */
1709         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1710         PVR_ASSERT(gpsHandleFuncs);
1711
1712         if (psBase == NULL)
1713         {
1714                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVReleaseHandle: Missing handle base"));
1715                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1716                 goto Exit;
1717         }
1718
1719         eError = FreeHandle(psBase, hHandle, eType, NULL);
1720
1721 Exit:
1722
1723         return eError;
1724 }
1725
1726 /*!
1727 ******************************************************************************
1728
1729  @Function      PVRSRVPurgeHandles
1730
1731  @Description   Purge handles for a given handle base
1732
1733  @Input         psBase - pointer to handle base structure
1734
1735  @Return        Error code or PVRSRV_OK
1736
1737 ******************************************************************************/
1738 PVRSRV_ERROR PVRSRVPurgeHandles(PVRSRV_HANDLE_BASE *psBase)
1739 {
1740         PVRSRV_ERROR eError;
1741
1742         PVR_ASSERT(gpsHandleFuncs);
1743
1744         LockHandle();
1745
1746         if (psBase == NULL)
1747         {
1748                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVPurgeHandles: Missing handle base"));
1749                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1750                 goto ExitUnlock;
1751         }
1752
1753         eError = gpsHandleFuncs->pfnPurgeHandles(psBase->psImplBase);
1754
1755 ExitUnlock:
1756         UnlockHandle();
1757
1758         return eError;
1759 }
1760
1761 /*!
1762 ******************************************************************************
1763
1764  @Function      PVRSRVAllocHandleBase
1765
1766  @Description   Allocate a handle base structure for a process
1767
1768  @Input         ppsBase - pointer to handle base structure pointer
1769
1770  @Output        ppsBase - points to handle base structure pointer
1771
1772  @Return        Error code or PVRSRV_OK
1773
1774 ******************************************************************************/
1775 PVRSRV_ERROR PVRSRVAllocHandleBase(PVRSRV_HANDLE_BASE **ppsBase,
1776                                    PVRSRV_HANDLE_BASE_TYPE eType)
1777 {
1778         PVRSRV_HANDLE_BASE *psBase;
1779         PVRSRV_ERROR eError;
1780
1781         if (gpsHandleFuncs == NULL)
1782         {
1783                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandleBase: Handle management not initialised"));
1784                 return PVRSRV_ERROR_NOT_READY;
1785         }
1786
1787         LockHandle();
1788
1789         if (ppsBase == NULL)
1790         {
1791                 eError = PVRSRV_ERROR_INVALID_PARAMS;
1792                 goto ErrorUnlock;
1793         }
1794
1795         psBase = OSAllocZMem(sizeof(*psBase));
1796         if (psBase == NULL)
1797         {
1798                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandleBase: Couldn't allocate handle base"));
1799                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
1800                 goto ErrorUnlock;
1801         }
1802
1803         psBase->eType = eType;
1804
1805         eError = gpsHandleFuncs->pfnCreateHandleBase(&psBase->psImplBase);
1806         if (eError != PVRSRV_OK)
1807         {
1808                 goto ErrorFreeHandleBase;
1809         }
1810
1811         psBase->psHashTab = HASH_Create_Extended(HANDLE_HASH_TAB_INIT_SIZE, 
1812                                                  sizeof(HAND_KEY), 
1813                                                  HASH_Func_Default, 
1814                                                  HASH_Key_Comp_Default);
1815         if (psBase->psHashTab == NULL)
1816         {
1817                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandleBase: Couldn't create data pointer hash table"));
1818                 eError = PVRSRV_ERROR_UNABLE_TO_CREATE_HASH_TABLE;
1819                 goto ErrorDestroyHandleBase;
1820         }
1821
1822         *ppsBase = psBase;
1823
1824         UnlockHandle();
1825
1826         return PVRSRV_OK;
1827
1828 ErrorDestroyHandleBase:
1829         (void)gpsHandleFuncs->pfnDestroyHandleBase(psBase->psImplBase);
1830
1831 ErrorFreeHandleBase:
1832         OSFreeMem(psBase);
1833
1834 ErrorUnlock:
1835         UnlockHandle();
1836
1837         return eError;
1838 }
1839
1840 #if defined(DEBUG)
1841 typedef struct _COUNT_HANDLE_DATA_
1842 {
1843         PVRSRV_HANDLE_BASE *psBase;
1844         IMG_UINT32 uiHandleDataCount;
1845 } COUNT_HANDLE_DATA;
1846
1847 /* Used to count the number of handles that have data associated with them */
1848 static PVRSRV_ERROR CountHandleDataWrapper(IMG_HANDLE hHandle, void *pvData)
1849 {
1850         COUNT_HANDLE_DATA *psData = (COUNT_HANDLE_DATA *)pvData;
1851         HANDLE_DATA *psHandleData = NULL;
1852         PVRSRV_ERROR eError;
1853
1854         PVR_ASSERT(gpsHandleFuncs);
1855
1856         if (psData == NULL ||
1857             psData->psBase == NULL)
1858         {
1859                 PVR_DPF((PVR_DBG_ERROR, "CountHandleDataWrapper: Missing free data"));
1860                 return PVRSRV_ERROR_INVALID_PARAMS;
1861         }
1862
1863         eError = GetHandleData(psData->psBase, 
1864                                &psHandleData, 
1865                                hHandle, 
1866                                PVRSRV_HANDLE_TYPE_NONE);
1867         if (eError != PVRSRV_OK)
1868         {
1869                 PVR_DPF((PVR_DBG_ERROR, "CountHandleDataWrapper: Couldn't get handle data for handle"));
1870                 return eError;
1871         }
1872
1873         if (psHandleData != NULL)
1874         {
1875                 psData->uiHandleDataCount++;
1876         }
1877
1878         return PVRSRV_OK;
1879 }
1880
1881 /* Print a handle in the handle base. Used with the iterator callback. */
1882 static PVRSRV_ERROR ListHandlesInBase(IMG_HANDLE hHandle, void *pvData)
1883 {
1884         PVRSRV_HANDLE_BASE *psBase = (PVRSRV_HANDLE_BASE*) pvData;
1885         HANDLE_DATA *psHandleData = NULL;
1886         PVRSRV_ERROR eError;
1887
1888         PVR_ASSERT(gpsHandleFuncs);
1889
1890         if (psBase == NULL)
1891         {
1892                 PVR_DPF((PVR_DBG_ERROR, "%s: Missing base", __func__));
1893                 return PVRSRV_ERROR_INVALID_PARAMS;
1894         }
1895
1896         eError = GetHandleData(psBase,
1897                                &psHandleData,
1898                                hHandle,
1899                                PVRSRV_HANDLE_TYPE_NONE);
1900         if (eError != PVRSRV_OK)
1901         {
1902                 PVR_DPF((PVR_DBG_ERROR, "%s: Couldn't get handle data for handle", __func__));
1903                 return eError;
1904         }
1905
1906         if (psHandleData != NULL)
1907         {
1908                 PVR_DPF((PVR_DBG_WARNING, "    Handle: %6u, Type: %3u, Refs: %3u",
1909                                 (IMG_UINT32) (uintptr_t) psHandleData->hHandle,
1910                                 psHandleData->eType,
1911                                 psHandleData->ui32RefCount));
1912
1913         }
1914
1915         return PVRSRV_OK;
1916 }
1917
1918
1919
1920 #endif /* defined(DEBUG) */
1921
1922 typedef struct FREE_HANDLE_DATA_TAG
1923 {
1924         PVRSRV_HANDLE_BASE *psBase;
1925         PVRSRV_HANDLE_TYPE eHandleFreeType;
1926         /* timing data (ns) to release bridge lock upon the deadline */
1927         IMG_UINT64 ui64TimeStart;
1928         IMG_UINT64 ui64MaxBridgeTime;
1929 } FREE_HANDLE_DATA;
1930
1931 static INLINE IMG_BOOL _CheckIfMaxTimeExpired(IMG_UINT64 ui64TimeStart, IMG_UINT64 ui64MaxBridgeTime)
1932 {
1933         IMG_UINT64 ui64Diff;
1934         IMG_UINT64 ui64Now = OSClockns64();
1935
1936         if(ui64Now >= ui64TimeStart)
1937         {
1938                 ui64Diff = ui64Now - ui64TimeStart;
1939         }
1940         else
1941         {
1942                 /* time has wrapped around */
1943                 ui64Diff = (0xFFFFFFFFFFFFFFFF - ui64TimeStart) + ui64Now;
1944         }
1945
1946         return ui64Diff >= ui64MaxBridgeTime;
1947 }
1948
1949 static PVRSRV_ERROR FreeHandleDataWrapper(IMG_HANDLE hHandle, void *pvData)
1950 {
1951         FREE_HANDLE_DATA *psData = (FREE_HANDLE_DATA *)pvData;
1952         HANDLE_DATA *psHandleData = NULL;
1953         PVRSRV_ERROR eError;
1954
1955         PVR_ASSERT(gpsHandleFuncs);
1956
1957         if (psData == NULL ||
1958             psData->psBase == NULL ||
1959             psData->eHandleFreeType == PVRSRV_HANDLE_TYPE_NONE)
1960         {
1961                 PVR_DPF((PVR_DBG_ERROR, "FreeHandleDataWrapper: Missing free data"));
1962                 return PVRSRV_ERROR_INVALID_PARAMS;
1963         }
1964
1965         eError = GetHandleData(psData->psBase, 
1966                                &psHandleData, 
1967                                hHandle, 
1968                                PVRSRV_HANDLE_TYPE_NONE);
1969         if (eError != PVRSRV_OK)
1970         {
1971                 PVR_DPF((PVR_DBG_ERROR, "FreeHandleDataWrapper: Couldn't get handle data for handle"));
1972                 return eError;
1973         }
1974
1975         if (psHandleData == NULL || psHandleData->eType != psData->eHandleFreeType)
1976         {
1977                 return PVRSRV_OK;
1978         }
1979
1980         PVR_ASSERT(psHandleData->ui32RefCount > 0);
1981
1982         while (psHandleData->ui32RefCount != 0)
1983         {
1984                 if (psHandleData->pfnReleaseData != NULL)
1985                 {
1986                         eError = psHandleData->pfnReleaseData(psHandleData->pvData);
1987                         if (eError == PVRSRV_ERROR_RETRY)
1988                         {
1989                                 PVR_DPF((PVR_DBG_MESSAGE,
1990                                          "FreeHandleDataWrapper: "
1991                                          "Got retry while calling release data callback for %p (type = %d)",
1992                                          hHandle,
1993                                          (IMG_UINT32)psHandleData->eType));
1994
1995                                 return eError;
1996                         }
1997                         else if (eError != PVRSRV_OK)
1998                         {
1999                                 return eError;
2000                         }
2001                 }
2002
2003                 _HandleUnref(psHandleData);
2004         }
2005
2006         if (!TEST_ALLOC_FLAG(psHandleData, PVRSRV_HANDLE_ALLOC_FLAG_MULTI))
2007         {
2008                 HAND_KEY aKey;
2009                 IMG_HANDLE hRemovedHandle;
2010
2011                 InitKey(aKey,
2012                         psData->psBase,
2013                         psHandleData->pvData,
2014                         psHandleData->eType,
2015                         ParentIfPrivate(psHandleData));
2016
2017                 hRemovedHandle = (IMG_HANDLE)HASH_Remove_Extended(psData->psBase->psHashTab, aKey);
2018
2019                 PVR_ASSERT(hRemovedHandle != NULL);
2020                 PVR_ASSERT(hRemovedHandle == psHandleData->hHandle);
2021                 PVR_UNREFERENCED_PARAMETER(hRemovedHandle);
2022         }
2023
2024         eError = gpsHandleFuncs->pfnSetHandleData(psData->psBase->psImplBase, hHandle, NULL);
2025         if (eError != PVRSRV_OK)
2026         {
2027                 return eError;
2028         }
2029
2030         OSFreeMem(psHandleData);
2031
2032         /* If we reach the end of the time slice release we can release the global
2033          * lock, invoke the scheduler and reacquire the lock */
2034         if((psData->ui64MaxBridgeTime != 0) && _CheckIfMaxTimeExpired(psData->ui64TimeStart, psData->ui64MaxBridgeTime))
2035         {
2036                 PVR_DPF((PVR_DBG_MESSAGE, "FreeResourceByCriteria: Lock timeout (timeout: %llu)",
2037                                                                             psData->ui64MaxBridgeTime));
2038                 UnlockHandle();
2039                 OSReleaseBridgeLock();
2040                 /* Invoke the scheduler to check if other processes are waiting for the lock */
2041                 OSReleaseThreadQuanta();
2042                 OSAcquireBridgeLock();
2043                 LockHandle();
2044                 /* Set again lock timeout and reset the counter */
2045                 psData->ui64TimeStart = OSClockns64();
2046                 PVR_DPF((PVR_DBG_MESSAGE, "FreeResourceByCriteria: Lock acquired again"));
2047         }
2048
2049         return PVRSRV_OK;
2050 }
2051
2052 static PVRSRV_HANDLE_TYPE g_aeOrderedFreeList[] =
2053 {
2054         PVRSRV_HANDLE_TYPE_EVENT_OBJECT_CONNECT,
2055         PVRSRV_HANDLE_TYPE_SHARED_EVENT_OBJECT,
2056         PVRSRV_HANDLE_TYPE_RGX_FW_MEMDESC,
2057         PVRSRV_HANDLE_TYPE_RGX_RTDATA_CLEANUP,
2058         PVRSRV_HANDLE_TYPE_RGX_FREELIST,
2059         PVRSRV_HANDLE_TYPE_RGX_RPM_FREELIST,
2060         PVRSRV_HANDLE_TYPE_RGX_SERVER_RPM_CONTEXT,
2061         PVRSRV_HANDLE_TYPE_RGX_MEMORY_BLOCK,
2062         PVRSRV_HANDLE_TYPE_RGX_POPULATION,
2063         PVRSRV_HANDLE_TYPE_RGX_FWIF_ZSBUFFER,
2064         PVRSRV_HANDLE_TYPE_RGX_FWIF_RENDERTARGET,
2065         PVRSRV_HANDLE_TYPE_RGX_SERVER_RENDER_CONTEXT,
2066         PVRSRV_HANDLE_TYPE_RGX_SERVER_TQ_CONTEXT,
2067         PVRSRV_HANDLE_TYPE_RGX_SERVER_TQ_TDM_CONTEXT,
2068         PVRSRV_HANDLE_TYPE_RGX_SERVER_COMPUTE_CONTEXT,
2069         PVRSRV_HANDLE_TYPE_RGX_SERVER_RAY_CONTEXT,
2070         PVRSRV_HANDLE_TYPE_RGX_SERVER_KICKSYNC_CONTEXT,
2071         PVRSRV_HANDLE_TYPE_RI_HANDLE,
2072         PVRSRV_HANDLE_TYPE_SYNC_RECORD_HANDLE,
2073         PVRSRV_HANDLE_TYPE_SERVER_OP_COOKIE,
2074         PVRSRV_HANDLE_TYPE_SERVER_SYNC_PRIMITIVE,
2075         PVRSRV_HANDLE_TYPE_SERVER_SYNC_EXPORT,
2076         PVRSRV_HANDLE_TYPE_SYNC_PRIMITIVE_BLOCK,
2077         PVRSRV_HANDLE_TYPE_DEVMEMINT_MAPPING,
2078         PVRSRV_HANDLE_TYPE_DEVMEMINT_RESERVATION,
2079         PVRSRV_HANDLE_TYPE_DEVMEMINT_HEAP,
2080         PVRSRV_HANDLE_TYPE_DEVMEMINT_CTX_EXPORT,
2081         PVRSRV_HANDLE_TYPE_DEV_PRIV_DATA,
2082         PVRSRV_HANDLE_TYPE_DEVMEMINT_CTX,
2083         PVRSRV_HANDLE_TYPE_PHYSMEM_PMR_PAGELIST,
2084         PVRSRV_HANDLE_TYPE_PHYSMEM_PMR_SECURE_EXPORT,
2085         PVRSRV_HANDLE_TYPE_PHYSMEM_PMR_EXPORT,
2086         PVRSRV_HANDLE_TYPE_PHYSMEM_PMR,
2087         PVRSRV_HANDLE_TYPE_DEVMEM_MEM_IMPORT,
2088         PVRSRV_HANDLE_TYPE_PMR_LOCAL_EXPORT_HANDLE,
2089         PVRSRV_HANDLE_TYPE_DC_PIN_HANDLE,
2090         PVRSRV_HANDLE_TYPE_DC_BUFFER,
2091         PVRSRV_HANDLE_TYPE_DC_DISPLAY_CONTEXT,
2092         PVRSRV_HANDLE_TYPE_DC_DEVICE,
2093         PVRSRV_HANDLE_TYPE_PVR_TL_SD,
2094         PVRSRV_HANDLE_TYPE_MM_PLAT_CLEANUP
2095 };
2096
2097 /*!
2098 ******************************************************************************
2099
2100  @Function      PVRSRVFreeHandleBase
2101
2102  @Description   Free a handle base structure
2103
2104  @Input         psBase - pointer to handle base structure
2105
2106  @Return        Error code or PVRSRV_OK
2107
2108 ******************************************************************************/
2109 PVRSRV_ERROR PVRSRVFreeHandleBase(PVRSRV_HANDLE_BASE *psBase, IMG_UINT64 ui64MaxBridgeTime)
2110 {
2111 #if defined(DEBUG)
2112         COUNT_HANDLE_DATA sCountData = { 0 };
2113 #endif
2114         FREE_HANDLE_DATA sHandleData = { 0 };
2115         IMG_UINT32 i;
2116         PVRSRV_ERROR eError;
2117
2118         PVR_ASSERT(gpsHandleFuncs);
2119
2120         LockHandle();
2121
2122         sHandleData.psBase = psBase;
2123         sHandleData.ui64TimeStart = OSClockns64();
2124         sHandleData.ui64MaxBridgeTime = ui64MaxBridgeTime;
2125
2126
2127 #if defined(DEBUG)
2128
2129         sCountData.psBase = psBase;
2130
2131         eError = gpsHandleFuncs->pfnIterateOverHandles(psBase->psImplBase,
2132                                                        &CountHandleDataWrapper,
2133                                                        (void *)&sCountData);
2134         if (eError != PVRSRV_OK)
2135         {
2136                 PVR_DPF((PVR_DBG_ERROR,
2137                          "PVRSRVFreeHandleBase: Failed to perform handle count (%s)",
2138                          PVRSRVGetErrorStringKM(eError)));
2139                 goto ExitUnlock;
2140         }
2141
2142         if (sCountData.uiHandleDataCount != 0)
2143         {
2144                 IMG_BOOL bList = sCountData.uiHandleDataCount < HANDLE_DEBUG_LISTING_MAX_NUM;
2145
2146                 PVR_DPF((PVR_DBG_WARNING,
2147                          "%s: %u remaining handles in handle base 0x%p "
2148                          "(PVRSRV_HANDLE_BASE_TYPE %u). %s",
2149                          __func__,
2150                          sCountData.uiHandleDataCount,
2151                          psBase,
2152                          psBase->eType,
2153                          bList ? "Check handle.h for a type reference":
2154                                          "Skipping details, too many items..."));
2155
2156                 if (bList)
2157                 {
2158                         PVR_DPF((PVR_DBG_WARNING, "-------- Listing Handles --------"));
2159                         eError = gpsHandleFuncs->pfnIterateOverHandles(psBase->psImplBase,
2160                                                                                    &ListHandlesInBase,
2161                                                                                    psBase);
2162                         PVR_DPF((PVR_DBG_WARNING, "-------- Done Listing    --------"));
2163                 }
2164         }
2165
2166 #endif /* defined(DEBUG) */
2167
2168         /*
2169          * As we're freeing handles based on type, make sure all
2170          * handles have actually had their data freed to avoid
2171          * resources being leaked
2172          */
2173         for (i = 0; i < ARRAY_SIZE(g_aeOrderedFreeList); i++)
2174         {
2175                 sHandleData.eHandleFreeType = g_aeOrderedFreeList[i];
2176
2177                 /* Make sure all handles have been freed before destroying the handle base */
2178                 eError = gpsHandleFuncs->pfnIterateOverHandles(psBase->psImplBase,
2179                                                                &FreeHandleDataWrapper,
2180                                                                (void *)&sHandleData);
2181                 if (eError != PVRSRV_OK)
2182                 {
2183                         goto ExitUnlock;
2184                 }
2185         }
2186
2187
2188         if (psBase->psHashTab != NULL)
2189         {
2190                 HASH_Delete(psBase->psHashTab);
2191         }
2192
2193         eError = gpsHandleFuncs->pfnDestroyHandleBase(psBase->psImplBase);
2194         if (eError != PVRSRV_OK)
2195         {
2196                 goto ExitUnlock;
2197         }
2198
2199         OSFreeMem(psBase);
2200
2201         eError = PVRSRV_OK;
2202
2203 ExitUnlock:
2204         UnlockHandle();
2205
2206         return eError;
2207 }
2208
2209 /*!
2210 ******************************************************************************
2211
2212  @Function      PVRSRVHandleInit
2213
2214  @Description   Initialise handle management
2215
2216  @Return        Error code or PVRSRV_OK
2217
2218 ******************************************************************************/
2219 PVRSRV_ERROR PVRSRVHandleInit(void)
2220 {
2221         PVRSRV_ERROR eError;
2222
2223         PVR_ASSERT(gpsKernelHandleBase == NULL);
2224         PVR_ASSERT(gpsHandleFuncs == NULL);
2225         PVR_ASSERT(!gbLockInitialised);
2226
2227         eError = OSLockCreate(&gHandleLock, LOCK_TYPE_PASSIVE);
2228         if (eError != PVRSRV_OK)
2229         {
2230                 PVR_DPF((PVR_DBG_ERROR,
2231                          "PVRSRVHandleInit: Creation of handle global lock failed (%s)",
2232                          PVRSRVGetErrorStringKM(eError)));
2233                 return eError;
2234         }
2235         gbLockInitialised = IMG_TRUE;
2236
2237         eError = PVRSRVHandleGetFuncTable(&gpsHandleFuncs);
2238         if (eError != PVRSRV_OK)
2239         {
2240                 PVR_DPF((PVR_DBG_ERROR,
2241                          "PVRSRVHandleInit: PVRSRVHandleGetFuncTable failed (%s)",
2242                          PVRSRVGetErrorStringKM(eError)));
2243                 goto ErrorHandleDeinit;
2244         }
2245
2246         eError = PVRSRVAllocHandleBase(&gpsKernelHandleBase,
2247                                        PVRSRV_HANDLE_BASE_TYPE_GLOBAL);
2248         if (eError != PVRSRV_OK)
2249         {
2250                 PVR_DPF((PVR_DBG_ERROR,
2251                          "PVRSRVHandleInit: PVRSRVAllocHandleBase failed (%s)",
2252                          PVRSRVGetErrorStringKM(eError)));
2253                 goto ErrorHandleDeinit;
2254         }
2255
2256         eError = gpsHandleFuncs->pfnEnableHandlePurging(gpsKernelHandleBase->psImplBase);
2257         if (eError != PVRSRV_OK)
2258         {
2259                 PVR_DPF((PVR_DBG_ERROR,
2260                          "PVRSRVHandleInit: PVRSRVEnableHandlePurging failed (%s)",
2261                          PVRSRVGetErrorStringKM(eError)));
2262                 goto ErrorHandleDeinit;
2263         }
2264
2265         return PVRSRV_OK;
2266
2267 ErrorHandleDeinit:
2268         (void) PVRSRVHandleDeInit();
2269
2270         return eError;
2271 }
2272
2273 /*!
2274 ******************************************************************************
2275
2276  @Function      PVRSRVHandleDeInit
2277
2278  @Description   De-initialise handle management
2279
2280  @Return        Error code or PVRSRV_OK
2281
2282 ******************************************************************************/
2283 PVRSRV_ERROR PVRSRVHandleDeInit(void)
2284 {
2285         PVRSRV_ERROR eError = PVRSRV_OK;
2286
2287         if (gpsHandleFuncs != NULL)
2288         {
2289                 if (gpsKernelHandleBase != NULL)
2290                 {
2291                         eError = PVRSRVFreeHandleBase(gpsKernelHandleBase, 0 /* do not release bridge lock */);
2292                         if (eError == PVRSRV_OK)
2293                         {
2294                                 gpsKernelHandleBase = NULL;
2295                         }
2296                         else
2297                         {
2298                                 PVR_DPF((PVR_DBG_ERROR,
2299                                          "PVRSRVHandleDeInit: FreeHandleBase failed (%s)",
2300                                          PVRSRVGetErrorStringKM(eError)));
2301                         }
2302                 }
2303
2304                 if (eError == PVRSRV_OK)
2305                 {
2306                         gpsHandleFuncs = NULL;
2307                 }
2308         }
2309         else
2310         {
2311                 /* If we don't have a handle function table we shouldn't have a handle base either */
2312                 PVR_ASSERT(gpsKernelHandleBase == NULL);
2313         }
2314
2315         if (gbLockInitialised)
2316         {
2317                 OSLockDestroy(gHandleLock);
2318                 gbLockInitialised = IMG_FALSE;
2319         }
2320
2321         return eError;
2322 }