fixes for bc_cat
[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         u32 ui32PID;
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
648                 if (PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_SUCCESSFUL))
649                         pArena->ui32PID = OSGetCurrentProcessIDKM();
650                 else
651                         pArena->ui32PID = 0;
652
653                 ret = snprintf(pArena->szProcInfoName,
654                              sizeof(pArena->szProcInfoName), "ra_info_%s",
655                              pArena->name);
656                 if ((ret > 0) && (ret < sizeof(pArena->szProcInfoName))) {
657                         ReplaceSpaces(pArena->szProcInfoName);
658                         ret = CreatePerProcessProcEntry(pArena->ui32PID,
659                                                         pArena->szProcInfoName,
660                                                         RA_DumpInfo, pArena);
661                 } else
662                         pArena->szProcInfoName[0] = 0;
663
664                 if (ret) {
665                         pArena->szProcInfoName[0] = 0;
666                         pr_err("%s: couldn't create ra_info proc entry for "
667                                "arena %s", __func__, 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->szProcSegsName))) {
674                         ReplaceSpaces(pArena->szProcSegsName);
675                         ret = CreatePerProcessProcEntry(pArena->ui32PID,
676                                                         pArena->szProcSegsName,
677                                                         RA_DumpSegs, pArena);
678                 } else
679                         ret = -1;
680
681                 if (ret) {
682                         pArena->szProcSegsName[0] = 0;
683                         pr_err("%s: couldn't create ra_segs proc entry for "
684                                "arena %s", __func__, pArena->name);
685                 }
686         }
687 #endif
688
689         pArena->pSegmentHash = HASH_Create(MINIMUM_HASH_SIZE);
690         if (pArena->pSegmentHash == NULL)
691                 goto hash_fail;
692         if (uSize > 0) {
693                 uSize = (uSize + uQuantum - 1) / uQuantum * uQuantum;
694                 pBT = _InsertResource(pArena, base, uSize);
695                 if (pBT == NULL)
696                         goto insert_fail;
697                 pBT->psMapping = psMapping;
698
699         }
700         return pArena;
701
702 insert_fail:
703         HASH_Delete(pArena->pSegmentHash);
704 hash_fail:
705         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RA_ARENA), pArena,
706                   NULL);
707 arena_fail:
708         return NULL;
709 }
710
711 void RA_Delete(struct RA_ARENA *pArena)
712 {
713         u32 uIndex;
714
715         PVR_ASSERT(pArena != NULL);
716
717         if (pArena == NULL) {
718                 PVR_DPF(PVR_DBG_ERROR,
719                          "RA_Delete: invalid parameter - pArena");
720                 return;
721         }
722
723         PVR_DPF(PVR_DBG_MESSAGE, "RA_Delete: name='%s'", pArena->name);
724
725         for (uIndex = 0; uIndex < FREE_TABLE_LIMIT; uIndex++)
726                 pArena->aHeadFree[uIndex] = NULL;
727
728         while (pArena->pHeadSegment != NULL) {
729                 struct BT *pBT = pArena->pHeadSegment;
730                 PVR_ASSERT(pBT->type == btt_free);
731                 _SegmentListRemove(pArena, pBT);
732                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pBT,
733                           NULL);
734 #ifdef RA_STATS
735                 pArena->sStatistics.uSpanCount--;
736 #endif
737         }
738 #if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA)
739         {
740                 if (pArena->szProcInfoName[0] != 0)
741                         RemovePerProcessProcEntry(pArena->ui32PID,
742                                                   pArena->szProcInfoName);
743
744                 if (pArena->szProcSegsName[0] != 0)
745                         RemovePerProcessProcEntry(pArena->ui32PID,
746                                                   pArena->szProcSegsName);
747         }
748 #endif
749         HASH_Delete(pArena->pSegmentHash);
750         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RA_ARENA), pArena,
751                   NULL);
752 }
753
754 IMG_BOOL RA_TestDelete(struct RA_ARENA *pArena)
755 {
756         PVR_ASSERT(pArena != NULL);
757
758         if (pArena != NULL)
759                 while (pArena->pHeadSegment != NULL) {
760                         struct BT *pBT = pArena->pHeadSegment;
761                         if (pBT->type != btt_free)
762                                 return IMG_FALSE;
763                 }
764
765         return IMG_TRUE;
766 }
767
768 IMG_BOOL RA_Add(struct RA_ARENA *pArena, u32 base, size_t uSize)
769 {
770         PVR_ASSERT(pArena != NULL);
771
772         if (pArena == NULL) {
773                 PVR_DPF(PVR_DBG_ERROR, "RA_Add: invalid parameter - pArena");
774                 return IMG_FALSE;
775         }
776
777         PVR_DPF(PVR_DBG_MESSAGE,
778                  "RA_Add: name='%s', base=0x%x, size=0x%x", pArena->name, base,
779                  uSize);
780
781         uSize = (uSize + pArena->uQuantum - 1) /
782                 pArena->uQuantum * pArena->uQuantum;
783         return (IMG_BOOL)(_InsertResource(pArena, base, uSize) != NULL);
784 }
785
786 IMG_BOOL RA_Alloc(struct RA_ARENA *pArena, size_t uRequestSize,
787                   struct BM_MAPPING **ppsMapping, u32 uFlags, u32 uAlignment,
788                   u32 *base)
789 {
790         IMG_BOOL bResult;
791         size_t uSize = uRequestSize;
792
793         PVR_ASSERT(pArena != NULL);
794
795         if (pArena == NULL) {
796                 PVR_DPF(PVR_DBG_ERROR,
797                          "RA_Alloc: invalid parameter - pArena");
798                 return IMG_FALSE;
799         }
800
801         PVR_DPF(PVR_DBG_MESSAGE, "RA_Alloc: "
802                  "arena='%s', size=0x%x(0x%x), alignment=0x%x",
803                  pArena->name, uSize, uRequestSize, uAlignment);
804
805         bResult = _AttemptAllocAligned(pArena, uSize, ppsMapping, uFlags,
806                                        uAlignment, base);
807         if (!bResult) {
808                 struct BM_MAPPING *psImportMapping;
809                 u32 import_base;
810                 size_t uImportSize = uSize;
811
812                 if (uAlignment > pArena->uQuantum)
813                         uImportSize += (uAlignment - 1);
814
815                 uImportSize =
816                     ((uImportSize + pArena->uQuantum - 1) /
817                      pArena->uQuantum) * pArena->uQuantum;
818
819                 bResult =
820                     pArena->pImportAlloc(pArena->pImportHandle, uImportSize,
821                                          &uImportSize, &psImportMapping, uFlags,
822                                          &import_base);
823                 if (bResult) {
824                         struct BT *pBT;
825                         pBT = _InsertResourceSpan(pArena, import_base,
826                                                 uImportSize);
827
828                         if (pBT == NULL) {
829                                 pArena->pImportFree(pArena->pImportHandle,
830                                                     import_base,
831                                                     psImportMapping);
832                                 PVR_DPF(PVR_DBG_MESSAGE, "RA_Alloc: "
833                                          "name='%s', size=0x%x failed!",
834                                          pArena->name, uSize);
835
836                                 return IMG_FALSE;
837                         }
838                         pBT->psMapping = psImportMapping;
839 #ifdef RA_STATS
840                         pArena->sStatistics.uFreeSegmentCount++;
841                         pArena->sStatistics.uFreeResourceCount += uImportSize;
842                         pArena->sStatistics.uImportCount++;
843                         pArena->sStatistics.uSpanCount++;
844 #endif
845                         bResult = _AttemptAllocAligned(pArena, uSize,
846                                                  ppsMapping, uFlags, uAlignment,
847                                                  base);
848                         if (!bResult)
849                                 PVR_DPF(PVR_DBG_MESSAGE, "RA_Alloc: "
850                                          "name='%s' uAlignment failed!",
851                                          pArena->name);
852                 }
853         }
854 #ifdef RA_STATS
855         if (bResult)
856                 pArena->sStatistics.uCumulativeAllocs++;
857 #endif
858
859         PVR_DPF(PVR_DBG_MESSAGE,
860                  "RA_Alloc: name='%s', size=0x%x, *base=0x%x = %d",
861                  pArena->name, uSize, *base, bResult);
862
863         return bResult;
864 }
865
866 void RA_Free(struct RA_ARENA *pArena, u32 base, IMG_BOOL bFreeBackingStore)
867 {
868         struct BT *pBT;
869
870         PVR_ASSERT(pArena != NULL);
871
872         if (pArena == NULL) {
873                 PVR_DPF(PVR_DBG_ERROR, "RA_Free: invalid parameter - pArena");
874                 return;
875         }
876
877         PVR_DPF(PVR_DBG_MESSAGE,
878                  "RA_Free: name='%s', base=0x%x", pArena->name, base);
879
880         pBT = (struct BT *)HASH_Remove(pArena->pSegmentHash, base);
881         PVR_ASSERT(pBT != NULL);
882
883         if (pBT) {
884                 PVR_ASSERT(pBT->base == base);
885
886 #ifdef RA_STATS
887                 pArena->sStatistics.uCumulativeFrees++;
888 #endif
889
890                 _FreeBT(pArena, pBT, bFreeBackingStore);
891         }
892 }
893
894 IMG_BOOL RA_GetNextLiveSegment(void *hArena,
895                                struct RA_SEGMENT_DETAILS *psSegDetails)
896 {
897         struct BT *pBT;
898
899         if (psSegDetails->hSegment) {
900                 pBT = (struct BT *)psSegDetails->hSegment;
901         } else {
902                 struct RA_ARENA *pArena = (struct RA_ARENA *)hArena;
903                 pBT = pArena->pHeadSegment;
904         }
905
906         while (pBT != NULL) {
907                 if (pBT->type == btt_live) {
908                         psSegDetails->uiSize = pBT->uSize;
909                         psSegDetails->sCpuPhyAddr.uiAddr = pBT->base;
910                         psSegDetails->hSegment = (void *) pBT->pNextSegment;
911
912                         return IMG_TRUE;
913                 }
914
915                 pBT = pBT->pNextSegment;
916         }
917
918         psSegDetails->uiSize = 0;
919         psSegDetails->sCpuPhyAddr.uiAddr = 0;
920         psSegDetails->hSegment = (void *) -1;
921
922         return IMG_FALSE;
923 }
924
925 #if (defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA)) || \
926      defined(RA_STATS)
927 static char *_BTType(int eType)
928 {
929         switch (eType) {
930         case btt_span:
931                 return "span";
932         case btt_free:
933                 return "free";
934         case btt_live:
935                 return "live";
936         }
937         return "junk";
938 }
939 #endif
940
941 #if defined(ENABLE_RA_DUMP)
942 void RA_Dump(struct RA_ARENA *pArena)
943 {
944         struct BT *pBT;
945         PVR_ASSERT(pArena != NULL);
946         PVR_DPF(PVR_DBG_MESSAGE, "Arena '%s':", pArena->name);
947         PVR_DPF(PVR_DBG_MESSAGE,
948                  "  alloc=%08X free=%08X handle=%08X quantum=%d",
949                  pArena->pImportAlloc, pArena->pImportFree,
950                  pArena->pImportHandle, pArena->uQuantum);
951         PVR_DPF(PVR_DBG_MESSAGE, "  segment Chain:");
952         if (pArena->pHeadSegment != NULL &&
953             pArena->pHeadSegment->pPrevSegment != NULL)
954                 PVR_DPF(PVR_DBG_MESSAGE,
955                          "  error: head boundary tag has invalid pPrevSegment");
956         if (pArena->pTailSegment != NULL &&
957             pArena->pTailSegment->pNextSegment != NULL)
958                 PVR_DPF(PVR_DBG_MESSAGE,
959                          "  error: tail boundary tag has invalid pNextSegment");
960
961         for (pBT = pArena->pHeadSegment; pBT != NULL; pBT = pBT->pNextSegment)
962                 PVR_DPF(PVR_DBG_MESSAGE,
963                          "\tbase=0x%x size=0x%x type=%s ref=%08X",
964                          (u32) pBT->base, pBT->uSize, _BTType(pBT->type),
965                          pBT->pRef);
966
967 }
968 #endif
969
970 #if defined(CONFIG_PROC_FS) && defined(CONFIG_PVR_DEBUG_EXTRA)
971 static int RA_DumpSegs(char *page, char **start, off_t off, int count, int *eof,
972                        void *data)
973 {
974         struct BT *pBT = NULL;
975         int len = 0;
976         struct RA_ARENA *pArena = (struct RA_ARENA *)data;
977
978         if (count < 80) {
979                 *start = (char *)0;
980                 return 0;
981         }
982         *eof = 0;
983         *start = (char *)1;
984         if (off == 0)
985                 return printAppend(page, count, 0,
986                         "Arena \"%s\"\nBase         Size Type Ref\n",
987                         pArena->name);
988         for (pBT = pArena->pHeadSegment; --off && pBT;
989              pBT = pBT->pNextSegment)
990                 ;
991         if (pBT)
992                 len = printAppend(page, count, 0, "%08x %8x %4s %08x\n",
993                                   (unsigned)pBT->base, (unsigned)pBT->uSize,
994                                   _BTType(pBT->type), (unsigned)pBT->psMapping);
995         else
996                 *eof = 1;
997         return len;
998 }
999
1000 static int RA_DumpInfo(char *page, char **start, off_t off, int count, int *eof,
1001             void *data)
1002 {
1003         int len = 0;
1004         struct RA_ARENA *pArena = (struct RA_ARENA *)data;
1005
1006         if (count < 80) {
1007                 *start = (char *)0;
1008                 return 0;
1009         }
1010         *eof = 0;
1011         switch (off) {
1012         case 0:
1013                 len = printAppend(page, count, 0, "quantum\t\t\t%u\n",
1014                                   pArena->uQuantum);
1015                 break;
1016         case 1:
1017                 len = printAppend(page, count, 0, "import_handle\t\t%08X\n",
1018                                 (unsigned)pArena->pImportHandle);
1019                 break;
1020 #ifdef RA_STATS
1021         case 2:
1022                 len = printAppend(page, count, 0, "span count\t\t%u\n",
1023                                 pArena->sStatistics.uSpanCount);
1024                 break;
1025         case 3:
1026                 len = printAppend(page, count, 0, "live segment count\t%u\n",
1027                                 pArena->sStatistics.uLiveSegmentCount);
1028                 break;
1029         case 4:
1030                 len = printAppend(page, count, 0, "free segment count\t%u\n",
1031                                 pArena->sStatistics.uFreeSegmentCount);
1032                 break;
1033         case 5:
1034                 len = printAppend(page, count, 0,
1035                                 "free resource count\t%u (0x%x)\n",
1036                                 pArena->sStatistics.uFreeResourceCount,
1037                                 (unsigned)pArena->sStatistics.
1038                                 uFreeResourceCount);
1039                 break;
1040         case 6:
1041                 len = printAppend(page, count, 0, "total allocs\t\t%u\n",
1042                                 pArena->sStatistics.uCumulativeAllocs);
1043                 break;
1044         case 7:
1045                 len = printAppend(page, count, 0, "total frees\t\t%u\n",
1046                                 pArena->sStatistics.uCumulativeFrees);
1047                 break;
1048         case 8:
1049                 len = printAppend(page, count, 0, "import count\t\t%u\n",
1050                                 pArena->sStatistics.uImportCount);
1051                 break;
1052         case 9:
1053                 len = printAppend(page, count, 0, "export count\t\t%u\n",
1054                                 pArena->sStatistics.uExportCount);
1055                 break;
1056 #endif
1057
1058         default:
1059                 *eof = 1;
1060         }
1061         *start = (char *)1;
1062         return len;
1063 }
1064 #endif
1065
1066 #ifdef RA_STATS
1067 enum PVRSRV_ERROR RA_GetStats(struct RA_ARENA *pArena, char **ppszStr,
1068                               u32 *pui32StrLen)
1069 {
1070         char *pszStr = *ppszStr;
1071         u32 ui32StrLen = *pui32StrLen;
1072         s32 i32Count;
1073         struct BT *pBT;
1074
1075         CHECK_SPACE(ui32StrLen);
1076         i32Count = OSSNPrintf(pszStr, 100, "\nArena '%s':\n", pArena->name);
1077         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1078
1079         CHECK_SPACE(ui32StrLen);
1080         i32Count = OSSNPrintf(pszStr, 100,
1081                        "  allocCB=%08X freeCB=%08X handle=%08X quantum=%d\n",
1082                        pArena->pImportAlloc, pArena->pImportFree,
1083                        pArena->pImportHandle, pArena->uQuantum);
1084         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1085
1086         CHECK_SPACE(ui32StrLen);
1087         i32Count = OSSNPrintf(pszStr, 100, "span count\t\t%lu\n",
1088                        pArena->sStatistics.uSpanCount);
1089         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1090
1091         CHECK_SPACE(ui32StrLen);
1092         i32Count = OSSNPrintf(pszStr, 100, "live segment count\t%lu\n",
1093                        pArena->sStatistics.uLiveSegmentCount);
1094         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1095
1096         CHECK_SPACE(ui32StrLen);
1097         i32Count = OSSNPrintf(pszStr, 100, "free segment count\t%lu\n",
1098                        pArena->sStatistics.uFreeSegmentCount);
1099         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1100
1101         CHECK_SPACE(ui32StrLen);
1102         i32Count = OSSNPrintf(pszStr, 100, "free resource count\t%lu (0x%x)\n",
1103                               pArena->sStatistics.uFreeResourceCount,
1104                               (unsigned)pArena->sStatistics.uFreeResourceCount);
1105         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1106
1107         CHECK_SPACE(ui32StrLen);
1108         i32Count = OSSNPrintf(pszStr, 100, "total allocs\t\t%lu\n",
1109                        pArena->sStatistics.uCumulativeAllocs);
1110         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1111
1112         CHECK_SPACE(ui32StrLen);
1113         i32Count = OSSNPrintf(pszStr, 100, "total frees\t\t%lu\n",
1114                        pArena->sStatistics.uCumulativeFrees);
1115         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1116
1117         CHECK_SPACE(ui32StrLen);
1118         i32Count = OSSNPrintf(pszStr, 100, "import count\t\t%lu\n",
1119                        pArena->sStatistics.uImportCount);
1120         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1121
1122         CHECK_SPACE(ui32StrLen);
1123         i32Count = OSSNPrintf(pszStr, 100, "export count\t\t%lu\n",
1124                        pArena->sStatistics.uExportCount);
1125         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1126
1127         CHECK_SPACE(ui32StrLen);
1128         i32Count = OSSNPrintf(pszStr, 100, "  segment Chain:\n");
1129         UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1130
1131         if (pArena->pHeadSegment != NULL &&
1132             pArena->pHeadSegment->pPrevSegment != NULL) {
1133                 CHECK_SPACE(ui32StrLen);
1134                 i32Count = OSSNPrintf(pszStr, 100,
1135                        "  error: head boundary tag has invalid pPrevSegment\n");
1136                 UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1137         }
1138
1139         if (pArena->pTailSegment != NULL &&
1140             pArena->pTailSegment->pNextSegment != NULL) {
1141                 CHECK_SPACE(ui32StrLen);
1142                 i32Count = OSSNPrintf(pszStr, 100,
1143                        "  error: tail boundary tag has invalid pNextSegment\n");
1144                 UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1145         }
1146
1147         for (pBT = pArena->pHeadSegment; pBT != NULL;
1148              pBT = pBT->pNextSegment) {
1149                 CHECK_SPACE(ui32StrLen);
1150                 i32Count = OSSNPrintf(pszStr, 100,
1151                                "\tbase=0x%x size=0x%x type=%s ref=%08X\n",
1152                                (u32) pBT->base, pBT->uSize, _BTType(pBT->type),
1153                                pBT->psMapping);
1154                 UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1155         }
1156
1157         *ppszStr = pszStr;
1158         *pui32StrLen = ui32StrLen;
1159
1160         return PVRSRV_OK;
1161 }
1162 #endif