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