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