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