gpu: pvr: fix locking on the HW recovery reset error path
[sgx.git] / pvr / ra.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 "services_headers.h"
28 #include "hash.h"
29 #include "ra.h"
30 #include "buffer_manager.h"
31 #include "osfunc.h"
32
33 #include <linux/kernel.h>
34 #include "proc.h"
35
36
37 #define MINIMUM_HASH_SIZE       64
38
39 struct BT {
40         enum bt_type {
41                 btt_span,
42                 btt_free,
43                 btt_live
44         } type;
45
46         u32 base;
47         size_t uSize;
48
49         struct BT *pNextSegment;
50         struct BT *pPrevSegment;
51
52         struct BT *pNextFree;
53         struct BT *pPrevFree;
54
55         struct BM_MAPPING *psMapping;
56 };
57 struct BT;
58
59 struct RA_ARENA {
60         char *name;
61         u32 uQuantum;
62         IMG_BOOL(*pImportAlloc)(void *, size_t uSize, size_t *pActualSize,
63                                 struct BM_MAPPING **ppsMapping, u32 uFlags,
64                                 u32 *pBase);
65         void (*pImportFree)(void *, u32, struct BM_MAPPING *psMapping);
66         void (*pBackingStoreFree)(void *, u32, u32, void *);
67         void *pImportHandle;
68 #define FREE_TABLE_LIMIT        32
69         struct BT *aHeadFree[FREE_TABLE_LIMIT];
70         struct BT *pHeadSegment;
71         struct BT *pTailSegment;
72         struct HASH_TABLE *pSegmentHash;
73 #ifdef RA_STATS
74         struct RA_STATISTICS sStatistics;
75 #endif
76 #if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA)
77 #define PROC_NAME_SIZE          32
78         char szProcInfoName[PROC_NAME_SIZE];
79         char szProcSegsName[PROC_NAME_SIZE];
80         IMG_BOOL bInitProcEntry;
81 #endif
82 };
83
84 #if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA)
85 static int RA_DumpSegs(char *page, char **start, off_t off, int count, int *eof,
86                        void *data);
87 static int RA_DumpInfo(char *page, char **start, off_t off, int count, int *eof,
88                        void *data);
89 #endif
90
91 #if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA)
92 static char *ReplaceSpaces(char *const pS)
93 {
94         char *pT;
95
96         for (pT = pS; *pT != 0; pT++)
97                 if (*pT == ' ' || *pT == '\t')
98                         *pT = '_';
99
100         return pS;
101 }
102 #endif
103
104 static IMG_BOOL _RequestAllocFail(void *_h, size_t _uSize, size_t *_pActualSize,
105                                   struct BM_MAPPING **_ppsMapping,
106                                   u32 _uFlags, u32 *_pBase)
107 {
108         PVR_UNREFERENCED_PARAMETER(_h);
109         PVR_UNREFERENCED_PARAMETER(_uSize);
110         PVR_UNREFERENCED_PARAMETER(_pActualSize);
111         PVR_UNREFERENCED_PARAMETER(_ppsMapping);
112         PVR_UNREFERENCED_PARAMETER(_uFlags);
113         PVR_UNREFERENCED_PARAMETER(_pBase);
114
115         return IMG_FALSE;
116 }
117
118 static u32 pvr_log2(size_t n)
119 {
120         u32 l = 0;
121         n >>= 1;
122         while (n > 0) {
123                 n >>= 1;
124                 l++;
125         }
126         return l;
127 }
128
129 static enum PVRSRV_ERROR _SegmentListInsertAfter(struct RA_ARENA *pArena,
130                                                  struct BT *pInsertionPoint,
131                                                  struct BT *pBT)
132 {
133         PVR_ASSERT(pArena != NULL);
134         PVR_ASSERT(pInsertionPoint != NULL);
135
136         if ((pInsertionPoint == NULL) || (pArena == NULL)) {
137                 PVR_DPF(PVR_DBG_ERROR,
138                          "_SegmentListInsertAfter: invalid parameters");
139                 return PVRSRV_ERROR_INVALID_PARAMS;
140         }
141
142         pBT->pNextSegment = pInsertionPoint->pNextSegment;
143         pBT->pPrevSegment = pInsertionPoint;
144         if (pInsertionPoint->pNextSegment == NULL)
145                 pArena->pTailSegment = pBT;
146         else
147                 pInsertionPoint->pNextSegment->pPrevSegment = pBT;
148         pInsertionPoint->pNextSegment = pBT;
149
150         return PVRSRV_OK;
151 }
152
153 static enum PVRSRV_ERROR _SegmentListInsert(struct RA_ARENA *pArena,
154                                             struct BT *pBT)
155 {
156         enum PVRSRV_ERROR eError = PVRSRV_OK;
157
158         if (pArena->pHeadSegment == NULL) {
159                 pArena->pHeadSegment = pArena->pTailSegment = pBT;
160                 pBT->pNextSegment = pBT->pPrevSegment = NULL;
161         } else {
162                 struct BT *pBTScan;
163                 if (pBT->base < pArena->pHeadSegment->base) {
164                         pBT->pNextSegment = pArena->pHeadSegment;
165                         pArena->pHeadSegment->pPrevSegment = pBT;
166                         pArena->pHeadSegment = pBT;
167                         pBT->pPrevSegment = NULL;
168                 } else {
169                         pBTScan = pArena->pHeadSegment;
170
171                         while ((pBTScan->pNextSegment != NULL) &&
172                                (pBT->base >= pBTScan->pNextSegment->base))
173                                 pBTScan = pBTScan->pNextSegment;
174
175                         eError = _SegmentListInsertAfter(pArena, pBTScan, pBT);
176                         if (eError != PVRSRV_OK)
177                                 return eError;
178                 }
179         }
180         return eError;
181 }
182
183 static void _SegmentListRemove(struct RA_ARENA *pArena, struct BT *pBT)
184 {
185         if (pBT->pPrevSegment == NULL)
186                 pArena->pHeadSegment = pBT->pNextSegment;
187         else
188                 pBT->pPrevSegment->pNextSegment = pBT->pNextSegment;
189
190         if (pBT->pNextSegment == NULL)
191                 pArena->pTailSegment = pBT->pPrevSegment;
192         else
193                 pBT->pNextSegment->pPrevSegment = pBT->pPrevSegment;
194 }
195
196 static struct BT *_SegmentSplit(struct RA_ARENA *pArena, struct BT *pBT,
197                                 size_t uSize)
198 {
199         struct BT *pNeighbour;
200
201         PVR_ASSERT(pArena != NULL);
202
203         if (pArena == NULL) {
204                 PVR_DPF(PVR_DBG_ERROR,
205                          "_SegmentSplit: invalid parameter - pArena");
206                 return NULL;
207         }
208
209         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
210                        sizeof(struct BT),
211                        (void **) &pNeighbour, NULL) != PVRSRV_OK)
212                 return NULL;
213
214         pNeighbour->pPrevSegment = pBT;
215         pNeighbour->pNextSegment = pBT->pNextSegment;
216         if (pBT->pNextSegment == NULL)
217                 pArena->pTailSegment = pNeighbour;
218         else
219                 pBT->pNextSegment->pPrevSegment = pNeighbour;
220         pBT->pNextSegment = pNeighbour;
221
222         pNeighbour->type = btt_free;
223         pNeighbour->uSize = pBT->uSize - uSize;
224         pNeighbour->base = pBT->base + uSize;
225         pNeighbour->psMapping = pBT->psMapping;
226         pBT->uSize = uSize;
227         return pNeighbour;
228 }
229
230 static void _FreeListInsert(struct RA_ARENA *pArena, struct BT *pBT)
231 {
232         u32 uIndex;
233         uIndex = pvr_log2(pBT->uSize);
234         pBT->type = btt_free;
235         pBT->pNextFree = pArena->aHeadFree[uIndex];
236         pBT->pPrevFree = NULL;
237         if (pArena->aHeadFree[uIndex] != NULL)
238                 pArena->aHeadFree[uIndex]->pPrevFree = pBT;
239         pArena->aHeadFree[uIndex] = pBT;
240 }
241
242 static void _FreeListRemove(struct RA_ARENA *pArena, struct BT *pBT)
243 {
244         u32 uIndex;
245         uIndex = pvr_log2(pBT->uSize);
246         if (pBT->pNextFree != NULL)
247                 pBT->pNextFree->pPrevFree = pBT->pPrevFree;
248         if (pBT->pPrevFree == NULL)
249                 pArena->aHeadFree[uIndex] = pBT->pNextFree;
250         else
251                 pBT->pPrevFree->pNextFree = pBT->pNextFree;
252 }
253
254 static struct BT *_BuildSpanMarker(u32 base, size_t uSize)
255 {
256         struct BT *pBT;
257
258         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
259                        sizeof(struct BT),
260                        (void **) &pBT, NULL) != PVRSRV_OK)
261                 return NULL;
262
263         pBT->type = btt_span;
264         pBT->base = base;
265         pBT->uSize = uSize;
266         pBT->psMapping = NULL;
267
268         return pBT;
269 }
270
271 static struct BT *_BuildBT(u32 base, size_t uSize)
272 {
273         struct BT *pBT;
274
275         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
276                        sizeof(struct BT),
277                        (void **) &pBT, NULL) != PVRSRV_OK)
278                 return NULL;
279
280         pBT->type = btt_free;
281         pBT->base = base;
282         pBT->uSize = uSize;
283
284         return pBT;
285 }
286
287 static struct BT *_InsertResource(struct RA_ARENA *pArena, u32 base,
288                            size_t uSize)
289 {
290         struct BT *pBT;
291         PVR_ASSERT(pArena != NULL);
292         if (pArena == NULL) {
293                 PVR_DPF(PVR_DBG_ERROR,
294                          "_InsertResource: invalid parameter - pArena");
295                 return NULL;
296         }
297
298         pBT = _BuildBT(base, uSize);
299         if (pBT != NULL) {
300                 if (_SegmentListInsert(pArena, pBT) != PVRSRV_OK) {
301                         PVR_DPF(PVR_DBG_ERROR,
302                         "_InsertResource: call to _SegmentListInsert failed");
303                         return NULL;
304                 }
305                 _FreeListInsert(pArena, pBT);
306 #ifdef RA_STATS
307                 pArena->sStatistics.uTotalResourceCount += uSize;
308                 pArena->sStatistics.uFreeResourceCount += uSize;
309                 pArena->sStatistics.uSpanCount++;
310 #endif
311         }
312         return pBT;
313 }
314
315 static struct BT *_InsertResourceSpan(struct RA_ARENA *pArena, u32 base,
316                                size_t uSize)
317 {
318         enum PVRSRV_ERROR eError;
319         struct BT *pSpanStart;
320         struct BT *pSpanEnd;
321         struct BT *pBT;
322
323         PVR_ASSERT(pArena != NULL);
324         if (pArena == NULL) {
325                 PVR_DPF(PVR_DBG_ERROR,
326                          "_InsertResourceSpan: invalid parameter - pArena");
327                 return NULL;
328         }
329
330         PVR_DPF(PVR_DBG_MESSAGE,
331                  "RA_InsertResourceSpan: arena='%s', base=0x%x, size=0x%x",
332                  pArena->name, base, uSize);
333
334         pSpanStart = _BuildSpanMarker(base, uSize);
335         if (pSpanStart == NULL)
336                 goto fail_start;
337         pSpanEnd = _BuildSpanMarker(base + uSize, 0);
338         if (pSpanEnd == NULL)
339                 goto fail_end;
340
341         pBT = _BuildBT(base, uSize);
342         if (pBT == NULL)
343                 goto fail_bt;
344
345         eError = _SegmentListInsert(pArena, pSpanStart);
346         if (eError != PVRSRV_OK)
347                 goto fail_SegListInsert;
348
349         eError = _SegmentListInsertAfter(pArena, pSpanStart, pBT);
350         if (eError != PVRSRV_OK)
351                 goto fail_SegListInsert;
352
353         _FreeListInsert(pArena, pBT);
354
355         eError = _SegmentListInsertAfter(pArena, pBT, pSpanEnd);
356         if (eError != PVRSRV_OK)
357                 goto fail_SegListInsert;
358
359 #ifdef RA_STATS
360         pArena->sStatistics.uTotalResourceCount += uSize;
361 #endif
362         return pBT;
363
364 fail_SegListInsert:
365         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pBT, NULL);
366 fail_bt:
367         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pSpanEnd, NULL);
368 fail_end:
369         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pSpanStart, NULL);
370 fail_start:
371         return NULL;
372 }
373
374 static void _FreeBT(struct RA_ARENA *pArena, struct BT *pBT,
375                     IMG_BOOL bFreeBackingStore)
376 {
377         struct BT *pNeighbour;
378         u32 uOrigBase;
379         size_t uOrigSize;
380
381         PVR_ASSERT(pArena != NULL);
382         PVR_ASSERT(pBT != NULL);
383
384         if ((pArena == NULL) || (pBT == NULL)) {
385                 PVR_DPF(PVR_DBG_ERROR, "_FreeBT: invalid parameter");
386                 return;
387         }
388 #ifdef RA_STATS
389         pArena->sStatistics.uLiveSegmentCount--;
390         pArena->sStatistics.uFreeSegmentCount++;
391         pArena->sStatistics.uFreeResourceCount += pBT->uSize;
392 #endif
393
394         uOrigBase = pBT->base;
395         uOrigSize = pBT->uSize;
396
397         pNeighbour = pBT->pPrevSegment;
398         if (pNeighbour != NULL && pNeighbour->type == btt_free &&
399             pNeighbour->base + pNeighbour->uSize == pBT->base) {
400                 _FreeListRemove(pArena, pNeighbour);
401                 _SegmentListRemove(pArena, pNeighbour);
402                 pBT->base = pNeighbour->base;
403                 pBT->uSize += pNeighbour->uSize;
404                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT),
405                           pNeighbour, NULL);
406 #ifdef RA_STATS
407                 pArena->sStatistics.uFreeSegmentCount--;
408 #endif
409         }
410
411         pNeighbour = pBT->pNextSegment;
412         if (pNeighbour != NULL && pNeighbour->type == btt_free &&
413             pBT->base + pBT->uSize == pNeighbour->base) {
414                 _FreeListRemove(pArena, pNeighbour);
415                 _SegmentListRemove(pArena, pNeighbour);
416                 pBT->uSize += pNeighbour->uSize;
417                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT),
418                           pNeighbour, NULL);
419 #ifdef RA_STATS
420                 pArena->sStatistics.uFreeSegmentCount--;
421 #endif
422         }
423
424         if (pArena->pBackingStoreFree != NULL && bFreeBackingStore) {
425                 u32 uRoundedStart, uRoundedEnd;
426
427                 uRoundedStart = (uOrigBase / pArena->uQuantum) *
428                                                         pArena->uQuantum;
429
430                 if (uRoundedStart < pBT->base)
431                         uRoundedStart += pArena->uQuantum;
432
433                 uRoundedEnd = ((uOrigBase + uOrigSize + pArena->uQuantum -
434                       1) / pArena->uQuantum) * pArena->uQuantum;
435
436                 if (uRoundedEnd > (pBT->base + pBT->uSize))
437                         uRoundedEnd -= pArena->uQuantum;
438
439                 if (uRoundedStart < uRoundedEnd)
440                         pArena->pBackingStoreFree(pArena->pImportHandle,
441                                                   uRoundedStart, uRoundedEnd,
442                                                   (void *) 0);
443         }
444
445         if (pBT->pNextSegment != NULL && pBT->pNextSegment->type == btt_span &&
446             pBT->pPrevSegment != NULL && pBT->pPrevSegment->type == btt_span) {
447                 struct BT *next = pBT->pNextSegment;
448                 struct BT *prev = pBT->pPrevSegment;
449                 _SegmentListRemove(pArena, next);
450                 _SegmentListRemove(pArena, prev);
451                 _SegmentListRemove(pArena, pBT);
452                 pArena->pImportFree(pArena->pImportHandle, pBT->base,
453                                     pBT->psMapping);
454 #ifdef RA_STATS
455                 pArena->sStatistics.uSpanCount--;
456                 pArena->sStatistics.uExportCount++;
457                 pArena->sStatistics.uFreeSegmentCount--;
458                 pArena->sStatistics.uFreeResourceCount -= pBT->uSize;
459                 pArena->sStatistics.uTotalResourceCount -= pBT->uSize;
460 #endif
461                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), next,
462                           NULL);
463                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), prev,
464                           NULL);
465                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pBT,
466                           NULL);
467         } else
468                 _FreeListInsert(pArena, pBT);
469 }
470
471 static int alloc_from_bt(struct RA_ARENA *arena, struct BT *bt, u32 start,
472                          size_t size, u32 align,
473                          struct BM_MAPPING **new_mapping, u32 *new_base)
474 {
475         _FreeListRemove(arena, bt);
476         PVR_ASSERT(bt->type == btt_free);
477 #ifdef RA_STATS
478         arena->sStatistics.uLiveSegmentCount++;
479         arena->sStatistics.uFreeSegmentCount--;
480         arena->sStatistics.uFreeResourceCount -= bt->uSize;
481 #endif
482         if (start > bt->base) {
483                 struct BT *next_bt;
484
485                 next_bt = _SegmentSplit(arena, bt, start - bt->base);
486
487                 if (!next_bt) {
488                         PVR_DPF(PVR_DBG_ERROR, "_AttemptAllocAligned: "
489                                         "Front split failed");
490
491                         _FreeListInsert(arena, bt);
492                         return -1;
493                 }
494
495                 _FreeListInsert(arena, bt);
496 #ifdef RA_STATS
497                 arena->sStatistics.uFreeSegmentCount++;
498                 arena->sStatistics.uFreeResourceCount += bt->uSize;
499 #endif
500                 bt = next_bt;
501         }
502
503         if (bt->uSize > size) {
504                 struct BT *next_bt;
505                 next_bt = _SegmentSplit(arena, bt, size);
506
507                 if (!next_bt) {
508                         PVR_DPF(PVR_DBG_ERROR, "_AttemptAllocAligned: "
509                                         "Back split failed");
510
511                         _FreeListInsert(arena, bt);
512                         return -1;
513                 }
514
515                 _FreeListInsert(arena, next_bt);
516 #ifdef RA_STATS
517                 arena->sStatistics.uFreeSegmentCount++;
518                 arena->sStatistics.uFreeResourceCount += next_bt->uSize;
519 #endif
520         }
521
522         bt->type = btt_live;
523
524         if (!HASH_Insert(arena->pSegmentHash, bt->base, (u32)bt)) {
525                 _FreeBT(arena, bt, IMG_FALSE);
526                 return -1;
527         }
528
529         if (new_mapping)
530                 *new_mapping = bt->psMapping;
531
532         *new_base = bt->base;
533
534         return 0;
535 }
536
537 static IMG_BOOL _AttemptAllocAligned(struct RA_ARENA *pArena, size_t uSize,
538                      struct BM_MAPPING **ppsMapping, u32 uFlags, u32 uAlignment,
539                      u32 *base)
540 {
541         u32 uIndex;
542         PVR_ASSERT(pArena != NULL);
543         if (pArena == NULL) {
544                 PVR_DPF(PVR_DBG_ERROR,
545                          "_AttemptAllocAligned: invalid parameter - pArena");
546                 return IMG_FALSE;
547         }
548
549         uIndex = pvr_log2(uSize);
550
551         while (uIndex < FREE_TABLE_LIMIT && pArena->aHeadFree[uIndex] == NULL)
552                 uIndex++;
553
554         for (; uIndex < FREE_TABLE_LIMIT; uIndex++) {
555                 struct BT *pBT;
556
557                 pBT = pArena->aHeadFree[uIndex];
558                 if (!pBT)
559                         continue;
560
561                 for (; pBT != NULL; pBT = pBT->pNextFree) {
562                         u32 aligned_base;
563
564                         if (uAlignment > 1)
565                                 aligned_base = (pBT->base + uAlignment -
566                                           1) / uAlignment * uAlignment;
567                         else
568                                 aligned_base = pBT->base;
569                         PVR_DPF(PVR_DBG_MESSAGE,
570                            "RA_AttemptAllocAligned: pBT-base=0x%x "
571                            "pBT-size=0x%x alignedbase=0x%x size=0x%x",
572                            pBT->base, pBT->uSize, aligned_base, uSize);
573
574                         if (pBT->base + pBT->uSize < aligned_base + uSize)
575                                 continue;
576
577                         if (pBT->psMapping && pBT->psMapping->ui32Flags !=
578                             uFlags) {
579                                 PVR_DPF(PVR_DBG_MESSAGE,
580                                         "AttemptAllocAligned: mismatch in "
581                                         "flags. Import has %x, request was %x",
582                                          pBT->psMapping->ui32Flags, uFlags);
583                                 continue;
584                         }
585
586                         if (alloc_from_bt(pArena, pBT, aligned_base, uSize,
587                                           uFlags, ppsMapping, base) < 0)
588                                 return IMG_FALSE;
589
590                         return IMG_TRUE;
591                 }
592         }
593
594         return IMG_FALSE;
595 }
596
597 struct RA_ARENA *RA_Create(char *name, u32 base, size_t uSize,
598                            struct BM_MAPPING *psMapping, size_t uQuantum,
599                            IMG_BOOL(*imp_alloc) (void *, size_t uSize,
600                                                  size_t *pActualSize,
601                                                  struct BM_MAPPING **ppsMapping,
602                                                  u32 _flags, u32 *pBase),
603                            void (*imp_free) (void *, u32, struct BM_MAPPING *),
604                            void(*backingstore_free) (void *, u32, u32, void *),
605                            void *pImportHandle)
606 {
607         struct RA_ARENA *pArena;
608         struct BT *pBT;
609         int i;
610
611         PVR_DPF(PVR_DBG_MESSAGE, "RA_Create: "
612                  "name='%s', base=0x%x, uSize=0x%x, alloc=0x%x, free=0x%x",
613                  name, base, uSize, imp_alloc, imp_free);
614
615         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
616                        sizeof(*pArena),
617                        (void **) &pArena, NULL) != PVRSRV_OK)
618                 goto arena_fail;
619
620         pArena->name = name;
621         pArena->pImportAlloc =
622             (imp_alloc != NULL) ? imp_alloc : _RequestAllocFail;
623         pArena->pImportFree = imp_free;
624         pArena->pBackingStoreFree = backingstore_free;
625         pArena->pImportHandle = pImportHandle;
626         for (i = 0; i < FREE_TABLE_LIMIT; i++)
627                 pArena->aHeadFree[i] = NULL;
628         pArena->pHeadSegment = NULL;
629         pArena->pTailSegment = NULL;
630         pArena->uQuantum = uQuantum;
631
632 #ifdef RA_STATS
633         pArena->sStatistics.uSpanCount = 0;
634         pArena->sStatistics.uLiveSegmentCount = 0;
635         pArena->sStatistics.uFreeSegmentCount = 0;
636         pArena->sStatistics.uFreeResourceCount = 0;
637         pArena->sStatistics.uTotalResourceCount = 0;
638         pArena->sStatistics.uCumulativeAllocs = 0;
639         pArena->sStatistics.uCumulativeFrees = 0;
640         pArena->sStatistics.uImportCount = 0;
641         pArena->sStatistics.uExportCount = 0;
642 #endif
643
644 #if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA)
645         if (strcmp(pArena->name, "") != 0) {
646                 int ret;
647                 int (*pfnCreateProcEntry) (const char *, read_proc_t,
648                                            write_proc_t, void *);
649
650                 pArena->bInitProcEntry =
651                     !PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_SUCCESSFUL);
652
653                 pfnCreateProcEntry = pArena->bInitProcEntry ? CreateProcEntry :
654                                             CreatePerProcessProcEntry;
655
656                 ret = snprintf(pArena->szProcInfoName,
657                              sizeof(pArena->szProcInfoName), "ra_info_%s",
658                              pArena->name);
659                 if (ret > 0 && ret < sizeof(pArena->szProcInfoName)) {
660                         (void)pfnCreateProcEntry(ReplaceSpaces
661                                                (pArena->szProcInfoName),
662                                                RA_DumpInfo, NULL, pArena);
663                 } else {
664                         pArena->szProcInfoName[0] = 0;
665                         PVR_DPF(PVR_DBG_ERROR, "RA_Create: "
666                               "couldn't create ra_info proc entry for arena %s",
667                                  pArena->name);
668                 }
669
670                 ret = snprintf(pArena->szProcSegsName,
671                              sizeof(pArena->szProcSegsName), "ra_segs_%s",
672                              pArena->name);
673                 if (ret > 0 && ret < sizeof(pArena->szProcInfoName)) {
674                         (void)pfnCreateProcEntry(ReplaceSpaces
675                                                (pArena->szProcSegsName),
676                                                RA_DumpSegs, NULL, pArena);
677                 } else {
678                         pArena->szProcSegsName[0] = 0;
679                         PVR_DPF(PVR_DBG_ERROR, "RA_Create: "
680                               "couldn't create ra_segs proc entry for arena %s",
681                                  pArena->name);
682                 }
683         }
684 #endif
685
686         pArena->pSegmentHash = HASH_Create(MINIMUM_HASH_SIZE);
687         if (pArena->pSegmentHash == NULL)
688                 goto hash_fail;
689         if (uSize > 0) {
690                 uSize = (uSize + uQuantum - 1) / uQuantum * uQuantum;
691                 pBT = _InsertResource(pArena, base, uSize);
692                 if (pBT == NULL)
693                         goto insert_fail;
694                 pBT->psMapping = psMapping;
695
696         }
697         return pArena;
698
699 insert_fail:
700         HASH_Delete(pArena->pSegmentHash);
701 hash_fail:
702         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RA_ARENA), pArena,
703                   NULL);
704 arena_fail:
705         return NULL;
706 }
707
708 void RA_Delete(struct RA_ARENA *pArena)
709 {
710         u32 uIndex;
711
712         PVR_ASSERT(pArena != NULL);
713
714         if (pArena == NULL) {
715                 PVR_DPF(PVR_DBG_ERROR,
716                          "RA_Delete: invalid parameter - pArena");
717                 return;
718         }
719
720         PVR_DPF(PVR_DBG_MESSAGE, "RA_Delete: name='%s'", pArena->name);
721
722         for (uIndex = 0; uIndex < FREE_TABLE_LIMIT; uIndex++)
723                 pArena->aHeadFree[uIndex] = NULL;
724
725         while (pArena->pHeadSegment != NULL) {
726                 struct BT *pBT = pArena->pHeadSegment;
727                 PVR_ASSERT(pBT->type == btt_free);
728                 _SegmentListRemove(pArena, pBT);
729                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pBT,
730                           NULL);
731 #ifdef RA_STATS
732                 pArena->sStatistics.uSpanCount--;
733 #endif
734         }
735 #if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA)
736         {
737                 void (*pfnRemoveProcEntry) (const char *);
738
739                 pfnRemoveProcEntry =
740                     pArena->
741                     bInitProcEntry ? RemoveProcEntry :
742                     RemovePerProcessProcEntry;
743
744                 if (pArena->szProcInfoName[0] != 0)
745                         pfnRemoveProcEntry(pArena->szProcInfoName);
746
747                 if (pArena->szProcSegsName[0] != 0)
748                         pfnRemoveProcEntry(pArena->szProcSegsName);
749         }
750 #endif
751         HASH_Delete(pArena->pSegmentHash);
752         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RA_ARENA), pArena,
753                   NULL);
754 }
755
756 IMG_BOOL RA_TestDelete(struct RA_ARENA *pArena)
757 {
758         PVR_ASSERT(pArena != NULL);
759
760         if (pArena != NULL)
761                 while (pArena->pHeadSegment != NULL) {
762                         struct BT *pBT = pArena->pHeadSegment;
763                         if (pBT->type != btt_free)
764                                 return IMG_FALSE;
765                 }
766
767         return IMG_TRUE;
768 }
769
770 IMG_BOOL RA_Add(struct RA_ARENA *pArena, u32 base, size_t uSize)
771 {
772         PVR_ASSERT(pArena != NULL);
773
774         if (pArena == NULL) {
775                 PVR_DPF(PVR_DBG_ERROR, "RA_Add: invalid parameter - pArena");
776                 return IMG_FALSE;
777         }
778
779         PVR_DPF(PVR_DBG_MESSAGE,
780                  "RA_Add: name='%s', base=0x%x, size=0x%x", pArena->name, base,
781                  uSize);
782
783         uSize = (uSize + pArena->uQuantum - 1) /
784                 pArena->uQuantum * pArena->uQuantum;
785         return (IMG_BOOL)(_InsertResource(pArena, base, uSize) != NULL);
786 }
787
788 IMG_BOOL RA_Alloc(struct RA_ARENA *pArena, size_t uRequestSize,
789                   struct BM_MAPPING **ppsMapping, u32 uFlags, u32 uAlignment,
790                   u32 *base)
791 {
792         IMG_BOOL bResult;
793         size_t uSize = uRequestSize;
794
795         PVR_ASSERT(pArena != NULL);
796
797         if (pArena == NULL) {
798                 PVR_DPF(PVR_DBG_ERROR,
799                          "RA_Alloc: invalid parameter - pArena");
800                 return IMG_FALSE;
801         }
802
803         PVR_DPF(PVR_DBG_MESSAGE, "RA_Alloc: "
804                  "arena='%s', size=0x%x(0x%x), alignment=0x%x",
805                  pArena->name, uSize, uRequestSize, uAlignment);
806
807         bResult = _AttemptAllocAligned(pArena, uSize, ppsMapping, uFlags,
808                                        uAlignment, base);
809         if (!bResult) {
810                 struct BM_MAPPING *psImportMapping;
811                 u32 import_base;
812                 size_t uImportSize = uSize;
813
814                 if (uAlignment > pArena->uQuantum)
815                         uImportSize += (uAlignment - 1);
816
817                 uImportSize =
818                     ((uImportSize + pArena->uQuantum - 1) /
819                      pArena->uQuantum) * pArena->uQuantum;
820
821                 bResult =
822                     pArena->pImportAlloc(pArena->pImportHandle, uImportSize,
823                                          &uImportSize, &psImportMapping, uFlags,
824                                          &import_base);
825                 if (bResult) {
826                         struct BT *pBT;
827                         pBT = _InsertResourceSpan(pArena, import_base,
828                                                 uImportSize);
829
830                         if (pBT == NULL) {
831                                 pArena->pImportFree(pArena->pImportHandle,
832                                                     import_base,
833                                                     psImportMapping);
834                                 PVR_DPF(PVR_DBG_MESSAGE, "RA_Alloc: "
835                                          "name='%s', size=0x%x failed!",
836                                          pArena->name, uSize);
837
838                                 return IMG_FALSE;
839                         }
840                         pBT->psMapping = psImportMapping;
841 #ifdef RA_STATS
842                         pArena->sStatistics.uFreeSegmentCount++;
843                         pArena->sStatistics.uFreeResourceCount += uImportSize;
844                         pArena->sStatistics.uImportCount++;
845                         pArena->sStatistics.uSpanCount++;
846 #endif
847                         bResult = _AttemptAllocAligned(pArena, uSize,
848                                                  ppsMapping, uFlags, uAlignment,
849                                                  base);
850                         if (!bResult)
851                                 PVR_DPF(PVR_DBG_MESSAGE, "RA_Alloc: "
852                                          "name='%s' uAlignment failed!",
853                                          pArena->name);
854                 }
855         }
856 #ifdef RA_STATS
857         if (bResult)
858                 pArena->sStatistics.uCumulativeAllocs++;
859 #endif
860
861         PVR_DPF(PVR_DBG_MESSAGE,
862                  "RA_Alloc: name='%s', size=0x%x, *base=0x%x = %d",
863                  pArena->name, uSize, *base, bResult);
864
865         return bResult;
866 }
867
868 void RA_Free(struct RA_ARENA *pArena, u32 base, IMG_BOOL bFreeBackingStore)
869 {
870         struct BT *pBT;
871
872         PVR_ASSERT(pArena != NULL);
873
874         if (pArena == NULL) {
875                 PVR_DPF(PVR_DBG_ERROR, "RA_Free: invalid parameter - pArena");
876                 return;
877         }
878
879         PVR_DPF(PVR_DBG_MESSAGE,
880                  "RA_Free: name='%s', base=0x%x", pArena->name, base);
881
882         pBT = (struct BT *)HASH_Remove(pArena->pSegmentHash, base);
883         PVR_ASSERT(pBT != NULL);
884
885         if (pBT) {
886                 PVR_ASSERT(pBT->base == base);
887
888 #ifdef RA_STATS
889                 pArena->sStatistics.uCumulativeFrees++;
890 #endif
891
892                 _FreeBT(pArena, pBT, bFreeBackingStore);
893         }
894 }
895
896 IMG_BOOL RA_GetNextLiveSegment(void *hArena,
897                                struct RA_SEGMENT_DETAILS *psSegDetails)
898 {
899         struct BT *pBT;
900
901         if (psSegDetails->hSegment) {
902                 pBT = (struct BT *)psSegDetails->hSegment;
903         } else {
904                 struct RA_ARENA *pArena = (struct RA_ARENA *)hArena;
905                 pBT = pArena->pHeadSegment;
906         }
907
908         while (pBT != NULL) {
909                 if (pBT->type == btt_live) {
910                         psSegDetails->uiSize = pBT->uSize;
911                         psSegDetails->sCpuPhyAddr.uiAddr = pBT->base;
912                         psSegDetails->hSegment = (void *) pBT->pNextSegment;
913
914                         return IMG_TRUE;
915                 }
916
917                 pBT = pBT->pNextSegment;
918         }
919
920         psSegDetails->uiSize = 0;
921         psSegDetails->sCpuPhyAddr.uiAddr = 0;
922         psSegDetails->hSegment = (void *) -1;
923
924         return IMG_FALSE;
925 }
926
927 #if (defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA)) || \
928      defined(RA_STATS)
929 static char *_BTType(int eType)
930 {
931         switch (eType) {
932         case btt_span:
933                 return "span";
934         case btt_free:
935                 return "free";
936         case btt_live:
937                 return "live";
938         }
939         return "junk";
940 }
941 #endif
942
943 #if defined(ENABLE_RA_DUMP)
944 void RA_Dump(struct RA_ARENA *pArena)
945 {
946         struct BT *pBT;
947         PVR_ASSERT(pArena != NULL);
948         PVR_DPF(PVR_DBG_MESSAGE, "Arena '%s':", pArena->name);
949         PVR_DPF(PVR_DBG_MESSAGE,
950                  "  alloc=%08X free=%08X handle=%08X quantum=%d",
951                  pArena->pImportAlloc, pArena->pImportFree,
952                  pArena->pImportHandle, pArena->uQuantum);
953         PVR_DPF(PVR_DBG_MESSAGE, "  segment Chain:");
954         if (pArena->pHeadSegment != NULL &&
955             pArena->pHeadSegment->pPrevSegment != NULL)
956                 PVR_DPF(PVR_DBG_MESSAGE,
957                          "  error: head boundary tag has invalid pPrevSegment");
958         if (pArena->pTailSegment != NULL &&
959             pArena->pTailSegment->pNextSegment != NULL)
960                 PVR_DPF(PVR_DBG_MESSAGE,
961                          "  error: tail boundary tag has invalid pNextSegment");
962
963         for (pBT = pArena->pHeadSegment; pBT != NULL; pBT = pBT->pNextSegment)
964                 PVR_DPF(PVR_DBG_MESSAGE,
965                          "\tbase=0x%x size=0x%x type=%s ref=%08X",
966                          (u32) pBT->base, pBT->uSize, _BTType(pBT->type),
967                          pBT->pRef);
968
969 }
970 #endif
971
972 #if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA)
973 static int RA_DumpSegs(char *page, char **start, off_t off, int count, int *eof,
974                        void *data)
975 {
976         struct BT *pBT = NULL;
977         int len = 0;
978         struct RA_ARENA *pArena = (struct RA_ARENA *)data;
979
980         if (count < 80) {
981                 *start = (char *)0;
982                 return 0;
983         }
984         *eof = 0;
985         *start = (char *)1;
986         if (off == 0)
987                 return printAppend(page, count, 0,
988                         "Arena \"%s\"\nBase         Size Type Ref\n",
989                         pArena->name);
990         for (pBT = pArena->pHeadSegment; --off && pBT;
991              pBT = pBT->pNextSegment)
992                 ;
993         if (pBT)
994                 len = printAppend(page, count, 0, "%08x %8x %4s %08x\n",
995                                   (unsigned)pBT->base, (unsigned)pBT->uSize,
996                                   _BTType(pBT->type), (unsigned)pBT->psMapping);
997         else
998                 *eof = 1;
999         return len;
1000 }
1001
1002 static int RA_DumpInfo(char *page, char **start, off_t off, int count, int *eof,
1003             void *data)
1004 {
1005         int len = 0;
1006         struct RA_ARENA *pArena = (struct RA_ARENA *)data;
1007
1008         if (count < 80) {
1009                 *start = (char *)0;
1010                 return 0;
1011         }
1012         *eof = 0;
1013         switch (off) {
1014         case 0:
1015                 len = printAppend(page, count, 0, "quantum\t\t\t%u\n",
1016                                   pArena->uQuantum);
1017                 break;
1018         case 1:
1019                 len = printAppend(page, count, 0, "import_handle\t\t%08X\n",
1020                                 (unsigned)pArena->pImportHandle);
1021                 break;
1022 #ifdef RA_STATS
1023         case 2:
1024                 len = printAppend(page, count, 0, "span count\t\t%u\n",
1025                                 pArena->sStatistics.uSpanCount);
1026                 break;
1027         case 3:
1028                 len = printAppend(page, count, 0, "live segment count\t%u\n",
1029                                 pArena->sStatistics.uLiveSegmentCount);
1030                 break;
1031         case 4:
1032                 len = printAppend(page, count, 0, "free segment count\t%u\n",
1033                                 pArena->sStatistics.uFreeSegmentCount);
1034                 break;
1035         case 5:
1036                 len = printAppend(page, count, 0,
1037                                 "free resource count\t%u (0x%x)\n",
1038                                 pArena->sStatistics.uFreeResourceCount,
1039                                 (unsigned)pArena->sStatistics.
1040                                 uFreeResourceCount);
1041                 break;
1042         case 6:
1043                 len = printAppend(page, count, 0, "total allocs\t\t%u\n",
1044                                 pArena->sStatistics.uCumulativeAllocs);
1045                 break;
1046         case 7:
1047                 len = printAppend(page, count, 0, "total frees\t\t%u\n",
1048                                 pArena->sStatistics.uCumulativeFrees);
1049                 break;
1050         case 8:
1051                 len = printAppend(page, count, 0, "import count\t\t%u\n",
1052                                 pArena->sStatistics.uImportCount);
1053                 break;
1054         case 9:
1055                 len = printAppend(page, count, 0, "export count\t\t%u\n",
1056                                 pArena->sStatistics.uExportCount);
1057                 break;
1058 #endif
1059
1060         default:
1061                 *eof = 1;
1062         }
1063         *start = (char *)1;
1064         return len;
1065 }
1066 #endif
1067
1068 #ifdef RA_STATS
1069 enum PVRSRV_ERROR RA_GetStats(struct RA_ARENA *pArena, char **ppszStr,
1070                               u32 *pui32StrLen)
1071 {
1072         char *pszStr = *ppszStr;
1073         u32 ui32StrLen = *pui32StrLen;
1074         s32 i32Count;
1075         struct BT *pBT;
1076
1077         CHECK_SPACE(ui32StrLen);
1078         i32Count = OSSNPrintf(pszStr, 100, "\nArena '%s':\n", pArena->name);
1079         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1080
1081         CHECK_SPACE(ui32StrLen);
1082         i32Count = OSSNPrintf(pszStr, 100,
1083                        "  allocCB=%08X freeCB=%08X handle=%08X quantum=%d\n",
1084                        pArena->pImportAlloc, pArena->pImportFree,
1085                        pArena->pImportHandle, pArena->uQuantum);
1086         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1087
1088         CHECK_SPACE(ui32StrLen);
1089         i32Count = OSSNPrintf(pszStr, 100, "span count\t\t%lu\n",
1090                        pArena->sStatistics.uSpanCount);
1091         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1092
1093         CHECK_SPACE(ui32StrLen);
1094         i32Count = OSSNPrintf(pszStr, 100, "live segment count\t%lu\n",
1095                        pArena->sStatistics.uLiveSegmentCount);
1096         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1097
1098         CHECK_SPACE(ui32StrLen);
1099         i32Count = OSSNPrintf(pszStr, 100, "free segment count\t%lu\n",
1100                        pArena->sStatistics.uFreeSegmentCount);
1101         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1102
1103         CHECK_SPACE(ui32StrLen);
1104         i32Count = OSSNPrintf(pszStr, 100, "free resource count\t%lu (0x%x)\n",
1105                               pArena->sStatistics.uFreeResourceCount,
1106                               (unsigned)pArena->sStatistics.uFreeResourceCount);
1107         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1108
1109         CHECK_SPACE(ui32StrLen);
1110         i32Count = OSSNPrintf(pszStr, 100, "total allocs\t\t%lu\n",
1111                        pArena->sStatistics.uCumulativeAllocs);
1112         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1113
1114         CHECK_SPACE(ui32StrLen);
1115         i32Count = OSSNPrintf(pszStr, 100, "total frees\t\t%lu\n",
1116                        pArena->sStatistics.uCumulativeFrees);
1117         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1118
1119         CHECK_SPACE(ui32StrLen);
1120         i32Count = OSSNPrintf(pszStr, 100, "import count\t\t%lu\n",
1121                        pArena->sStatistics.uImportCount);
1122         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1123
1124         CHECK_SPACE(ui32StrLen);
1125         i32Count = OSSNPrintf(pszStr, 100, "export count\t\t%lu\n",
1126                        pArena->sStatistics.uExportCount);
1127         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1128
1129         CHECK_SPACE(ui32StrLen);
1130         i32Count = OSSNPrintf(pszStr, 100, "  segment Chain:\n");
1131         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1132
1133         if (pArena->pHeadSegment != NULL &&
1134             pArena->pHeadSegment->pPrevSegment != NULL) {
1135                 CHECK_SPACE(ui32StrLen);
1136                 i32Count = OSSNPrintf(pszStr, 100,
1137                        "  error: head boundary tag has invalid pPrevSegment\n");
1138                 UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1139         }
1140
1141         if (pArena->pTailSegment != NULL &&
1142             pArena->pTailSegment->pNextSegment != NULL) {
1143                 CHECK_SPACE(ui32StrLen);
1144                 i32Count = OSSNPrintf(pszStr, 100,
1145                        "  error: tail boundary tag has invalid pNextSegment\n");
1146                 UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1147         }
1148
1149         for (pBT = pArena->pHeadSegment; pBT != NULL;
1150              pBT = pBT->pNextSegment) {
1151                 CHECK_SPACE(ui32StrLen);
1152                 i32Count = OSSNPrintf(pszStr, 100,
1153                                "\tbase=0x%x size=0x%x type=%s ref=%08X\n",
1154                                (u32) pBT->base, pBT->uSize, _BTType(pBT->type),
1155                                pBT->psMapping);
1156                 UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1157         }
1158
1159         *ppszStr = pszStr;
1160         *pui32StrLen = ui32StrLen;
1161
1162         return PVRSRV_OK;
1163 }
1164 #endif