gpu: pvr: enable debug trace for basic debug build
[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         }
586
587         if (ui32CopySize != 0)
588                 OSMemCopy(pvNewMem, pvOldMem, ui32CopySize);
589
590         if (ui32OldSize != 0)
591                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, ui32OldSize, pvOldMem,
592                           hOldBlockAlloc);
593
594         *ppvMem = pvNewMem;
595         *phBlockAlloc = hNewBlockAlloc;
596
597         return PVRSRV_OK;
598 }
599
600 static inline enum PVRSRV_ERROR ReallocHandleArray(struct PVRSRV_HANDLE_BASE
601                                                    *psBase, u32 ui32NewCount,
602                                                    u32 ui32OldCount)
603 {
604         return ReallocMem((void **)&psBase->psHandleArray,
605                           &psBase->hHandBlockAlloc,
606                           ui32NewCount * sizeof(struct sHandle),
607                           ui32OldCount * sizeof(struct sHandle));
608 }
609
610 static enum PVRSRV_ERROR IncreaseHandleArraySize(struct PVRSRV_HANDLE_BASE
611                                                  *psBase, u32 ui32Delta)
612 {
613         enum PVRSRV_ERROR eError;
614         struct sHandle *psHandle;
615         u32 ui32DeltaAdjusted =
616             ROUND_UP_TO_MULTIPLE(ui32Delta, HANDLE_BLOCK_SIZE);
617         u32 ui32NewTotalHandCount =
618             psBase->ui32TotalHandCount + ui32DeltaAdjusted;
619
620         PVR_ASSERT(ui32Delta != 0);
621
622         if (ui32NewTotalHandCount > psBase->ui32MaxIndexPlusOne ||
623             ui32NewTotalHandCount <= psBase->ui32TotalHandCount) {
624                 ui32NewTotalHandCount = psBase->ui32MaxIndexPlusOne;
625
626                 ui32DeltaAdjusted =
627                     ui32NewTotalHandCount - psBase->ui32TotalHandCount;
628
629                 if (ui32DeltaAdjusted < ui32Delta) {
630                         PVR_DPF(PVR_DBG_ERROR, "IncreaseHandleArraySize: "
631                                         "Maximum handle limit reached (%d)",
632                                  psBase->ui32MaxIndexPlusOne);
633                         return PVRSRV_ERROR_OUT_OF_MEMORY;
634                 }
635         }
636
637         PVR_ASSERT(ui32DeltaAdjusted >= ui32Delta);
638
639         eError = ReallocHandleArray(psBase, ui32NewTotalHandCount,
640                                psBase->ui32TotalHandCount);
641         if (eError != PVRSRV_OK) {
642                 PVR_DPF(PVR_DBG_ERROR, "IncreaseHandleArraySize: "
643                                        "ReallocHandleArray failed (%d)",
644                          eError);
645                 return eError;
646         }
647
648         for (psHandle = psBase->psHandleArray + psBase->ui32TotalHandCount;
649              psHandle < psBase->psHandleArray + ui32NewTotalHandCount;
650              psHandle++) {
651                 psHandle->eType = PVRSRV_HANDLE_TYPE_NONE;
652                 psHandle->eInternalFlag = INTERNAL_HANDLE_FLAG_NONE;
653                 psHandle->ui32NextIndexPlusOne = 0;
654         }
655
656         psBase->ui32FreeHandCount += ui32DeltaAdjusted;
657
658         if (psBase->ui32FirstFreeIndex == 0) {
659                 PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0);
660
661                 psBase->ui32FirstFreeIndex = psBase->ui32TotalHandCount;
662         } else {
663                 if (!psBase->bPurgingEnabled) {
664                         PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0);
665                         PVR_ASSERT(INDEX_TO_HANDLE_PTR
666                                        (psBase,
667                                         psBase->ui32LastFreeIndexPlusOne -
668                                         1)->ui32NextIndexPlusOne == 0);
669
670                         INDEX_TO_HANDLE_PTR(psBase,
671                                             psBase->ui32LastFreeIndexPlusOne -
672                                             1)->ui32NextIndexPlusOne =
673                             psBase->ui32TotalHandCount + 1;
674                 }
675         }
676
677         if (!psBase->bPurgingEnabled)
678                 psBase->ui32LastFreeIndexPlusOne = ui32NewTotalHandCount;
679
680         psBase->ui32TotalHandCount = ui32NewTotalHandCount;
681
682         return PVRSRV_OK;
683 }
684
685 static enum PVRSRV_ERROR EnsureFreeHandles(struct PVRSRV_HANDLE_BASE *psBase,
686                                       u32 ui32Free)
687 {
688         enum PVRSRV_ERROR eError;
689
690         if (ui32Free > psBase->ui32FreeHandCount) {
691                 u32 ui32FreeHandDelta =
692                     ui32Free - psBase->ui32FreeHandCount;
693                 eError = IncreaseHandleArraySize(psBase, ui32FreeHandDelta);
694                 if (eError != PVRSRV_OK) {
695                         PVR_DPF(PVR_DBG_ERROR, "EnsureFreeHandles: "
696                                 "Couldn't allocate %u handles to ensure %u "
697                                 "free handles (IncreaseHandleArraySize "
698                                 "failed with error %d)",
699                                 ui32FreeHandDelta, ui32Free, eError);
700
701                         return eError;
702                 }
703         }
704
705         return PVRSRV_OK;
706 }
707
708 static enum PVRSRV_ERROR AllocHandle(struct PVRSRV_HANDLE_BASE *psBase,
709                                 void **phHandle, void *pvData,
710                                 enum PVRSRV_HANDLE_TYPE eType,
711                                 enum PVRSRV_HANDLE_ALLOC_FLAG eFlag,
712                                 void *hParent)
713 {
714         u32 ui32NewIndex;
715         struct sHandle *psNewHandle = NULL;
716         void *hHandle;
717         u32 aKey[HAND_KEY_LEN];
718         enum PVRSRV_ERROR eError;
719
720         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
721
722         PVR_ASSERT(psBase->psHashTab != NULL);
723
724         if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI))
725                 PVR_ASSERT(FindHandle(psBase, pvData, eType, hParent) == NULL);
726
727         if (psBase->ui32FreeHandCount == 0 && HANDLES_BATCHED(psBase))
728                 PVR_DPF(PVR_DBG_WARNING, "AllocHandle: "
729                         "Handle batch size (%u) was too small, "
730                         "allocating additional space",
731                          psBase->ui32HandBatchSize);
732
733         eError = EnsureFreeHandles(psBase, 1);
734         if (eError != PVRSRV_OK) {
735                 PVR_DPF(PVR_DBG_ERROR,
736                          "AllocHandle: EnsureFreeHandles failed (%d)", eError);
737                 return eError;
738         }
739         PVR_ASSERT(psBase->ui32FreeHandCount != 0);
740
741         if (!psBase->bPurgingEnabled) {
742                 ui32NewIndex = psBase->ui32FirstFreeIndex;
743                 psNewHandle = INDEX_TO_HANDLE_PTR(psBase, ui32NewIndex);
744         } else {
745                 for (ui32NewIndex = psBase->ui32FirstFreeIndex;
746                      ui32NewIndex < psBase->ui32TotalHandCount;
747                      ui32NewIndex++) {
748                         psNewHandle = INDEX_TO_HANDLE_PTR(psBase, ui32NewIndex);
749                         if (HANDLE_STRUCT_IS_FREE(psNewHandle))
750                                 break;
751
752                 }
753                 psBase->ui32FirstFreeIndex = 0;
754                 PVR_ASSERT(ui32NewIndex < psBase->ui32TotalHandCount);
755         }
756         PVR_ASSERT(psNewHandle != NULL);
757
758         hHandle = INDEX_TO_HANDLE(psBase, ui32NewIndex);
759
760         if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) {
761
762                 InitKey(aKey, psBase, pvData, eType, hParent);
763
764                 if (!HASH_Insert_Extended
765                     (psBase->psHashTab, aKey, (u32) hHandle)) {
766                         PVR_DPF(PVR_DBG_ERROR, "AllocHandle: "
767                                         "Couldn't add handle to hash table");
768
769                         return PVRSRV_ERROR_GENERIC;
770                 }
771         }
772
773         psBase->ui32FreeHandCount--;
774
775         if (!psBase->bPurgingEnabled) {
776                 if (psBase->ui32FreeHandCount == 0) {
777                         PVR_ASSERT(psBase->ui32FirstFreeIndex == ui32NewIndex);
778                         PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne ==
779                                    (ui32NewIndex + 1));
780
781                         psBase->ui32LastFreeIndexPlusOne = 0;
782                         psBase->ui32FirstFreeIndex = 0;
783                 } else {
784                         psBase->ui32FirstFreeIndex =
785                             (psNewHandle->ui32NextIndexPlusOne ==
786                                      0) ? ui32NewIndex +
787                                     1 : psNewHandle->ui32NextIndexPlusOne - 1;
788                 }
789         }
790
791         psNewHandle->eType = eType;
792         psNewHandle->pvData = pvData;
793         psNewHandle->eInternalFlag = INTERNAL_HANDLE_FLAG_NONE;
794         psNewHandle->eFlag = eFlag;
795         psNewHandle->ui32Index = ui32NewIndex;
796
797         InitParentList(psBase, psNewHandle);
798         PVR_ASSERT(NoChildren(psBase, psNewHandle));
799
800         InitChildEntry(psBase, psNewHandle);
801         PVR_ASSERT(NoParent(psBase, psNewHandle));
802
803         if (HANDLES_BATCHED(psBase)) {
804
805                 psNewHandle->ui32NextIndexPlusOne =
806                     psBase->ui32FirstBatchIndexPlusOne;
807
808                 psBase->ui32FirstBatchIndexPlusOne = ui32NewIndex + 1;
809
810                 SET_BATCHED_HANDLE(psNewHandle);
811         } else {
812                 psNewHandle->ui32NextIndexPlusOne = 0;
813         }
814
815         *phHandle = hHandle;
816
817         return PVRSRV_OK;
818 }
819
820 enum PVRSRV_ERROR PVRSRVAllocHandle(struct PVRSRV_HANDLE_BASE *psBase,
821                                void **phHandle, void *pvData,
822                                enum PVRSRV_HANDLE_TYPE eType,
823                                enum PVRSRV_HANDLE_ALLOC_FLAG eFlag)
824 {
825         void *hHandle;
826         enum PVRSRV_ERROR eError;
827
828         *phHandle = NULL;
829
830         if (HANDLES_BATCHED(psBase))
831                 psBase->ui32BatchHandAllocFailures++;
832
833         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
834
835         if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) {
836                 hHandle = FindHandle(psBase, pvData, eType, NULL);
837                 if (hHandle != NULL) {
838                         struct sHandle *psHandle;
839
840                         eError =
841                             GetHandleStructure(psBase, &psHandle, hHandle,
842                                                eType);
843                         if (eError != PVRSRV_OK) {
844                                 PVR_DPF(PVR_DBG_ERROR,
845                                         "PVRSRVAllocHandle: "
846                                         "Lookup of existing handle failed");
847                                 return eError;
848                         }
849
850                         if (TEST_FLAG(psHandle->eFlag & eFlag,
851                              PVRSRV_HANDLE_ALLOC_FLAG_SHARED)) {
852                                 *phHandle = hHandle;
853                                 eError = PVRSRV_OK;
854                                 goto exit_ok;
855                         }
856                         return PVRSRV_ERROR_GENERIC;
857                 }
858         }
859
860         eError = AllocHandle(psBase, phHandle, pvData, eType, eFlag, NULL);
861
862 exit_ok:
863         if (HANDLES_BATCHED(psBase) && (eError == PVRSRV_OK))
864                 psBase->ui32BatchHandAllocFailures--;
865
866         return eError;
867 }
868
869 enum PVRSRV_ERROR PVRSRVAllocSubHandle(struct PVRSRV_HANDLE_BASE *psBase,
870                                   void **phHandle, void *pvData,
871                                   enum PVRSRV_HANDLE_TYPE eType,
872                                   enum PVRSRV_HANDLE_ALLOC_FLAG eFlag,
873                                   void *hParent)
874 {
875         struct sHandle *psPHand;
876         struct sHandle *psCHand;
877         enum PVRSRV_ERROR eError;
878         void *hParentKey;
879         void *hHandle;
880
881         *phHandle = NULL;
882
883         if (HANDLES_BATCHED(psBase))
884
885                 psBase->ui32BatchHandAllocFailures++;
886
887         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
888
889         hParentKey = TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ?
890             hParent : NULL;
891
892         eError = GetHandleStructure(psBase, &psPHand, hParent,
893                                PVRSRV_HANDLE_TYPE_NONE);
894         if (eError != PVRSRV_OK)
895                 return PVRSRV_ERROR_GENERIC;
896
897         if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) {
898
899                 hHandle = FindHandle(psBase, pvData, eType, hParentKey);
900                 if (hHandle != NULL) {
901                         struct sHandle *psCHandle;
902                         enum PVRSRV_ERROR eErr;
903
904                         eErr = GetHandleStructure(psBase, &psCHandle, hHandle,
905                                                eType);
906                         if (eErr != PVRSRV_OK) {
907                                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVAllocSubHandle: "
908                                         "Lookup of existing handle failed");
909                                 return eErr;
910                         }
911
912                         PVR_ASSERT(hParentKey != NULL &&
913                                    ParentHandle(HANDLE_TO_HANDLE_PTR
914                                                 (psBase, hHandle)) == hParent);
915
916                         if (TEST_FLAG(psCHandle->eFlag & eFlag,
917                             PVRSRV_HANDLE_ALLOC_FLAG_SHARED) &&
918                             ParentHandle(HANDLE_TO_HANDLE_PTR(psBase, hHandle))
919                             == hParent) {
920                                 *phHandle = hHandle;
921                                 goto exit_ok;
922                         }
923                         return PVRSRV_ERROR_GENERIC;
924                 }
925         }
926
927         eError = AllocHandle(psBase, &hHandle, pvData, eType, eFlag,
928                              hParentKey);
929         if (eError != PVRSRV_OK)
930                 return eError;
931
932         psPHand = HANDLE_TO_HANDLE_PTR(psBase, hParent);
933
934         psCHand = HANDLE_TO_HANDLE_PTR(psBase, hHandle);
935
936         AdoptChild(psBase, psPHand, psCHand);
937
938         *phHandle = hHandle;
939
940 exit_ok:
941         if (HANDLES_BATCHED(psBase))
942                 psBase->ui32BatchHandAllocFailures--;
943
944         return PVRSRV_OK;
945 }
946
947 enum PVRSRV_ERROR PVRSRVFindHandle(struct PVRSRV_HANDLE_BASE *psBase,
948                               void **phHandle, void *pvData,
949                               enum PVRSRV_HANDLE_TYPE eType)
950 {
951         void *hHandle;
952
953         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
954
955         hHandle = (void *)FindHandle(psBase, pvData, eType, NULL);
956         if (hHandle == NULL)
957                 return PVRSRV_ERROR_GENERIC;
958
959         *phHandle = hHandle;
960
961         return PVRSRV_OK;
962 }
963
964 enum PVRSRV_ERROR PVRSRVLookupHandleAnyType(struct PVRSRV_HANDLE_BASE *psBase,
965                                        void **ppvData,
966                                        enum PVRSRV_HANDLE_TYPE *peType,
967                                        void *hHandle)
968 {
969         struct sHandle *psHandle;
970         enum PVRSRV_ERROR eError;
971
972         eError = GetHandleStructure(psBase, &psHandle, hHandle,
973                                PVRSRV_HANDLE_TYPE_NONE);
974         if (eError != PVRSRV_OK) {
975                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVLookupHandleAnyType: "
976                                         "Error looking up handle (%d)",
977                                         eError);
978                 return eError;
979         }
980
981         *ppvData = psHandle->pvData;
982         *peType = psHandle->eType;
983
984         return PVRSRV_OK;
985 }
986
987 enum PVRSRV_ERROR PVRSRVLookupHandle(struct PVRSRV_HANDLE_BASE *psBase,
988                                 void **ppvData, void *hHandle,
989                                 enum PVRSRV_HANDLE_TYPE eType)
990 {
991         struct sHandle *psHandle;
992         enum PVRSRV_ERROR eError;
993
994         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
995
996         eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
997         if (eError != PVRSRV_OK) {
998                 PVR_DPF(PVR_DBG_ERROR,
999                          "PVRSRVLookupHandle: Error looking up handle (%d)",
1000                          eError);
1001                 return eError;
1002         }
1003
1004         *ppvData = psHandle->pvData;
1005
1006         return PVRSRV_OK;
1007 }
1008
1009 enum PVRSRV_ERROR PVRSRVLookupSubHandle(struct PVRSRV_HANDLE_BASE *psBase,
1010                                    void **ppvData, void *hHandle,
1011                                    enum PVRSRV_HANDLE_TYPE eType,
1012                                    void *hAncestor)
1013 {
1014         struct sHandle *psPHand;
1015         struct sHandle *psCHand;
1016         enum PVRSRV_ERROR eError;
1017
1018         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1019
1020         eError = GetHandleStructure(psBase, &psCHand, hHandle, eType);
1021         if (eError != PVRSRV_OK) {
1022                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVLookupSubHandle: "
1023                                 "Error looking up subhandle (%d)",
1024                          eError);
1025                 return eError;
1026         }
1027
1028         for (psPHand = psCHand; ParentHandle(psPHand) != hAncestor;) {
1029                 eError =
1030                     GetHandleStructure(psBase, &psPHand, ParentHandle(psPHand),
1031                                        PVRSRV_HANDLE_TYPE_NONE);
1032                 if (eError != PVRSRV_OK) {
1033                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVLookupSubHandle: "
1034                                 "Subhandle doesn't belong to given ancestor");
1035                         return PVRSRV_ERROR_GENERIC;
1036                 }
1037         }
1038
1039         *ppvData = psCHand->pvData;
1040
1041         return PVRSRV_OK;
1042 }
1043
1044 enum PVRSRV_ERROR PVRSRVGetParentHandle(struct PVRSRV_HANDLE_BASE *psBase,
1045                                    void **phParent, void *hHandle,
1046                                    enum PVRSRV_HANDLE_TYPE eType)
1047 {
1048         struct sHandle *psHandle;
1049         enum PVRSRV_ERROR eError;
1050
1051         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1052
1053         eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
1054         if (eError != PVRSRV_OK) {
1055                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVGetParentHandle: "
1056                                         "Error looking up subhandle (%d)",
1057                          eError);
1058                 return eError;
1059         }
1060
1061         *phParent = ParentHandle(psHandle);
1062
1063         return PVRSRV_OK;
1064 }
1065
1066 enum PVRSRV_ERROR PVRSRVLookupAndReleaseHandle(
1067                                 struct PVRSRV_HANDLE_BASE *psBase,
1068                                 void **ppvData, void *hHandle,
1069                                 enum PVRSRV_HANDLE_TYPE eType)
1070 {
1071         struct sHandle *psHandle;
1072         enum PVRSRV_ERROR eError;
1073
1074         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1075
1076         eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
1077         if (eError != PVRSRV_OK) {
1078                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVLookupAndReleaseHandle: "
1079                                         "Error looking up handle (%d)",
1080                          eError);
1081                 return eError;
1082         }
1083
1084         *ppvData = psHandle->pvData;
1085
1086         eError = FreeHandle(psBase, psHandle);
1087
1088         return eError;
1089 }
1090
1091 enum PVRSRV_ERROR PVRSRVReleaseHandle(struct PVRSRV_HANDLE_BASE *psBase,
1092                                  void *hHandle, enum PVRSRV_HANDLE_TYPE eType)
1093 {
1094         struct sHandle *psHandle;
1095         enum PVRSRV_ERROR eError;
1096
1097         PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
1098
1099         eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
1100         if (eError != PVRSRV_OK) {
1101                 PVR_DPF(PVR_DBG_ERROR,
1102                          "PVRSRVReleaseHandle: Error looking up handle (%d)",
1103                          eError);
1104                 return eError;
1105         }
1106
1107         eError = FreeHandle(psBase, psHandle);
1108
1109         return eError;
1110 }
1111
1112 enum PVRSRV_ERROR PVRSRVNewHandleBatch(struct PVRSRV_HANDLE_BASE *psBase,
1113                                   u32 ui32BatchSize)
1114 {
1115         enum PVRSRV_ERROR eError;
1116
1117         if (HANDLES_BATCHED(psBase)) {
1118                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVNewHandleBatch: "
1119                           "There is a handle batch already in use (size %u)",
1120                          psBase->ui32HandBatchSize);
1121                 return PVRSRV_ERROR_GENERIC;
1122         }
1123
1124         if (ui32BatchSize == 0) {
1125                 PVR_DPF(PVR_DBG_ERROR,
1126                          "PVRSRVNewHandleBatch: Invalid batch size (%u)",
1127                          ui32BatchSize);
1128                 return PVRSRV_ERROR_INVALID_PARAMS;
1129         }
1130
1131         eError = EnsureFreeHandles(psBase, ui32BatchSize);
1132         if (eError != PVRSRV_OK) {
1133                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVNewHandleBatch: "
1134                                 "EnsureFreeHandles failed (error %d)",
1135                          eError);
1136                 return eError;
1137         }
1138
1139         psBase->ui32HandBatchSize = ui32BatchSize;
1140         psBase->ui32TotalHandCountPreBatch = psBase->ui32TotalHandCount;
1141
1142         PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0);
1143         PVR_ASSERT(psBase->ui32FirstBatchIndexPlusOne == 0);
1144         PVR_ASSERT(HANDLES_BATCHED(psBase));
1145
1146         return PVRSRV_OK;
1147 }
1148
1149 static enum PVRSRV_ERROR PVRSRVHandleBatchCommitOrRelease(
1150                         struct PVRSRV_HANDLE_BASE *psBase, IMG_BOOL bCommit)
1151 {
1152         u32 ui32IndexPlusOne;
1153         IMG_BOOL bCommitBatch = bCommit;
1154
1155         if (!HANDLES_BATCHED(psBase)) {
1156                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVHandleBatchCommitOrRelease: "
1157                                         "There is no handle batch");
1158                 return PVRSRV_ERROR_INVALID_PARAMS;
1159
1160         }
1161
1162         if (psBase->ui32BatchHandAllocFailures != 0) {
1163                 if (bCommit)
1164                         PVR_DPF(PVR_DBG_ERROR,
1165                                 "PVRSRVHandleBatchCommitOrRelease: "
1166                                 "Attempting to commit batch with handle "
1167                                 "allocation failures.");
1168                 bCommitBatch = IMG_FALSE;
1169         }
1170
1171         PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0 || !bCommit);
1172
1173         ui32IndexPlusOne = psBase->ui32FirstBatchIndexPlusOne;
1174         while (ui32IndexPlusOne != 0) {
1175                 struct sHandle *psHandle =
1176                     INDEX_TO_HANDLE_PTR(psBase, ui32IndexPlusOne - 1);
1177                 u32 ui32NextIndexPlusOne =
1178                     psHandle->ui32NextIndexPlusOne;
1179                 PVR_ASSERT(BATCHED_HANDLE(psHandle));
1180
1181                 psHandle->ui32NextIndexPlusOne = 0;
1182
1183                 if (!bCommitBatch || BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) {
1184                         enum PVRSRV_ERROR eError;
1185
1186                         if (!BATCHED_HANDLE_PARTIALLY_FREE(psHandle))
1187                                 SET_UNBATCHED_HANDLE(psHandle);
1188
1189                         eError = FreeHandle(psBase, psHandle);
1190                         if (eError != PVRSRV_OK)
1191                                 PVR_DPF(PVR_DBG_ERROR,
1192                                         "PVRSRVHandleBatchCommitOrRelease: "
1193                                         "Error freeing handle (%d)",
1194                                          eError);
1195                         PVR_ASSERT(eError == PVRSRV_OK);
1196                 } else {
1197                         SET_UNBATCHED_HANDLE(psHandle);
1198                 }
1199
1200                 ui32IndexPlusOne = ui32NextIndexPlusOne;
1201         }
1202
1203 #ifdef CONFIG_PVR_DEBUG_EXTRA
1204         if (psBase->ui32TotalHandCountPreBatch != psBase->ui32TotalHandCount) {
1205                 u32 ui32Delta =
1206                     psBase->ui32TotalHandCount -
1207                     psBase->ui32TotalHandCountPreBatch;
1208
1209                 PVR_ASSERT(psBase->ui32TotalHandCount >
1210                            psBase->ui32TotalHandCountPreBatch);
1211
1212                 PVR_DPF(PVR_DBG_WARNING,
1213                          "PVRSRVHandleBatchCommitOrRelease: "
1214                          "The batch size was too small.  "
1215                          "Batch size was %u, but needs to be %u",
1216                          psBase->ui32HandBatchSize,
1217                          psBase->ui32HandBatchSize + ui32Delta);
1218
1219         }
1220 #endif
1221
1222         psBase->ui32HandBatchSize = 0;
1223         psBase->ui32FirstBatchIndexPlusOne = 0;
1224         psBase->ui32TotalHandCountPreBatch = 0;
1225         psBase->ui32BatchHandAllocFailures = 0;
1226
1227         if (psBase->ui32BatchHandAllocFailures != 0 && bCommit) {
1228                 PVR_ASSERT(!bCommitBatch);
1229
1230                 return PVRSRV_ERROR_GENERIC;
1231         }
1232
1233         return PVRSRV_OK;
1234 }
1235
1236 enum PVRSRV_ERROR PVRSRVCommitHandleBatch(struct PVRSRV_HANDLE_BASE *psBase)
1237 {
1238         return PVRSRVHandleBatchCommitOrRelease(psBase, IMG_TRUE);
1239 }
1240
1241 void PVRSRVReleaseHandleBatch(struct PVRSRV_HANDLE_BASE *psBase)
1242 {
1243         (void)PVRSRVHandleBatchCommitOrRelease(psBase, IMG_FALSE);
1244 }
1245
1246 enum PVRSRV_ERROR PVRSRVSetMaxHandle(struct PVRSRV_HANDLE_BASE *psBase,
1247                                      u32 ui32MaxHandle)
1248 {
1249         if (HANDLES_BATCHED(psBase)) {
1250                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVSetMaxHandle: "
1251                         "Limit cannot be set whilst in batch mode");
1252                 return PVRSRV_ERROR_INVALID_PARAMS;
1253         }
1254
1255         if (ui32MaxHandle == 0 || ui32MaxHandle > DEFAULT_MAX_HANDLE) {
1256                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVSetMaxHandle: "
1257                                 "Limit must be between %u and %u, inclusive",
1258                          0, DEFAULT_MAX_HANDLE);
1259
1260                 return PVRSRV_ERROR_INVALID_PARAMS;
1261         }
1262
1263         if (psBase->ui32TotalHandCount != 0) {
1264                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVSetMaxHandle: "
1265                                 "Limit cannot be set becuase handles "
1266                                 "have already been allocated");
1267
1268                 return PVRSRV_ERROR_INVALID_PARAMS;
1269         }
1270
1271         psBase->ui32MaxIndexPlusOne = ui32MaxHandle;
1272
1273         return PVRSRV_OK;
1274 }
1275
1276 u32 PVRSRVGetMaxHandle(struct PVRSRV_HANDLE_BASE *psBase)
1277 {
1278         return psBase->ui32MaxIndexPlusOne;
1279 }
1280
1281 enum PVRSRV_ERROR PVRSRVEnableHandlePurging(struct PVRSRV_HANDLE_BASE *psBase)
1282 {
1283         if (psBase->bPurgingEnabled) {
1284                 PVR_DPF(PVR_DBG_WARNING,
1285                          "PVRSRVEnableHandlePurging: Purging already enabled");
1286                 return PVRSRV_OK;
1287         }
1288
1289         if (psBase->ui32TotalHandCount != 0) {
1290                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVEnableHandlePurging: "
1291                                         "Handles have already been allocated");
1292                 return PVRSRV_ERROR_INVALID_PARAMS;
1293         }
1294
1295         psBase->bPurgingEnabled = IMG_TRUE;
1296
1297         return PVRSRV_OK;
1298 }
1299
1300 enum PVRSRV_ERROR PVRSRVPurgeHandles(struct PVRSRV_HANDLE_BASE *psBase)
1301 {
1302         u32 ui32Handle;
1303         u32 ui32NewHandCount;
1304
1305         if (!psBase->bPurgingEnabled) {
1306                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVPurgeHandles: "
1307                                 "Purging not enabled for this handle base");
1308                 return PVRSRV_ERROR_NOT_SUPPORTED;
1309         }
1310
1311         if (HANDLES_BATCHED(psBase)) {
1312                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVPurgeHandles: "
1313                                 "Purging not allowed whilst in batch mode");
1314                 return PVRSRV_ERROR_INVALID_PARAMS;
1315         }
1316
1317         for (ui32Handle = psBase->ui32TotalHandCount; ui32Handle != 0;
1318              ui32Handle--) {
1319                 struct sHandle *psHandle =
1320                     HANDLE_TO_HANDLE_PTR(psBase, ui32Handle);
1321                 if (!HANDLE_STRUCT_IS_FREE(psHandle))
1322                         break;
1323         }
1324
1325         ui32NewHandCount = ROUND_UP_TO_MULTIPLE(ui32Handle, HANDLE_BLOCK_SIZE);
1326
1327         if (ui32NewHandCount >= ui32Handle
1328             && ui32NewHandCount <= (psBase->ui32TotalHandCount / 2)) {
1329                 u32 ui32Delta = psBase->ui32TotalHandCount - ui32NewHandCount;
1330                 enum PVRSRV_ERROR eError;
1331
1332                 eError =
1333                     ReallocHandleArray(psBase, ui32NewHandCount,
1334                                        psBase->ui32TotalHandCount);
1335                 if (eError != PVRSRV_OK)
1336                         return eError;
1337
1338                 psBase->ui32TotalHandCount = ui32NewHandCount;
1339                 psBase->ui32FreeHandCount -= ui32Delta;
1340                 psBase->ui32FirstFreeIndex = 0;
1341         }
1342
1343         return PVRSRV_OK;
1344 }
1345
1346 enum PVRSRV_ERROR PVRSRVAllocHandleBase(struct PVRSRV_HANDLE_BASE **ppsBase)
1347 {
1348         struct PVRSRV_HANDLE_BASE *psBase;
1349         void *hBlockAlloc;
1350         enum PVRSRV_ERROR eError;
1351
1352         eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
1353                             sizeof(*psBase), (void **)&psBase, &hBlockAlloc);
1354         if (eError != PVRSRV_OK) {
1355                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVAllocHandleBase: "
1356                                         "Couldn't allocate handle base (%d)",
1357                          eError);
1358                 return eError;
1359         }
1360         OSMemSet(psBase, 0, sizeof(*psBase));
1361
1362         psBase->psHashTab =
1363             HASH_Create_Extended(HANDLE_HASH_TAB_INIT_SIZE,
1364                                  HAND_KEY_LEN * sizeof(u32),
1365                                  HASH_Func_Default, HASH_Key_Comp_Default);
1366         if (psBase->psHashTab == NULL) {
1367                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVAllocHandleBase: "
1368                                 "Couldn't create data pointer hash table\n");
1369                 goto failure;
1370         }
1371
1372         psBase->hBaseBlockAlloc = hBlockAlloc;
1373
1374         psBase->ui32MaxIndexPlusOne = DEFAULT_MAX_INDEX_PLUS_ONE;
1375
1376         *ppsBase = psBase;
1377
1378         return PVRSRV_OK;
1379 failure:
1380         (void)PVRSRVFreeHandleBase(psBase);
1381         return PVRSRV_ERROR_GENERIC;
1382 }
1383
1384 enum PVRSRV_ERROR PVRSRVFreeHandleBase(struct PVRSRV_HANDLE_BASE *psBase)
1385 {
1386         enum PVRSRV_ERROR eError;
1387
1388         PVR_ASSERT(psBase != gpsKernelHandleBase);
1389
1390         eError = FreeHandleBase(psBase);
1391         if (eError != PVRSRV_OK)
1392                 PVR_DPF(PVR_DBG_ERROR,
1393                          "PVRSRVFreeHandleBase: FreeHandleBase failed (%d)",
1394                          eError);
1395
1396         return eError;
1397 }
1398
1399 enum PVRSRV_ERROR PVRSRVHandleInit(void)
1400 {
1401         enum PVRSRV_ERROR eError;
1402
1403         PVR_ASSERT(gpsKernelHandleBase == NULL);
1404
1405         eError = PVRSRVAllocHandleBase(&gpsKernelHandleBase);
1406         if (eError != PVRSRV_OK) {
1407                 PVR_DPF(PVR_DBG_ERROR,
1408                          "PVRSRVHandleInit: PVRSRVAllocHandleBase failed (%d)",
1409                          eError);
1410                 goto error;
1411         }
1412
1413         eError = PVRSRVEnableHandlePurging(gpsKernelHandleBase);
1414         if (eError != PVRSRV_OK) {
1415                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVHandleInit: "
1416                                         "PVRSRVEnableHandlePurging failed (%d)",
1417                          eError);
1418                 goto error;
1419         }
1420
1421         return PVRSRV_OK;
1422 error:
1423         (void)PVRSRVHandleDeInit();
1424         return eError;
1425 }
1426
1427 enum PVRSRV_ERROR PVRSRVHandleDeInit(void)
1428 {
1429         enum PVRSRV_ERROR eError = PVRSRV_OK;
1430
1431         if (gpsKernelHandleBase != NULL) {
1432                 eError = FreeHandleBase(gpsKernelHandleBase);
1433                 if (eError == PVRSRV_OK) {
1434                         gpsKernelHandleBase = NULL;
1435                 } else {
1436                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVHandleDeInit: "
1437                                                 "FreeHandleBase failed (%d)",
1438                                  eError);
1439                 }
1440         }
1441
1442         return eError;
1443 }