bfbd6b3b718d1d4916fd348496569a9861f98dad
[profile/ivi/intel-emgd-kmod.git] / pvr / services4 / srvkm / common / handle.c
1 /**********************************************************************
2  Copyright (c) Imagination Technologies Ltd.
3
4  Permission is hereby granted, free of charge, to any person obtaining a copy
5  of this software and associated documentation files (the "Software"), to deal
6  in the Software without restriction, including without limitation the rights
7  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  copies of the Software, and to permit persons to whom the Software is
9  furnished to do so, subject to the following conditions:
10
11  The above copyright notice and this permission notice shall be included in
12  all copies or substantial portions of the Software.
13
14  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  THE SOFTWARE.
21  ******************************************************************************/
22
23 #ifdef  PVR_SECURE_HANDLES
24 #include <stddef.h>
25
26 #include "services_headers.h"
27 #include "handle.h"
28
29 #ifdef  DEBUG
30 #define HANDLE_BLOCK_SIZE       1
31 #else
32 #define HANDLE_BLOCK_SIZE       256
33 #endif
34
35 #define HANDLE_HASH_TAB_INIT_SIZE       32
36
37 #define DEFAULT_MAX_INDEX_PLUS_ONE      0xfffffffful
38 #define DEFAULT_MAX_HANDLE              DEFAULT_MAX_INDEX_PLUS_ONE
39
40 #define INDEX_IS_VALID(psBase, i) ((i) < (psBase)->ui32TotalHandCount)
41
42 #define INDEX_TO_HANDLE(psBase, idx) ((IMG_HANDLE)((idx) + 1))
43 #define HANDLE_TO_INDEX(psBase, hand) ((IMG_UINT32)(hand) - 1)
44
45 #define INDEX_TO_HANDLE_PTR(psBase, i) (((psBase)->psHandleArray) + (i))
46 #define HANDLE_TO_HANDLE_PTR(psBase, h) (INDEX_TO_HANDLE_PTR(psBase, HANDLE_TO_INDEX(psBase, h)))
47
48 #define HANDLE_PTR_TO_INDEX(psBase, psHandle) (IMG_UINT32)((psHandle) - ((psBase)->psHandleArray))
49 #define HANDLE_PTR_TO_HANDLE(psBase, psHandle) \
50         INDEX_TO_HANDLE(psBase, HANDLE_PTR_TO_INDEX(psBase, psHandle))
51
52 #define ROUND_UP_TO_MULTIPLE(a, b) ((((a) + (b) - 1) / (b)) * (b))
53
54 #define HANDLES_BATCHED(psBase) ((psBase)->ui32HandBatchSize != 0)
55
56 #define SET_FLAG(v, f) ((IMG_VOID)((v) |= (f)))
57 #define CLEAR_FLAG(v, f) ((IMG_VOID)((v) &= ~(f)))
58 #define TEST_FLAG(v, f) ((IMG_BOOL)(((v) & (f)) != 0))
59
60 #define TEST_ALLOC_FLAG(psHandle, f) TEST_FLAG((psHandle)->eFlag, f)
61
62 #define SET_INTERNAL_FLAG(psHandle, f) SET_FLAG((psHandle)->eInternalFlag, f)
63 #define CLEAR_INTERNAL_FLAG(psHandle, f) CLEAR_FLAG((psHandle)->eInternalFlag, f)
64 #define TEST_INTERNAL_FLAG(psHandle, f) TEST_FLAG((psHandle)->eInternalFlag, f)
65
66 #define BATCHED_HANDLE(psHandle) TEST_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED)
67
68 #define SET_BATCHED_HANDLE(psHandle) SET_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED)
69
70 #define SET_UNBATCHED_HANDLE(psHandle) CLEAR_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED)
71
72 #define BATCHED_HANDLE_PARTIALLY_FREE(psHandle) TEST_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE)
73
74 #define SET_BATCHED_HANDLE_PARTIALLY_FREE(psHandle) SET_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE)
75
76 #define HANDLE_STRUCT_IS_FREE(psHandle) ((psHandle)->eType == PVRSRV_HANDLE_TYPE_NONE && (psHandle)->eInternalFlag == INTERNAL_HANDLE_FLAG_NONE)
77
78 #ifdef  MIN
79 #undef MIN
80 #endif
81
82 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
83
84 struct sHandleList
85 {
86         IMG_UINT32 ui32Prev;
87         IMG_UINT32 ui32Next;
88         IMG_HANDLE hParent;
89 };
90
91 enum ePVRSRVInternalHandleFlag
92 {
93         INTERNAL_HANDLE_FLAG_NONE = 0x00,
94         INTERNAL_HANDLE_FLAG_BATCHED = 0x01,
95         INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE = 0x02,
96 };
97
98 struct sHandle
99 {
100
101         PVRSRV_HANDLE_TYPE eType;
102
103
104         IMG_VOID *pvData;
105
106
107         IMG_UINT32 ui32NextIndexPlusOne;
108
109
110         enum ePVRSRVInternalHandleFlag eInternalFlag;
111
112
113         PVRSRV_HANDLE_ALLOC_FLAG eFlag;
114
115
116         IMG_UINT32 ui32Index;
117
118
119         struct sHandleList sChildren;
120
121
122         struct sHandleList sSiblings;
123 };
124
125 struct _PVRSRV_HANDLE_BASE_
126 {
127
128         IMG_HANDLE hBaseBlockAlloc;
129
130
131         IMG_HANDLE hHandBlockAlloc;
132
133
134         struct sHandle *psHandleArray;
135
136
137         HASH_TABLE *psHashTab;
138
139
140         IMG_UINT32 ui32FreeHandCount;
141
142
143         IMG_UINT32 ui32FirstFreeIndex;
144
145
146         IMG_UINT32 ui32MaxIndexPlusOne;
147
148
149         IMG_UINT32 ui32TotalHandCount;
150
151
152         IMG_UINT32 ui32LastFreeIndexPlusOne;
153
154
155         IMG_UINT32 ui32HandBatchSize;
156
157
158         IMG_UINT32 ui32TotalHandCountPreBatch;
159
160
161         IMG_UINT32 ui32FirstBatchIndexPlusOne;
162
163
164         IMG_UINT32 ui32BatchHandAllocFailures;
165
166
167         IMG_BOOL bPurgingEnabled;
168 };
169
170 enum eHandKey {
171         HAND_KEY_DATA = 0,
172         HAND_KEY_TYPE,
173         HAND_KEY_PARENT,
174         HAND_KEY_LEN
175 };
176
177 PVRSRV_HANDLE_BASE *gpsKernelHandleBase = IMG_NULL;
178
179 typedef IMG_UINTPTR_T HAND_KEY[HAND_KEY_LEN];
180
181 #ifdef INLINE_IS_PRAGMA
182 #pragma inline(HandleListInit)
183 #endif
184 static INLINE
185 IMG_VOID HandleListInit(IMG_UINT32 ui32Index, struct sHandleList *psList, IMG_HANDLE hParent)
186 {
187         psList->ui32Next = ui32Index;
188         psList->ui32Prev = ui32Index;
189         psList->hParent = hParent;
190 }
191
192 #ifdef INLINE_IS_PRAGMA
193 #pragma inline(InitParentList)
194 #endif
195 static INLINE
196 IMG_VOID InitParentList(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHandle)
197 {
198         IMG_UINT32 ui32Parent = HANDLE_PTR_TO_INDEX(psBase, psHandle);
199
200         HandleListInit(ui32Parent, &psHandle->sChildren, INDEX_TO_HANDLE(psBase, ui32Parent));
201 }
202
203 #ifdef INLINE_IS_PRAGMA
204 #pragma inline(InitChildEntry)
205 #endif
206 static INLINE
207 IMG_VOID InitChildEntry(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHandle)
208 {
209         HandleListInit(HANDLE_PTR_TO_INDEX(psBase, psHandle), &psHandle->sSiblings, IMG_NULL);
210 }
211
212 #ifdef INLINE_IS_PRAGMA
213 #pragma inline(HandleListIsEmpty)
214 #endif
215 static INLINE
216 IMG_BOOL HandleListIsEmpty(IMG_UINT32 ui32Index, struct sHandleList *psList)
217 {
218         IMG_BOOL bIsEmpty;
219
220         bIsEmpty = (IMG_BOOL)(psList->ui32Next == ui32Index);
221
222 #ifdef  DEBUG
223         {
224                 IMG_BOOL bIsEmpty2;
225
226                 bIsEmpty2 = (IMG_BOOL)(psList->ui32Prev == ui32Index);
227                 PVR_ASSERT(bIsEmpty == bIsEmpty2);
228         }
229 #endif
230
231         return bIsEmpty;
232 }
233
234 #ifdef DEBUG
235 #ifdef INLINE_IS_PRAGMA
236 #pragma inline(NoChildren)
237 #endif
238 static INLINE
239 IMG_BOOL NoChildren(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHandle)
240 {
241         PVR_ASSERT(psHandle->sChildren.hParent == HANDLE_PTR_TO_HANDLE(psBase, psHandle));
242
243         return HandleListIsEmpty(HANDLE_PTR_TO_INDEX(psBase, psHandle), &psHandle->sChildren);
244 }
245
246 #ifdef INLINE_IS_PRAGMA
247 #pragma inline(NoParent)
248 #endif
249 static INLINE
250 IMG_BOOL NoParent(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHandle)
251 {
252         if (HandleListIsEmpty(HANDLE_PTR_TO_INDEX(psBase, psHandle), &psHandle->sSiblings))
253         {
254                 PVR_ASSERT(psHandle->sSiblings.hParent == IMG_NULL);
255
256                 return IMG_TRUE;
257         }
258         else
259         {
260                 PVR_ASSERT(psHandle->sSiblings.hParent != IMG_NULL);
261         }
262         return IMG_FALSE;
263 }
264 #endif
265 #ifdef INLINE_IS_PRAGMA
266 #pragma inline(ParentHandle)
267 #endif
268 static INLINE
269 IMG_HANDLE ParentHandle(struct sHandle *psHandle)
270 {
271         return psHandle->sSiblings.hParent;
272 }
273
274 #define LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, i, p, po, eo) \
275                 ((struct sHandleList *)((IMG_CHAR *)(INDEX_TO_HANDLE_PTR(psBase, i)) + (((i) == (p)) ? (po) : (eo))))
276
277 #ifdef INLINE_IS_PRAGMA
278 #pragma inline(HandleListInsertBefore)
279 #endif
280 static INLINE
281 IMG_VOID HandleListInsertBefore(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32InsIndex, struct sHandleList *psIns, IMG_SIZE_T uiParentOffset, IMG_UINT32 ui32EntryIndex, struct sHandleList *psEntry, IMG_SIZE_T uiEntryOffset, IMG_UINT32 ui32ParentIndex)
282 {
283
284         struct sHandleList *psPrevIns = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psIns->ui32Prev, ui32ParentIndex, uiParentOffset, uiEntryOffset);
285
286         PVR_ASSERT(psEntry->hParent == IMG_NULL);
287         PVR_ASSERT(ui32InsIndex == psPrevIns->ui32Next);
288         PVR_ASSERT(LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, ui32ParentIndex, ui32ParentIndex, uiParentOffset, uiParentOffset)->hParent == INDEX_TO_HANDLE(psBase, ui32ParentIndex));
289
290         psEntry->ui32Prev = psIns->ui32Prev;
291         psIns->ui32Prev = ui32EntryIndex;
292         psEntry->ui32Next = ui32InsIndex;
293         psPrevIns->ui32Next = ui32EntryIndex;
294
295         psEntry->hParent = INDEX_TO_HANDLE(psBase, ui32ParentIndex);
296 }
297
298 #ifdef INLINE_IS_PRAGMA
299 #pragma inline(AdoptChild)
300 #endif
301 static INLINE
302 IMG_VOID AdoptChild(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psParent, struct sHandle *psChild)
303 {
304         IMG_UINT32 ui32Parent = HANDLE_TO_INDEX(psBase, psParent->sChildren.hParent);
305
306         PVR_ASSERT(ui32Parent == HANDLE_PTR_TO_INDEX(psBase, psParent));
307
308         HandleListInsertBefore(psBase, ui32Parent, &psParent->sChildren, offsetof(struct sHandle, sChildren), HANDLE_PTR_TO_INDEX(psBase, psChild), &psChild->sSiblings, offsetof(struct sHandle, sSiblings), ui32Parent);
309
310 }
311
312 #ifdef INLINE_IS_PRAGMA
313 #pragma inline(HandleListRemove)
314 #endif
315 static INLINE
316 IMG_VOID HandleListRemove(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32EntryIndex, struct sHandleList *psEntry, IMG_SIZE_T uiEntryOffset, IMG_SIZE_T uiParentOffset)
317 {
318         if (!HandleListIsEmpty(ui32EntryIndex, psEntry))
319         {
320
321                 struct sHandleList *psPrev = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psEntry->ui32Prev, HANDLE_TO_INDEX(psBase, psEntry->hParent), uiParentOffset, uiEntryOffset);
322                 struct sHandleList *psNext = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psEntry->ui32Next, HANDLE_TO_INDEX(psBase, psEntry->hParent), uiParentOffset, uiEntryOffset);
323
324
325                 PVR_ASSERT(psEntry->hParent != IMG_NULL);
326
327                 psPrev->ui32Next = psEntry->ui32Next;
328                 psNext->ui32Prev = psEntry->ui32Prev;
329
330                 HandleListInit(ui32EntryIndex, psEntry, IMG_NULL);
331         }
332 }
333
334 #ifdef INLINE_IS_PRAGMA
335 #pragma inline(UnlinkFromParent)
336 #endif
337 static INLINE
338 IMG_VOID UnlinkFromParent(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHandle)
339 {
340         HandleListRemove(psBase, HANDLE_PTR_TO_INDEX(psBase, psHandle), &psHandle->sSiblings, offsetof(struct sHandle, sSiblings), offsetof(struct sHandle, sChildren));
341 }
342
343 #ifdef INLINE_IS_PRAGMA
344 #pragma inline(HandleListIterate)
345 #endif
346 static INLINE
347 PVRSRV_ERROR HandleListIterate(PVRSRV_HANDLE_BASE *psBase, struct sHandleList *psHead, IMG_SIZE_T uiParentOffset, IMG_SIZE_T uiEntryOffset, PVRSRV_ERROR (*pfnIterFunc)(PVRSRV_HANDLE_BASE *, struct sHandle *))
348 {
349         IMG_UINT32 ui32Index;
350         IMG_UINT32 ui32Parent = HANDLE_TO_INDEX(psBase, psHead->hParent);
351
352         PVR_ASSERT(psHead->hParent != IMG_NULL);
353
354
355         for(ui32Index = psHead->ui32Next; ui32Index != ui32Parent; )
356         {
357                 struct sHandle *psHandle = INDEX_TO_HANDLE_PTR(psBase, ui32Index);
358
359                 struct sHandleList *psEntry = LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, ui32Index, ui32Parent, uiParentOffset, uiEntryOffset);
360                 PVRSRV_ERROR eError;
361
362                 PVR_ASSERT(psEntry->hParent == psHead->hParent);
363
364                 ui32Index = psEntry->ui32Next;
365
366                 eError = (*pfnIterFunc)(psBase, psHandle);
367                 if (eError != PVRSRV_OK)
368                 {
369                         return eError;
370                 }
371         }
372
373         return PVRSRV_OK;
374 }
375
376 #ifdef INLINE_IS_PRAGMA
377 #pragma inline(IterateOverChildren)
378 #endif
379 static INLINE
380 PVRSRV_ERROR IterateOverChildren(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psParent, PVRSRV_ERROR (*pfnIterFunc)(PVRSRV_HANDLE_BASE *, struct sHandle *))
381 {
382          return HandleListIterate(psBase, &psParent->sChildren, offsetof(struct sHandle, sChildren), offsetof(struct sHandle, sSiblings), pfnIterFunc);
383 }
384
385 #ifdef INLINE_IS_PRAGMA
386 #pragma inline(GetHandleStructure)
387 #endif
388 static INLINE
389 PVRSRV_ERROR GetHandleStructure(PVRSRV_HANDLE_BASE *psBase, struct sHandle **ppsHandle, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType)
390 {
391         IMG_UINT32 ui32Index = HANDLE_TO_INDEX(psBase, hHandle);
392         struct sHandle *psHandle;
393
394
395         if (!INDEX_IS_VALID(psBase, ui32Index))
396         {
397                 PVR_DPF((PVR_DBG_ERROR, "GetHandleStructure: Handle index out of range (%u >= %u)", ui32Index, psBase->ui32TotalHandCount));
398                 return PVRSRV_ERROR_GENERIC;
399         }
400
401         psHandle =  INDEX_TO_HANDLE_PTR(psBase, ui32Index);
402         if (psHandle->eType == PVRSRV_HANDLE_TYPE_NONE)
403         {
404                 PVR_DPF((PVR_DBG_ERROR, "GetHandleStructure: Handle not allocated (index: %u)", ui32Index));
405                 return PVRSRV_ERROR_GENERIC;
406         }
407
408
409         if (eType != PVRSRV_HANDLE_TYPE_NONE && eType != psHandle->eType)
410         {
411                 PVR_DPF((PVR_DBG_ERROR, "GetHandleStructure: Handle type mismatch (%d != %d)", eType, psHandle->eType));
412                 return PVRSRV_ERROR_GENERIC;
413         }
414
415
416         *ppsHandle = psHandle;
417
418         return PVRSRV_OK;
419 }
420
421 #ifdef INLINE_IS_PRAGMA
422 #pragma inline(ParentIfPrivate)
423 #endif
424 static INLINE
425 IMG_HANDLE ParentIfPrivate(struct sHandle *psHandle)
426 {
427         return TEST_ALLOC_FLAG(psHandle, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ?
428                         ParentHandle(psHandle) : IMG_NULL;
429 }
430
431 #ifdef INLINE_IS_PRAGMA
432 #pragma inline(InitKey)
433 #endif
434 static INLINE
435 IMG_VOID InitKey(HAND_KEY aKey, PVRSRV_HANDLE_BASE *psBase, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, IMG_HANDLE hParent)
436 {
437         PVR_UNREFERENCED_PARAMETER(psBase);
438
439         aKey[HAND_KEY_DATA] = (IMG_UINTPTR_T)pvData;
440         aKey[HAND_KEY_TYPE] = (IMG_UINTPTR_T)eType;
441         aKey[HAND_KEY_PARENT] = (IMG_UINTPTR_T)hParent;
442 }
443
444 static PVRSRV_ERROR FreeHandleArray(PVRSRV_HANDLE_BASE *psBase)
445 {
446         PVRSRV_ERROR eError = PVRSRV_OK;
447
448         if (psBase->psHandleArray != IMG_NULL)
449         {
450                 eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
451                         psBase->ui32TotalHandCount * sizeof(struct sHandle),
452                         psBase->psHandleArray,
453                         psBase->hHandBlockAlloc);
454
455                 if (eError != PVRSRV_OK)
456                 {
457                         PVR_DPF((PVR_DBG_ERROR, "FreeHandleArray: Error freeing memory (%d)", eError));
458                 }
459                 else
460                 {
461                         psBase->psHandleArray = IMG_NULL;
462                 }
463         }
464
465         return eError;
466 }
467
468 static PVRSRV_ERROR FreeHandle(PVRSRV_HANDLE_BASE *psBase, struct sHandle *psHandle)
469 {
470         HAND_KEY aKey;
471         IMG_UINT32 ui32Index = HANDLE_PTR_TO_INDEX(psBase, psHandle);
472         PVRSRV_ERROR eError;
473
474
475         InitKey(aKey, psBase, psHandle->pvData, psHandle->eType, ParentIfPrivate(psHandle));
476
477         if (!TEST_ALLOC_FLAG(psHandle, PVRSRV_HANDLE_ALLOC_FLAG_MULTI) && !BATCHED_HANDLE_PARTIALLY_FREE(psHandle))
478         {
479                 IMG_HANDLE hHandle;
480                 hHandle = (IMG_HANDLE) HASH_Remove_Extended(psBase->psHashTab, aKey);
481
482                 PVR_ASSERT(hHandle != IMG_NULL);
483                 PVR_ASSERT(hHandle == INDEX_TO_HANDLE(psBase, ui32Index));
484                 PVR_UNREFERENCED_PARAMETER(hHandle);
485         }
486
487
488         UnlinkFromParent(psBase, psHandle);
489
490
491         eError = IterateOverChildren(psBase, psHandle, FreeHandle);
492         if (eError != PVRSRV_OK)
493         {
494                 PVR_DPF((PVR_DBG_ERROR, "FreeHandle: Error whilst freeing subhandles (%d)", eError));
495                 return eError;
496         }
497
498
499         psHandle->eType = PVRSRV_HANDLE_TYPE_NONE;
500
501         if (BATCHED_HANDLE(psHandle) && !BATCHED_HANDLE_PARTIALLY_FREE(psHandle))
502         {
503
504                 SET_BATCHED_HANDLE_PARTIALLY_FREE(psHandle);
505
506                 return PVRSRV_OK;
507         }
508
509
510         if (!psBase->bPurgingEnabled)
511         {
512                 if (psBase->ui32FreeHandCount == 0)
513                 {
514                         PVR_ASSERT(psBase->ui32FirstFreeIndex == 0);
515                         PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0);
516
517                         psBase->ui32FirstFreeIndex =  ui32Index;
518                 }
519                 else
520                 {
521
522                         PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0);
523                         PVR_ASSERT(INDEX_TO_HANDLE_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne == 0);
524                         INDEX_TO_HANDLE_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne =  ui32Index + 1;
525                 }
526
527                 PVR_ASSERT(psHandle->ui32NextIndexPlusOne == 0);
528
529
530                 psBase->ui32LastFreeIndexPlusOne = ui32Index + 1;
531         }
532
533         psBase->ui32FreeHandCount++;
534
535         return PVRSRV_OK;
536 }
537
538 static PVRSRV_ERROR FreeAllHandles(PVRSRV_HANDLE_BASE *psBase)
539 {
540         IMG_UINT32 i;
541         PVRSRV_ERROR eError = PVRSRV_OK;
542
543         if (psBase->ui32FreeHandCount == psBase->ui32TotalHandCount)
544         {
545                 return eError;
546         }
547
548         for (i = 0; i < psBase->ui32TotalHandCount; i++)
549         {
550                 struct sHandle *psHandle;
551
552                 psHandle = INDEX_TO_HANDLE_PTR(psBase, i);
553
554                 if (psHandle->eType != PVRSRV_HANDLE_TYPE_NONE)
555                 {
556                         eError = FreeHandle(psBase, psHandle);
557                         if (eError != PVRSRV_OK)
558                         {
559                                 PVR_DPF((PVR_DBG_ERROR, "FreeAllHandles: FreeHandle failed (%d)", eError));
560                                 break;
561                         }
562
563
564                         if (psBase->ui32FreeHandCount == psBase->ui32TotalHandCount)
565                         {
566                                 break;
567                         }
568                 }
569         }
570
571         return eError;
572 }
573
574 static PVRSRV_ERROR FreeHandleBase(PVRSRV_HANDLE_BASE *psBase)
575 {
576         PVRSRV_ERROR eError;
577
578         if (HANDLES_BATCHED(psBase))
579         {
580                 PVR_DPF((PVR_DBG_WARNING, "FreeHandleBase: Uncommitted/Unreleased handle batch"));
581                 PVRSRVReleaseHandleBatch(psBase);
582         }
583
584
585         eError = FreeAllHandles(psBase);
586         if (eError != PVRSRV_OK)
587         {
588                 PVR_DPF((PVR_DBG_ERROR, "FreeHandleBase: Couldn't free handles (%d)", eError));
589                 return eError;
590         }
591
592
593         eError = FreeHandleArray(psBase);
594         if (eError != PVRSRV_OK)
595         {
596                 PVR_DPF((PVR_DBG_ERROR, "FreeHandleBase: Couldn't free handle array (%d)", eError));
597                 return eError;
598         }
599
600         if (psBase->psHashTab != IMG_NULL)
601         {
602
603                 HASH_Delete(psBase->psHashTab);
604         }
605
606         eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
607                 sizeof(*psBase),
608                 psBase,
609                 psBase->hBaseBlockAlloc);
610         if (eError != PVRSRV_OK)
611         {
612                 PVR_DPF((PVR_DBG_ERROR, "FreeHandleBase: Couldn't free handle base (%d)", eError));
613                 return eError;
614         }
615
616         return PVRSRV_OK;
617 }
618
619 #ifdef INLINE_IS_PRAGMA
620 #pragma inline(FindHandle)
621 #endif
622 static INLINE
623 IMG_HANDLE FindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, IMG_HANDLE hParent)
624 {
625         HAND_KEY aKey;
626
627         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
628
629         InitKey(aKey, psBase, pvData, eType, hParent);
630
631         return (IMG_HANDLE) HASH_Retrieve_Extended(psBase->psHashTab, aKey);
632 }
633
634 static PVRSRV_ERROR ReallocMem(IMG_PVOID *ppvMem, IMG_HANDLE *phBlockAlloc, IMG_UINT32 ui32NewSize, IMG_UINT32 ui32OldSize)
635 {
636         IMG_VOID *pvOldMem = *ppvMem;
637         IMG_HANDLE hOldBlockAlloc = *phBlockAlloc;
638         IMG_UINT32 ui32CopySize = MIN(ui32NewSize, ui32OldSize);
639         IMG_VOID *pvNewMem = IMG_NULL;
640         IMG_HANDLE hNewBlockAlloc = IMG_NULL;
641         PVRSRV_ERROR eError;
642
643         if (ui32NewSize == ui32OldSize)
644         {
645                 return (PVRSRV_OK);
646         }
647
648         if (ui32NewSize != 0)
649         {
650
651                 eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
652                         ui32NewSize,
653                         &pvNewMem,
654                         &hNewBlockAlloc,
655                         "Memory Area");
656                 if (eError != PVRSRV_OK)
657                 {
658                         PVR_DPF((PVR_DBG_ERROR, "ReallocMem: Couldn't allocate new memory area (%d)", eError));
659                         return eError;
660                 }
661         }
662
663         if (ui32CopySize != 0)
664         {
665
666                 OSMemCopy(pvNewMem, pvOldMem, ui32CopySize);
667         }
668
669         if (ui32OldSize != 0)
670         {
671
672                 eError = OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
673                                 ui32OldSize,
674                                 pvOldMem,
675                                 hOldBlockAlloc);
676                 if (eError != PVRSRV_OK)
677                 {
678                         PVR_DPF((PVR_DBG_ERROR, "ReallocMem: Couldn't free old memory area (%d)", eError));
679                 }
680         }
681
682         *ppvMem = pvNewMem;
683         *phBlockAlloc = hNewBlockAlloc;
684
685         return PVRSRV_OK;
686 }
687
688 #ifdef INLINE_IS_PRAGMA
689 #pragma inline(ReallocHandleArray)
690 #endif
691 static INLINE
692 PVRSRV_ERROR ReallocHandleArray(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32NewCount, IMG_UINT32 ui32OldCount)
693 {
694         return ReallocMem((IMG_PVOID *)&psBase->psHandleArray,
695                                 &psBase->hHandBlockAlloc,
696                                 ui32NewCount * sizeof(struct sHandle),
697                                 ui32OldCount * sizeof(struct sHandle));
698 }
699
700 static PVRSRV_ERROR IncreaseHandleArraySize(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32Delta)
701 {
702         PVRSRV_ERROR eError;
703         struct sHandle *psHandle;
704         IMG_UINT32 ui32DeltaAdjusted = ROUND_UP_TO_MULTIPLE(ui32Delta, HANDLE_BLOCK_SIZE);
705         IMG_UINT32 ui32NewTotalHandCount = psBase->ui32TotalHandCount + ui32DeltaAdjusted;
706 ;
707
708         PVR_ASSERT(ui32Delta != 0);
709
710
711         if (ui32NewTotalHandCount > psBase->ui32MaxIndexPlusOne || ui32NewTotalHandCount <= psBase->ui32TotalHandCount)
712         {
713                 ui32NewTotalHandCount = psBase->ui32MaxIndexPlusOne;
714
715                 ui32DeltaAdjusted = ui32NewTotalHandCount - psBase->ui32TotalHandCount;
716
717                 if (ui32DeltaAdjusted < ui32Delta)
718                 {
719                         PVR_DPF((PVR_DBG_ERROR, "IncreaseHandleArraySize: Maximum handle limit reached (%d)", psBase->ui32MaxIndexPlusOne));
720                         return PVRSRV_ERROR_OUT_OF_MEMORY;
721                 }
722         }
723
724         PVR_ASSERT(ui32DeltaAdjusted >= ui32Delta);
725
726
727         eError = ReallocHandleArray(psBase, ui32NewTotalHandCount, psBase->ui32TotalHandCount);
728         if (eError != PVRSRV_OK)
729         {
730                 PVR_DPF((PVR_DBG_ERROR, "IncreaseHandleArraySize: ReallocHandleArray failed (%d)", eError));
731                 return eError;
732         }
733
734
735         for(psHandle = psBase->psHandleArray + psBase->ui32TotalHandCount;
736                 psHandle < psBase->psHandleArray + ui32NewTotalHandCount;
737                 psHandle++)
738         {
739                 psHandle->eType = PVRSRV_HANDLE_TYPE_NONE;
740                 psHandle->eInternalFlag = INTERNAL_HANDLE_FLAG_NONE;
741                 psHandle->ui32NextIndexPlusOne  = 0;
742         }
743
744
745         psBase->ui32FreeHandCount += ui32DeltaAdjusted;
746
747         if (psBase->ui32FirstFreeIndex == 0)
748         {
749                 PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0);
750
751                 psBase->ui32FirstFreeIndex = psBase->ui32TotalHandCount;
752         }
753         else
754         {
755                 if (!psBase->bPurgingEnabled)
756                 {
757                         PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0)
758                         PVR_ASSERT(INDEX_TO_HANDLE_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne == 0);
759
760                         INDEX_TO_HANDLE_PTR(psBase, psBase->ui32LastFreeIndexPlusOne - 1)->ui32NextIndexPlusOne = psBase->ui32TotalHandCount + 1;
761                 }
762         }
763
764         if (!psBase->bPurgingEnabled)
765         {
766                 psBase->ui32LastFreeIndexPlusOne = ui32NewTotalHandCount;
767         }
768
769         psBase->ui32TotalHandCount = ui32NewTotalHandCount;
770
771         return PVRSRV_OK;
772 }
773
774 static PVRSRV_ERROR EnsureFreeHandles(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32Free)
775 {
776         PVRSRV_ERROR eError;
777
778         if (ui32Free > psBase->ui32FreeHandCount)
779         {
780                 IMG_UINT32 ui32FreeHandDelta = ui32Free - psBase->ui32FreeHandCount;
781                 eError = IncreaseHandleArraySize(psBase, ui32FreeHandDelta);
782                 if (eError != PVRSRV_OK)
783                 {
784                         PVR_DPF((PVR_DBG_ERROR, "EnsureFreeHandles: Couldn't allocate %u handles to ensure %u free handles (IncreaseHandleArraySize failed with error %d)", ui32FreeHandDelta, ui32Free, eError));
785
786                         return eError;
787                 }
788         }
789
790         return PVRSRV_OK;
791 }
792
793 static PVRSRV_ERROR AllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag, IMG_HANDLE hParent)
794 {
795         IMG_UINT32 ui32NewIndex;
796         struct sHandle *psNewHandle = IMG_NULL;
797         IMG_HANDLE hHandle;
798         HAND_KEY aKey;
799         PVRSRV_ERROR eError;
800
801
802         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
803
804         PVR_ASSERT(psBase->psHashTab != IMG_NULL);
805
806         if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI))
807         {
808
809                 PVR_ASSERT(FindHandle(psBase, pvData, eType, hParent) == IMG_NULL);
810         }
811
812         if (psBase->ui32FreeHandCount == 0 && HANDLES_BATCHED(psBase))
813         {
814                  PVR_DPF((PVR_DBG_WARNING, "AllocHandle: Handle batch size (%u) was too small, allocating additional space", psBase->ui32HandBatchSize));
815         }
816
817
818         eError = EnsureFreeHandles(psBase, 1);
819         if (eError != PVRSRV_OK)
820         {
821                 PVR_DPF((PVR_DBG_ERROR, "AllocHandle: EnsureFreeHandles failed (%d)", eError));
822                 return eError;
823         }
824         PVR_ASSERT(psBase->ui32FreeHandCount != 0)
825
826         if (!psBase->bPurgingEnabled)
827         {
828
829                 ui32NewIndex = psBase->ui32FirstFreeIndex;
830
831
832                 psNewHandle = INDEX_TO_HANDLE_PTR(psBase, ui32NewIndex);
833         }
834         else
835         {
836
837                 for(ui32NewIndex = psBase->ui32FirstFreeIndex; ui32NewIndex < psBase->ui32TotalHandCount; ui32NewIndex++)
838                 {
839                         psNewHandle = INDEX_TO_HANDLE_PTR(psBase, ui32NewIndex);
840                         if (HANDLE_STRUCT_IS_FREE(psNewHandle))
841                         {
842                                 break;
843                         }
844
845                 }
846                 psBase->ui32FirstFreeIndex = 0;
847                 PVR_ASSERT(ui32NewIndex < psBase->ui32TotalHandCount);
848         }
849         PVR_ASSERT(psNewHandle != IMG_NULL);
850
851
852         hHandle = INDEX_TO_HANDLE(psBase, ui32NewIndex);
853
854
855         if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI))
856         {
857
858                 InitKey(aKey, psBase, pvData, eType, hParent);
859
860
861                 if (!HASH_Insert_Extended(psBase->psHashTab, aKey, (IMG_UINTPTR_T)hHandle))
862                 {
863                         PVR_DPF((PVR_DBG_ERROR, "AllocHandle: Couldn't add handle to hash table"));
864
865                         return PVRSRV_ERROR_GENERIC;
866                 }
867         }
868
869         psBase->ui32FreeHandCount--;
870
871
872         if (!psBase->bPurgingEnabled)
873         {
874
875                 if (psBase->ui32FreeHandCount == 0)
876                 {
877                         PVR_ASSERT(psBase->ui32FirstFreeIndex == ui32NewIndex);
878                         PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == (ui32NewIndex + 1));
879
880                         psBase->ui32LastFreeIndexPlusOne = 0;
881                         psBase->ui32FirstFreeIndex = 0;
882                 }
883                 else
884                 {
885
886                         psBase->ui32FirstFreeIndex = (psNewHandle->ui32NextIndexPlusOne == 0) ?
887                                 ui32NewIndex + 1 :
888                                 psNewHandle->ui32NextIndexPlusOne - 1;
889                 }
890         }
891
892
893         psNewHandle->eType = eType;
894         psNewHandle->pvData = pvData;
895         psNewHandle->eInternalFlag = INTERNAL_HANDLE_FLAG_NONE;
896         psNewHandle->eFlag = eFlag;
897         psNewHandle->ui32Index = ui32NewIndex;
898
899         InitParentList(psBase, psNewHandle);
900 #if defined(DEBUG)
901         PVR_ASSERT(NoChildren(psBase, psNewHandle));
902 #endif
903
904         InitChildEntry(psBase, psNewHandle);
905 #if defined(DEBUG)
906         PVR_ASSERT(NoParent(psBase, psNewHandle));
907 #endif
908
909         if (HANDLES_BATCHED(psBase))
910         {
911
912                 psNewHandle->ui32NextIndexPlusOne = psBase->ui32FirstBatchIndexPlusOne;
913
914                 psBase->ui32FirstBatchIndexPlusOne = ui32NewIndex + 1;
915
916
917                 SET_BATCHED_HANDLE(psNewHandle);
918         }
919         else
920         {
921                 psNewHandle->ui32NextIndexPlusOne = 0;
922         }
923
924
925         *phHandle = hHandle;
926
927         return PVRSRV_OK;
928 }
929
930 PVRSRV_ERROR PVRSRVAllocHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag)
931 {
932         IMG_HANDLE hHandle;
933         PVRSRV_ERROR eError;
934
935         *phHandle = IMG_NULL;
936
937         if (HANDLES_BATCHED(psBase))
938         {
939
940                 psBase->ui32BatchHandAllocFailures++;
941         }
942
943
944         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
945
946         if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI))
947         {
948
949                 hHandle = FindHandle(psBase, pvData, eType, IMG_NULL);
950                 if (hHandle != IMG_NULL)
951                 {
952                         struct sHandle *psHandle;
953
954                         eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
955                         if (eError != PVRSRV_OK)
956                         {
957                                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandle: Lookup of existing handle failed"));
958                                 return eError;
959                         }
960
961
962                         if (TEST_FLAG(psHandle->eFlag & eFlag, PVRSRV_HANDLE_ALLOC_FLAG_SHARED))
963                         {
964                                 *phHandle = hHandle;
965                                 eError = PVRSRV_OK;
966                                 goto exit_ok;
967                         }
968                         return PVRSRV_ERROR_GENERIC;
969                 }
970         }
971
972         eError = AllocHandle(psBase, phHandle, pvData, eType, eFlag, IMG_NULL);
973
974 exit_ok:
975         if (HANDLES_BATCHED(psBase) && (eError == PVRSRV_OK))
976         {
977                 psBase->ui32BatchHandAllocFailures--;
978         }
979
980         return eError;
981 }
982
983 PVRSRV_ERROR PVRSRVAllocSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType, PVRSRV_HANDLE_ALLOC_FLAG eFlag, IMG_HANDLE hParent)
984 {
985         struct sHandle *psPHand;
986         struct sHandle *psCHand;
987         PVRSRV_ERROR eError;
988         IMG_HANDLE hParentKey;
989         IMG_HANDLE hHandle;
990
991         *phHandle = IMG_NULL;
992
993         if (HANDLES_BATCHED(psBase))
994         {
995
996                 psBase->ui32BatchHandAllocFailures++;
997         }
998
999
1000         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1001
1002         hParentKey = TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ?
1003                         hParent : IMG_NULL;
1004
1005
1006         eError = GetHandleStructure(psBase, &psPHand, hParent, PVRSRV_HANDLE_TYPE_NONE);
1007         if (eError != PVRSRV_OK)
1008         {
1009                 return PVRSRV_ERROR_GENERIC;
1010         }
1011
1012         if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI))
1013         {
1014
1015                 hHandle = FindHandle(psBase, pvData, eType, hParentKey);
1016                 if (hHandle != IMG_NULL)
1017                 {
1018                         struct sHandle *psCHandle;
1019                         PVRSRV_ERROR eErr;
1020
1021                         eErr = GetHandleStructure(psBase, &psCHandle, hHandle, eType);
1022                         if (eErr != PVRSRV_OK)
1023                         {
1024                                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocSubHandle: Lookup of existing handle failed"));
1025                                 return eErr;
1026                         }
1027
1028                         PVR_ASSERT(hParentKey != IMG_NULL && ParentHandle(HANDLE_TO_HANDLE_PTR(psBase, hHandle)) == hParent);
1029
1030
1031                         if (TEST_FLAG(psCHandle->eFlag & eFlag, PVRSRV_HANDLE_ALLOC_FLAG_SHARED) && ParentHandle(HANDLE_TO_HANDLE_PTR(psBase, hHandle)) == hParent)
1032                         {
1033                                 *phHandle = hHandle;
1034                                 goto exit_ok;
1035                         }
1036                         return PVRSRV_ERROR_GENERIC;
1037                 }
1038         }
1039
1040         eError = AllocHandle(psBase, &hHandle, pvData, eType, eFlag, hParentKey);
1041         if (eError != PVRSRV_OK)
1042         {
1043                 return eError;
1044         }
1045
1046
1047         psPHand = HANDLE_TO_HANDLE_PTR(psBase, hParent);
1048
1049         psCHand = HANDLE_TO_HANDLE_PTR(psBase, hHandle);
1050
1051         AdoptChild(psBase, psPHand, psCHand);
1052
1053         *phHandle = hHandle;
1054
1055 exit_ok:
1056         if (HANDLES_BATCHED(psBase))
1057         {
1058                 psBase->ui32BatchHandAllocFailures--;
1059         }
1060
1061         return PVRSRV_OK;
1062 }
1063
1064 PVRSRV_ERROR PVRSRVFindHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE *phHandle, IMG_VOID *pvData, PVRSRV_HANDLE_TYPE eType)
1065 {
1066         IMG_HANDLE hHandle;
1067
1068         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1069
1070
1071         hHandle = (IMG_HANDLE) FindHandle(psBase, pvData, eType, IMG_NULL);
1072         if (hHandle == IMG_NULL)
1073         {
1074                 return PVRSRV_ERROR_GENERIC;
1075         }
1076
1077         *phHandle = hHandle;
1078
1079         return PVRSRV_OK;
1080 }
1081
1082 PVRSRV_ERROR PVRSRVLookupHandleAnyType(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, PVRSRV_HANDLE_TYPE *peType, IMG_HANDLE hHandle)
1083 {
1084         struct sHandle *psHandle;
1085         PVRSRV_ERROR eError;
1086
1087         eError = GetHandleStructure(psBase, &psHandle, hHandle, PVRSRV_HANDLE_TYPE_NONE);
1088         if (eError != PVRSRV_OK)
1089         {
1090                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupHandleAnyType: Error looking up handle (%d)", eError));
1091                 return eError;
1092         }
1093
1094         *ppvData = psHandle->pvData;
1095         *peType = psHandle->eType;
1096
1097         return PVRSRV_OK;
1098 }
1099
1100 PVRSRV_ERROR PVRSRVLookupHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType)
1101 {
1102         struct sHandle *psHandle;
1103         PVRSRV_ERROR eError;
1104
1105         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1106
1107         eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
1108         if (eError != PVRSRV_OK)
1109         {
1110                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupHandle: Error looking up handle (%d)", eError));
1111                 return eError;
1112         }
1113
1114         *ppvData = psHandle->pvData;
1115
1116         return PVRSRV_OK;
1117 }
1118
1119 PVRSRV_ERROR PVRSRVLookupSubHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType, IMG_HANDLE hAncestor)
1120 {
1121         struct sHandle *psPHand;
1122         struct sHandle *psCHand;
1123         PVRSRV_ERROR eError;
1124
1125         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1126
1127         eError = GetHandleStructure(psBase, &psCHand, hHandle, eType);
1128         if (eError != PVRSRV_OK)
1129         {
1130                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupSubHandle: Error looking up subhandle (%d)", eError));
1131                 return eError;
1132         }
1133
1134
1135         for (psPHand = psCHand; ParentHandle(psPHand) != hAncestor; )
1136         {
1137                 eError = GetHandleStructure(psBase, &psPHand, ParentHandle(psPHand), PVRSRV_HANDLE_TYPE_NONE);
1138                 if (eError != PVRSRV_OK)
1139                 {
1140                         PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupSubHandle: Subhandle doesn't belong to given ancestor"));
1141                         return PVRSRV_ERROR_GENERIC;
1142                 }
1143         }
1144
1145         *ppvData = psCHand->pvData;
1146
1147         return PVRSRV_OK;
1148 }
1149
1150 PVRSRV_ERROR PVRSRVGetParentHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *phParent, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType)
1151 {
1152         struct sHandle *psHandle;
1153         PVRSRV_ERROR eError;
1154
1155         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1156
1157         eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
1158         if (eError != PVRSRV_OK)
1159         {
1160                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetParentHandle: Error looking up subhandle (%d)", eError));
1161                 return eError;
1162         }
1163
1164         *phParent = ParentHandle(psHandle);
1165
1166         return PVRSRV_OK;
1167 }
1168
1169 PVRSRV_ERROR PVRSRVLookupAndReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_PVOID *ppvData, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType)
1170 {
1171         struct sHandle *psHandle;
1172         PVRSRV_ERROR eError;
1173
1174         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1175
1176         eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
1177         if (eError != PVRSRV_OK)
1178         {
1179                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVLookupAndReleaseHandle: Error looking up handle (%d)", eError));
1180                 return eError;
1181         }
1182
1183         *ppvData = psHandle->pvData;
1184
1185         eError = FreeHandle(psBase, psHandle);
1186
1187         return eError;
1188 }
1189
1190 PVRSRV_ERROR PVRSRVReleaseHandle(PVRSRV_HANDLE_BASE *psBase, IMG_HANDLE hHandle, PVRSRV_HANDLE_TYPE eType)
1191 {
1192         struct sHandle *psHandle;
1193         PVRSRV_ERROR eError;
1194
1195         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1196
1197         eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
1198         if (eError != PVRSRV_OK)
1199         {
1200                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVReleaseHandle: Error looking up handle (%d)", eError));
1201                 return eError;
1202         }
1203
1204         eError = FreeHandle(psBase, psHandle);
1205
1206         return eError;
1207 }
1208
1209 PVRSRV_ERROR PVRSRVNewHandleBatch(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32BatchSize)
1210 {
1211         PVRSRV_ERROR eError;
1212
1213         if (HANDLES_BATCHED(psBase))
1214         {
1215                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVNewHandleBatch: There is a handle batch already in use (size %u)", psBase->ui32HandBatchSize));
1216                 return  PVRSRV_ERROR_GENERIC;
1217         }
1218
1219         if (ui32BatchSize == 0)
1220         {
1221                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVNewHandleBatch: Invalid batch size (%u)", ui32BatchSize));
1222                 return  PVRSRV_ERROR_INVALID_PARAMS;
1223         }
1224
1225         eError = EnsureFreeHandles(psBase, ui32BatchSize);
1226         if (eError != PVRSRV_OK)
1227         {
1228                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVNewHandleBatch: EnsureFreeHandles failed (error %d)", eError));
1229                 return eError;
1230         }
1231
1232         psBase->ui32HandBatchSize = ui32BatchSize;
1233
1234
1235         psBase->ui32TotalHandCountPreBatch = psBase->ui32TotalHandCount;
1236
1237         PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0);
1238
1239         PVR_ASSERT(psBase->ui32FirstBatchIndexPlusOne == 0);
1240
1241         PVR_ASSERT(HANDLES_BATCHED(psBase));
1242
1243         return PVRSRV_OK;
1244 }
1245
1246 static PVRSRV_ERROR PVRSRVHandleBatchCommitOrRelease(PVRSRV_HANDLE_BASE *psBase, IMG_BOOL bCommit)
1247 {
1248
1249         IMG_UINT32 ui32IndexPlusOne;
1250         IMG_BOOL bCommitBatch = bCommit;
1251
1252         if (!HANDLES_BATCHED(psBase))
1253         {
1254                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleBatchCommitOrRelease: There is no handle batch"));
1255                 return PVRSRV_ERROR_INVALID_PARAMS;
1256
1257         }
1258
1259         if (psBase->ui32BatchHandAllocFailures != 0)
1260         {
1261                 if (bCommit)
1262                 {
1263                         PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleBatchCommitOrRelease: Attempting to commit batch with handle allocation failures."));
1264                 }
1265                 bCommitBatch = IMG_FALSE;
1266         }
1267
1268         PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0 || !bCommit);
1269
1270         ui32IndexPlusOne = psBase->ui32FirstBatchIndexPlusOne;
1271         while(ui32IndexPlusOne != 0)
1272         {
1273                 struct sHandle *psHandle = INDEX_TO_HANDLE_PTR(psBase, ui32IndexPlusOne - 1);
1274                 IMG_UINT32 ui32NextIndexPlusOne = psHandle->ui32NextIndexPlusOne;
1275                 PVR_ASSERT(BATCHED_HANDLE(psHandle));
1276
1277                 psHandle->ui32NextIndexPlusOne = 0;
1278
1279                 if (!bCommitBatch || BATCHED_HANDLE_PARTIALLY_FREE(psHandle))
1280                 {
1281                         PVRSRV_ERROR eError;
1282
1283
1284                         if (!BATCHED_HANDLE_PARTIALLY_FREE(psHandle))
1285                         {
1286                                 SET_UNBATCHED_HANDLE(psHandle);
1287                         }
1288
1289                         eError = FreeHandle(psBase, psHandle);
1290                         if (eError != PVRSRV_OK)
1291                         {
1292                                  PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleBatchCommitOrRelease: Error freeing handle (%d)", eError));
1293                         }
1294                         PVR_ASSERT(eError == PVRSRV_OK);
1295                 }
1296                 else
1297                 {
1298                         SET_UNBATCHED_HANDLE(psHandle);
1299                 }
1300
1301                 ui32IndexPlusOne = ui32NextIndexPlusOne;
1302         }
1303
1304 #ifdef DEBUG
1305         if (psBase->ui32TotalHandCountPreBatch != psBase->ui32TotalHandCount)
1306         {
1307                 IMG_UINT32 ui32Delta = psBase->ui32TotalHandCount - psBase->ui32TotalHandCountPreBatch;
1308
1309                 PVR_ASSERT(psBase->ui32TotalHandCount > psBase->ui32TotalHandCountPreBatch);
1310
1311                 PVR_DPF((PVR_DBG_WARNING, "PVRSRVHandleBatchCommitOrRelease: The batch size was too small.  Batch size was %u, but needs to be %u", psBase->ui32HandBatchSize,  psBase->ui32HandBatchSize + ui32Delta));
1312
1313         }
1314 #endif
1315
1316         psBase->ui32HandBatchSize = 0;
1317         psBase->ui32FirstBatchIndexPlusOne = 0;
1318         psBase->ui32TotalHandCountPreBatch = 0;
1319         psBase->ui32BatchHandAllocFailures = 0;
1320
1321         if (psBase->ui32BatchHandAllocFailures != 0 && bCommit)
1322         {
1323                 PVR_ASSERT(!bCommitBatch);
1324
1325                 return PVRSRV_ERROR_GENERIC;
1326         }
1327
1328         return PVRSRV_OK;
1329 }
1330
1331 PVRSRV_ERROR PVRSRVCommitHandleBatch(PVRSRV_HANDLE_BASE *psBase)
1332 {
1333         return PVRSRVHandleBatchCommitOrRelease(psBase, IMG_TRUE);
1334 }
1335
1336 IMG_VOID PVRSRVReleaseHandleBatch(PVRSRV_HANDLE_BASE *psBase)
1337 {
1338         (IMG_VOID) PVRSRVHandleBatchCommitOrRelease(psBase, IMG_FALSE);
1339 }
1340
1341 PVRSRV_ERROR PVRSRVSetMaxHandle(PVRSRV_HANDLE_BASE *psBase, IMG_UINT32 ui32MaxHandle)
1342 {
1343         if (HANDLES_BATCHED(psBase))
1344         {
1345                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVSetMaxHandle: Limit cannot be set whilst in batch mode"));
1346                 return PVRSRV_ERROR_INVALID_PARAMS;
1347         }
1348
1349
1350         if (ui32MaxHandle == 0 || ui32MaxHandle >= DEFAULT_MAX_HANDLE)
1351         {
1352                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVSetMaxHandle: Limit must be between %u and %u, inclusive", 0, DEFAULT_MAX_HANDLE));
1353
1354                 return PVRSRV_ERROR_INVALID_PARAMS;
1355         }
1356
1357
1358         if (psBase->ui32TotalHandCount != 0)
1359         {
1360                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVSetMaxHandle: Limit cannot be set becuase handles have already been allocated"));
1361
1362                 return PVRSRV_ERROR_INVALID_PARAMS;
1363         }
1364
1365         psBase->ui32MaxIndexPlusOne = ui32MaxHandle;
1366
1367         return PVRSRV_OK;
1368 }
1369
1370 IMG_UINT32 PVRSRVGetMaxHandle(PVRSRV_HANDLE_BASE *psBase)
1371 {
1372         return psBase->ui32MaxIndexPlusOne;
1373 }
1374
1375 PVRSRV_ERROR PVRSRVEnableHandlePurging(PVRSRV_HANDLE_BASE *psBase)
1376 {
1377         if (psBase->bPurgingEnabled)
1378         {
1379                 PVR_DPF((PVR_DBG_WARNING, "PVRSRVEnableHandlePurging: Purging already enabled"));
1380                 return PVRSRV_OK;
1381         }
1382
1383
1384         if (psBase->ui32TotalHandCount != 0)
1385         {
1386                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVEnableHandlePurging: Handles have already been allocated"));
1387                 return PVRSRV_ERROR_INVALID_PARAMS;
1388         }
1389
1390         psBase->bPurgingEnabled = IMG_TRUE;
1391
1392         return PVRSRV_OK;
1393 }
1394
1395 PVRSRV_ERROR PVRSRVPurgeHandles(PVRSRV_HANDLE_BASE *psBase)
1396 {
1397         IMG_UINT32 ui32Handle;
1398         IMG_UINT32 ui32NewHandCount;
1399
1400         if (!psBase->bPurgingEnabled)
1401         {
1402                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVPurgeHandles: Purging not enabled for this handle base"));
1403                 return PVRSRV_ERROR_NOT_SUPPORTED;
1404         }
1405
1406         if (HANDLES_BATCHED(psBase))
1407         {
1408                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVPurgeHandles: Purging not allowed whilst in batch mode"));
1409                 return PVRSRV_ERROR_INVALID_PARAMS;
1410         }
1411
1412         for (ui32Handle = psBase->ui32TotalHandCount; ui32Handle != 0; ui32Handle--)
1413         {
1414                 struct sHandle *psHandle = HANDLE_TO_HANDLE_PTR(psBase, ui32Handle);
1415                 if (!HANDLE_STRUCT_IS_FREE(psHandle))
1416                 {
1417                         break;
1418                 }
1419         }
1420
1421         ui32NewHandCount = ROUND_UP_TO_MULTIPLE(ui32Handle, HANDLE_BLOCK_SIZE);
1422
1423
1424         if (ui32NewHandCount >= ui32Handle && ui32NewHandCount <= (psBase->ui32TotalHandCount/2))
1425         {
1426                 IMG_UINT32 ui32Delta = psBase->ui32TotalHandCount - ui32NewHandCount;
1427                 PVRSRV_ERROR eError;
1428
1429
1430
1431                 eError = ReallocHandleArray(psBase, ui32NewHandCount, psBase->ui32TotalHandCount);
1432                 if (eError != PVRSRV_OK)
1433                 {
1434                         return eError;
1435                 }
1436
1437
1438                 psBase->ui32TotalHandCount = ui32NewHandCount;
1439                 psBase->ui32FreeHandCount -= ui32Delta;
1440                 psBase->ui32FirstFreeIndex = 0;
1441         }
1442
1443         return PVRSRV_OK;
1444 }
1445
1446 PVRSRV_ERROR PVRSRVAllocHandleBase(PVRSRV_HANDLE_BASE **ppsBase)
1447 {
1448         PVRSRV_HANDLE_BASE *psBase;
1449         IMG_HANDLE hBlockAlloc;
1450         PVRSRV_ERROR eError;
1451
1452         eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
1453                 sizeof(*psBase),
1454                 (IMG_PVOID *)&psBase,
1455                 &hBlockAlloc,
1456                 "Handle Base");
1457         if (eError != PVRSRV_OK)
1458         {
1459                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandleBase: Couldn't allocate handle base (%d)", eError));
1460                 return eError;
1461         }
1462         OSMemSet(psBase, 0, sizeof(*psBase));
1463
1464
1465         psBase->psHashTab = HASH_Create_Extended(HANDLE_HASH_TAB_INIT_SIZE, sizeof(HAND_KEY), HASH_Func_Default, HASH_Key_Comp_Default);
1466         if (psBase->psHashTab == IMG_NULL)
1467         {
1468                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVAllocHandleBase: Couldn't create data pointer hash table\n"));
1469                 goto failure;
1470         }
1471
1472         psBase->hBaseBlockAlloc = hBlockAlloc;
1473
1474         psBase->ui32MaxIndexPlusOne = DEFAULT_MAX_INDEX_PLUS_ONE;
1475
1476         *ppsBase = psBase;
1477
1478         return PVRSRV_OK;
1479 failure:
1480         (IMG_VOID)PVRSRVFreeHandleBase(psBase);
1481         return PVRSRV_ERROR_GENERIC;
1482 }
1483
1484 PVRSRV_ERROR PVRSRVFreeHandleBase(PVRSRV_HANDLE_BASE *psBase)
1485 {
1486         PVRSRV_ERROR eError;
1487
1488         PVR_ASSERT(psBase != gpsKernelHandleBase);
1489
1490         eError = FreeHandleBase(psBase);
1491         if (eError != PVRSRV_OK)
1492         {
1493                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVFreeHandleBase: FreeHandleBase failed (%d)", eError));
1494         }
1495
1496         return eError;
1497 }
1498
1499 PVRSRV_ERROR PVRSRVHandleInit(IMG_VOID)
1500 {
1501         PVRSRV_ERROR eError;
1502
1503         PVR_ASSERT(gpsKernelHandleBase == IMG_NULL);
1504
1505         eError = PVRSRVAllocHandleBase(&gpsKernelHandleBase);
1506         if (eError != PVRSRV_OK)
1507         {
1508                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleInit: PVRSRVAllocHandleBase failed (%d)", eError));
1509                 goto error;
1510         }
1511
1512         eError = PVRSRVEnableHandlePurging(gpsKernelHandleBase);
1513         if (eError != PVRSRV_OK)
1514         {
1515                 PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleInit: PVRSRVEnableHandlePurging failed (%d)", eError));
1516                 goto error;
1517         }
1518
1519         return PVRSRV_OK;
1520 error:
1521         (IMG_VOID) PVRSRVHandleDeInit();
1522         return eError;
1523 }
1524
1525 PVRSRV_ERROR PVRSRVHandleDeInit(IMG_VOID)
1526 {
1527         PVRSRV_ERROR eError = PVRSRV_OK;
1528
1529         if (gpsKernelHandleBase != IMG_NULL)
1530         {
1531                 eError = FreeHandleBase(gpsKernelHandleBase);
1532                 if (eError == PVRSRV_OK)
1533                 {
1534                         gpsKernelHandleBase = IMG_NULL;
1535                 }
1536                 else
1537                 {
1538                         PVR_DPF((PVR_DBG_ERROR, "PVRSRVHandleDeInit: FreeHandleBase failed (%d)", eError));
1539                 }
1540         }
1541
1542         return eError;
1543 }
1544 #else
1545 #endif