]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_db.c
gpu: vivante: Update driver from Freescale 3.10.53-1.1-ga BSP
[karo-tx-linux.git] / drivers / mxc / gpu-viv / hal / kernel / gc_hal_kernel_db.c
1 /****************************************************************************
2 *
3 *    Copyright (C) 2005 - 2014 by Vivante Corp.
4 *
5 *    This program is free software; you can redistribute it and/or modify
6 *    it under the terms of the GNU General Public License as published by
7 *    the Free Software Foundation; either version 2 of the license, or
8 *    (at your option) any later version.
9 *
10 *    This program is distributed in the hope that it will be useful,
11 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 *    GNU General Public License for more details.
14 *
15 *    You should have received a copy of the GNU General Public License
16 *    along with this program; if not write to the Free Software
17 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 *****************************************************************************/
20
21
22 #include "gc_hal_kernel_precomp.h"
23
24 #define _GC_OBJ_ZONE    gcvZONE_DATABASE
25
26 /*******************************************************************************
27 ***** Private fuctions ********************************************************/
28
29 #define _GetSlot(database, x) \
30     (gctUINT32)(gcmPTR_TO_UINT64(x) % gcmCOUNTOF(database->list))
31
32 /*******************************************************************************
33 **  gckKERNEL_NewDatabase
34 **
35 **  Create a new database structure and insert it to the head of the hash list.
36 **
37 **  INPUT:
38 **
39 **      gckKERNEL Kernel
40 **          Pointer to a gckKERNEL object.
41 **
42 **      gctUINT32 ProcessID
43 **          ProcessID that identifies the database.
44 **
45 **  OUTPUT:
46 **
47 **      gcsDATABASE_PTR * Database
48 **          Pointer to a variable receiving the database structure pointer on
49 **          success.
50 */
51 static gceSTATUS
52 gckKERNEL_NewDatabase(
53     IN gckKERNEL Kernel,
54     IN gctUINT32 ProcessID,
55     OUT gcsDATABASE_PTR * Database
56     )
57 {
58     gceSTATUS status;
59     gcsDATABASE_PTR database;
60     gctBOOL acquired = gcvFALSE;
61     gctSIZE_T slot;
62     gcsDATABASE_PTR existingDatabase;
63
64     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
65
66     /* Acquire the database mutex. */
67     gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
68     acquired = gcvTRUE;
69
70     /* Compute the hash for the database. */
71     slot = ProcessID % gcmCOUNTOF(Kernel->db->db);
72
73     /* Walk the hash list. */
74     for (existingDatabase = Kernel->db->db[slot];
75          existingDatabase != gcvNULL;
76          existingDatabase = existingDatabase->next)
77     {
78         if (existingDatabase->processID == ProcessID)
79         {
80             /* One process can't be added twice. */
81             gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
82         }
83     }
84
85     if (Kernel->db->freeDatabase != gcvNULL)
86     {
87         /* Allocate a database from the free list. */
88         database             = Kernel->db->freeDatabase;
89         Kernel->db->freeDatabase = database->next;
90     }
91     else
92     {
93         gctPOINTER pointer = gcvNULL;
94
95         /* Allocate a new database from the heap. */
96         gcmkONERROR(gckOS_Allocate(Kernel->os,
97                                    gcmSIZEOF(gcsDATABASE),
98                                    &pointer));
99
100         gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsDATABASE));
101
102         database = pointer;
103
104         gcmkONERROR(gckOS_CreateMutex(Kernel->os, &database->counterMutex));
105     }
106
107     /* Insert the database into the hash. */
108     database->next   = Kernel->db->db[slot];
109     Kernel->db->db[slot] = database;
110
111     /* Save the hash slot. */
112     database->slot = slot;
113
114     /* Release the database mutex. */
115     gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
116
117     /* Return the database. */
118     *Database = database;
119
120     /* Success. */
121     gcmkFOOTER_ARG("*Database=0x%x", *Database);
122     return gcvSTATUS_OK;
123
124 OnError:
125     if (acquired)
126     {
127         /* Release the database mutex. */
128         gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
129     }
130
131     /* Return the status. */
132     gcmkFOOTER();
133     return status;
134 }
135
136 /*******************************************************************************
137 **  gckKERNEL_FindDatabase
138 **
139 **  Find a database identified by a process ID and move it to the head of the
140 **  hash list.
141 **
142 **  INPUT:
143 **
144 **      gckKERNEL Kernel
145 **          Pointer to a gckKERNEL object.
146 **
147 **      gctUINT32 ProcessID
148 **          ProcessID that identifies the database.
149 **
150 **      gctBOOL LastProcessID
151 **          gcvTRUE if searching for the last known process ID.  gcvFALSE if
152 **          we need to search for the process ID specified by the ProcessID
153 **          argument.
154 **
155 **  OUTPUT:
156 **
157 **      gcsDATABASE_PTR * Database
158 **          Pointer to a variable receiving the database structure pointer on
159 **          success.
160 */
161 gceSTATUS
162 gckKERNEL_FindDatabase(
163     IN gckKERNEL Kernel,
164     IN gctUINT32 ProcessID,
165     IN gctBOOL LastProcessID,
166     OUT gcsDATABASE_PTR * Database
167     )
168 {
169     gceSTATUS status;
170     gcsDATABASE_PTR database, previous;
171     gctSIZE_T slot;
172     gctBOOL acquired = gcvFALSE;
173
174     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d LastProcessID=%d",
175                    Kernel, ProcessID, LastProcessID);
176
177     /* Compute the hash for the database. */
178     slot = ProcessID % gcmCOUNTOF(Kernel->db->db);
179
180     /* Acquire the database mutex. */
181     gcmkONERROR(
182         gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
183     acquired = gcvTRUE;
184
185     /* Check whether we are getting the last known database. */
186     if (LastProcessID)
187     {
188         /* Use last database. */
189         database = Kernel->db->lastDatabase;
190
191         if (database == gcvNULL)
192         {
193             /* Database not found. */
194             gcmkONERROR(gcvSTATUS_INVALID_DATA);
195         }
196     }
197     else
198     {
199         /* Walk the hash list. */
200         for (previous = gcvNULL, database = Kernel->db->db[slot];
201              database != gcvNULL;
202              database = database->next)
203         {
204             if (database->processID == ProcessID)
205             {
206                 /* Found it! */
207                 break;
208             }
209
210             previous = database;
211         }
212
213         if (database == gcvNULL)
214         {
215             /* Database not found. */
216             gcmkONERROR(gcvSTATUS_INVALID_DATA);
217         }
218
219         if (previous != gcvNULL)
220         {
221             /* Move database to the head of the hash list. */
222             previous->next   = database->next;
223             database->next   = Kernel->db->db[slot];
224             Kernel->db->db[slot] = database;
225         }
226     }
227
228     /* Release the database mutex. */
229     gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
230
231     /* Return the database. */
232     *Database = database;
233
234     /* Success. */
235     gcmkFOOTER_ARG("*Database=0x%x", *Database);
236     return gcvSTATUS_OK;
237
238 OnError:
239     if (acquired)
240     {
241         /* Release the database mutex. */
242         gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
243     }
244
245     /* Return the status. */
246     gcmkFOOTER();
247     return status;
248 }
249
250 /*******************************************************************************
251 **  gckKERNEL_DeleteDatabase
252 **
253 **  Remove a database from the hash list and delete its structure.
254 **
255 **  INPUT:
256 **
257 **      gckKERNEL Kernel
258 **          Pointer to a gckKERNEL object.
259 **
260 **      gcsDATABASE_PTR Database
261 **          Pointer to the database structure to remove.
262 **
263 **  OUTPUT:
264 **
265 **      Nothing.
266 */
267 static gceSTATUS
268 gckKERNEL_DeleteDatabase(
269     IN gckKERNEL Kernel,
270     IN gcsDATABASE_PTR Database
271     )
272 {
273     gceSTATUS status;
274     gctBOOL acquired = gcvFALSE;
275     gcsDATABASE_PTR database;
276
277     gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database);
278
279     /* Acquire the database mutex. */
280     gcmkONERROR(
281         gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
282     acquired = gcvTRUE;
283
284     /* Check slot value. */
285     gcmkVERIFY_ARGUMENT(Database->slot < gcmCOUNTOF(Kernel->db->db));
286
287     if (Database->slot < gcmCOUNTOF(Kernel->db->db))
288     {
289         /* Check if database if the head of the hash list. */
290         if (Kernel->db->db[Database->slot] == Database)
291         {
292             /* Remove the database from the hash list. */
293             Kernel->db->db[Database->slot] = Database->next;
294         }
295         else
296         {
297             /* Walk the has list to find the database. */
298             for (database = Kernel->db->db[Database->slot];
299                  database != gcvNULL;
300                  database = database->next
301             )
302             {
303                 /* Check if the next list entry is this database. */
304                 if (database->next == Database)
305                 {
306                     /* Remove the database from the hash list. */
307                     database->next = Database->next;
308                     break;
309                 }
310             }
311
312             if (database == gcvNULL)
313             {
314                 /* Ouch!  Something got corrupted. */
315                 gcmkONERROR(gcvSTATUS_INVALID_DATA);
316             }
317         }
318     }
319
320     if (Kernel->db->lastDatabase != gcvNULL)
321     {
322         /* Insert database to the free list. */
323         Kernel->db->lastDatabase->next = Kernel->db->freeDatabase;
324         Kernel->db->freeDatabase       = Kernel->db->lastDatabase;
325     }
326
327     /* Keep database as the last database. */
328     Kernel->db->lastDatabase = Database;
329
330     /* Destory handle db. */
331     gcmkVERIFY_OK(gckKERNEL_DestroyIntegerDatabase(Kernel, Database->handleDatabase));
332     Database->handleDatabase = gcvNULL;
333     gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Database->handleDatabaseMutex));
334     Database->handleDatabaseMutex = gcvNULL;
335
336 #if gcdPROCESS_ADDRESS_SPACE
337     /* Destory process MMU. */
338     gcmkVERIFY_OK(gckEVENT_DestroyMmu(Kernel->eventObj, Database->mmu, gcvKERNEL_PIXEL));
339     Database->mmu = gcvNULL;
340 #endif
341
342     /* Release the database mutex. */
343     gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
344
345     /* Success. */
346     gcmkFOOTER_NO();
347     return gcvSTATUS_OK;
348
349 OnError:
350     if (acquired)
351     {
352         /* Release the database mutex. */
353         gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
354     }
355
356     /* Return the status. */
357     gcmkFOOTER();
358     return status;
359 }
360
361 /*******************************************************************************
362 **  gckKERNEL_NewRecord
363 **
364 **  Create a new database record structure and insert it to the head of the
365 **  database.
366 **
367 **  INPUT:
368 **
369 **      gckKERNEL Kernel
370 **          Pointer to a gckKERNEL object.
371 **
372 **      gcsDATABASE_PTR Database
373 **          Pointer to a database structure.
374 **
375 **  OUTPUT:
376 **
377 **      gcsDATABASE_RECORD_PTR * Record
378 **          Pointer to a variable receiving the database record structure
379 **          pointer on success.
380 */
381 static gceSTATUS
382 gckKERNEL_NewRecord(
383     IN gckKERNEL Kernel,
384     IN gcsDATABASE_PTR Database,
385     IN gctUINT32 Slot,
386     OUT gcsDATABASE_RECORD_PTR * Record
387     )
388 {
389     gceSTATUS status;
390     gctBOOL acquired = gcvFALSE;
391     gcsDATABASE_RECORD_PTR record = gcvNULL;
392
393     gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database);
394
395     /* Acquire the database mutex. */
396     gcmkONERROR(
397         gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
398     acquired = gcvTRUE;
399
400     if (Kernel->db->freeRecord != gcvNULL)
401     {
402         /* Allocate the record from the free list. */
403         record             = Kernel->db->freeRecord;
404         Kernel->db->freeRecord = record->next;
405     }
406     else
407     {
408         gctPOINTER pointer = gcvNULL;
409
410         /* Allocate the record from the heap. */
411         gcmkONERROR(gckOS_Allocate(Kernel->os,
412                                    gcmSIZEOF(gcsDATABASE_RECORD),
413                                    &pointer));
414
415         record = pointer;
416     }
417
418     /* Insert the record in the database. */
419     record->next         = Database->list[Slot];
420     Database->list[Slot] = record;
421
422     /* Release the database mutex. */
423     gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
424
425     /* Return the record. */
426     *Record = record;
427
428     /* Success. */
429     gcmkFOOTER_ARG("*Record=0x%x", *Record);
430     return gcvSTATUS_OK;
431
432 OnError:
433     if (acquired)
434     {
435         /* Release the database mutex. */
436         gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
437     }
438     if (record != gcvNULL)
439     {
440         gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record));
441     }
442
443     /* Return the status. */
444     gcmkFOOTER();
445     return status;
446 }
447
448 /*******************************************************************************
449 **  gckKERNEL_DeleteRecord
450 **
451 **  Remove a database record from the database and delete its structure.
452 **
453 **  INPUT:
454 **
455 **      gckKERNEL Kernel
456 **          Pointer to a gckKERNEL object.
457 **
458 **      gcsDATABASE_PTR Database
459 **          Pointer to a database structure.
460 **
461 **      gceDATABASE_TYPE Type
462 **          Type of the record to remove.
463 **
464 **      gctPOINTER Data
465 **          Data of the record to remove.
466 **
467 **  OUTPUT:
468 **
469 **      gctSIZE_T_PTR Bytes
470 **          Pointer to a variable that receives the size of the record deleted.
471 **          Can be gcvNULL if the size is not required.
472 */
473 static gceSTATUS
474 gckKERNEL_DeleteRecord(
475     IN gckKERNEL Kernel,
476     IN gcsDATABASE_PTR Database,
477     IN gceDATABASE_TYPE Type,
478     IN gctPOINTER Data,
479     OUT gctSIZE_T_PTR Bytes OPTIONAL
480     )
481 {
482     gceSTATUS status;
483     gctBOOL acquired = gcvFALSE;
484     gcsDATABASE_RECORD_PTR record, previous;
485     gctUINT32 slot = _GetSlot(Database, Data);
486
487     gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x",
488                    Kernel, Database, Type, Data);
489
490     /* Acquire the database mutex. */
491     gcmkONERROR(
492         gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
493     acquired = gcvTRUE;
494
495     /* Scan the database for this record. */
496     for (record = Database->list[slot], previous = gcvNULL;
497          record != gcvNULL;
498          record = record->next
499     )
500     {
501         if ((record->type == Type)
502         &&  (record->data == Data)
503         )
504         {
505             /* Found it! */
506             break;
507         }
508
509         previous = record;
510     }
511
512     if (record == gcvNULL)
513     {
514         /* Ouch!  This record is not found? */
515         gcmkONERROR(gcvSTATUS_INVALID_DATA);
516     }
517
518     if (Bytes != gcvNULL)
519     {
520         /* Return size of record. */
521         *Bytes = record->bytes;
522     }
523
524     /* Remove record from database. */
525     if (previous == gcvNULL)
526     {
527         Database->list[slot] = record->next;
528     }
529     else
530     {
531         previous->next = record->next;
532     }
533
534     /* Insert record in free list. */
535     record->next       = Kernel->db->freeRecord;
536     Kernel->db->freeRecord = record;
537
538     /* Release the database mutex. */
539     gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
540
541     /* Success. */
542     gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
543     return gcvSTATUS_OK;
544
545 OnError:
546     if (acquired)
547     {
548         /* Release the database mutex. */
549         gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
550     }
551
552     /* Return the status. */
553     gcmkFOOTER();
554     return status;
555 }
556
557 /*******************************************************************************
558 **  gckKERNEL_FindRecord
559 **
560 **  Find a database record from the database.
561 **
562 **  INPUT:
563 **
564 **      gckKERNEL Kernel
565 **          Pointer to a gckKERNEL object.
566 **
567 **      gcsDATABASE_PTR Database
568 **          Pointer to a database structure.
569 **
570 **      gceDATABASE_TYPE Type
571 **          Type of the record to remove.
572 **
573 **      gctPOINTER Data
574 **          Data of the record to remove.
575 **
576 **  OUTPUT:
577 **
578 **      gctSIZE_T_PTR Bytes
579 **          Pointer to a variable that receives the size of the record deleted.
580 **          Can be gcvNULL if the size is not required.
581 */
582 static gceSTATUS
583 gckKERNEL_FindRecord(
584     IN gckKERNEL Kernel,
585     IN gcsDATABASE_PTR Database,
586     IN gceDATABASE_TYPE Type,
587     IN gctPOINTER Data,
588     OUT gcsDATABASE_RECORD_PTR Record
589     )
590 {
591     gceSTATUS status;
592     gctBOOL acquired = gcvFALSE;
593     gcsDATABASE_RECORD_PTR record;
594     gctUINT32 slot = _GetSlot(Database, Data);
595
596     gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x",
597                    Kernel, Database, Type, Data);
598
599     /* Acquire the database mutex. */
600     gcmkONERROR(
601         gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
602     acquired = gcvTRUE;
603
604     /* Scan the database for this record. */
605     for (record = Database->list[slot];
606          record != gcvNULL;
607          record = record->next
608     )
609     {
610         if ((record->type == Type)
611         &&  (record->data == Data)
612         )
613         {
614             /* Found it! */
615             break;
616         }
617     }
618
619     if (record == gcvNULL)
620     {
621         /* Ouch!  This record is not found? */
622         gcmkONERROR(gcvSTATUS_INVALID_DATA);
623     }
624
625     if (Record != gcvNULL)
626     {
627         /* Return information of record. */
628         gcmkONERROR(
629             gckOS_MemCopy(Record, record, sizeof(gcsDATABASE_RECORD)));
630     }
631
632     /* Release the database mutex. */
633     gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
634
635     /* Success. */
636     gcmkFOOTER_ARG("Record=0x%x", Record);
637     return gcvSTATUS_OK;
638
639 OnError:
640     if (acquired)
641     {
642         /* Release the database mutex. */
643         gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
644     }
645
646     /* Return the status. */
647     gcmkFOOTER();
648     return status;
649 }
650
651 /*******************************************************************************
652 ***** Public API **************************************************************/
653
654 /*******************************************************************************
655 **  gckKERNEL_CreateProcessDB
656 **
657 **  Create a new process database.
658 **
659 **  INPUT:
660 **
661 **      gckKERNEL Kernel
662 **          Pointer to a gckKERNEL object.
663 **
664 **      gctUINT32 ProcessID
665 **          Process ID used to identify the database.
666 **
667 **  OUTPUT:
668 **
669 **      Nothing.
670 */
671 gceSTATUS
672 gckKERNEL_CreateProcessDB(
673     IN gckKERNEL Kernel,
674     IN gctUINT32 ProcessID
675     )
676 {
677     gceSTATUS status;
678     gcsDATABASE_PTR database = gcvNULL;
679     gctUINT32 i;
680
681     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
682
683     /* Verify the arguments. */
684     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
685
686     /* Create a new database. */
687     gcmkONERROR(gckKERNEL_NewDatabase(Kernel, ProcessID, &database));
688
689     /* Initialize the database. */
690     database->processID             = ProcessID;
691     database->vidMem.bytes          = 0;
692     database->vidMem.maxBytes       = 0;
693     database->vidMem.totalBytes     = 0;
694     database->nonPaged.bytes        = 0;
695     database->nonPaged.maxBytes     = 0;
696     database->nonPaged.totalBytes   = 0;
697     database->contiguous.bytes      = 0;
698     database->contiguous.maxBytes   = 0;
699     database->contiguous.totalBytes = 0;
700     database->mapMemory.bytes          = 0;
701     database->mapMemory.maxBytes       = 0;
702     database->mapMemory.totalBytes     = 0;
703     database->mapUserMemory.bytes      = 0;
704     database->mapUserMemory.maxBytes   = 0;
705     database->mapUserMemory.totalBytes = 0;
706     database->virtualCommandBuffer.bytes = 0;
707     database->virtualCommandBuffer.maxBytes = 0;
708     database->virtualCommandBuffer.totalBytes = 0;
709
710     for (i = 0; i < gcmCOUNTOF(database->list); i++)
711     {
712         database->list[i]              = gcvNULL;
713     }
714
715     for (i = 0; i < gcvSURF_NUM_TYPES; i++)
716     {
717         database->vidMemType[i].bytes = 0;
718         database->vidMemType[i].maxBytes = 0;
719         database->vidMemType[i].totalBytes = 0;
720     }
721
722     for (i = 0; i < gcvPOOL_NUMBER_OF_POOLS; i++)
723     {
724         database->vidMemPool[i].bytes = 0;
725         database->vidMemPool[i].maxBytes = 0;
726         database->vidMemPool[i].totalBytes = 0;
727     }
728
729     gcmkASSERT(database->handleDatabase == gcvNULL);
730     gcmkONERROR(
731         gckKERNEL_CreateIntegerDatabase(Kernel, &database->handleDatabase));
732
733     gcmkASSERT(database->handleDatabaseMutex == gcvNULL);
734     gcmkONERROR(
735         gckOS_CreateMutex(Kernel->os, &database->handleDatabaseMutex));
736
737 #if gcdPROCESS_ADDRESS_SPACE
738     gcmkASSERT(database->mmu == gcvNULL);
739     gcmkONERROR(
740         gckMMU_Construct(Kernel, gcdMMU_SIZE, &database->mmu));
741 #endif
742
743 #if gcdSECURE_USER
744     {
745         gctINT slot;
746         gcskSECURE_CACHE * cache = &database->cache;
747
748         /* Setup the linked list of cache nodes. */
749         for (slot = 1; slot <= gcdSECURE_CACHE_SLOTS; ++slot)
750         {
751             cache->cache[slot].logical = gcvNULL;
752
753 #if gcdSECURE_CACHE_METHOD != gcdSECURE_CACHE_TABLE
754             cache->cache[slot].prev = &cache->cache[slot - 1];
755             cache->cache[slot].next = &cache->cache[slot + 1];
756 #   endif
757 #if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
758             cache->cache[slot].nextHash = gcvNULL;
759             cache->cache[slot].prevHash = gcvNULL;
760 #   endif
761         }
762
763 #if gcdSECURE_CACHE_METHOD != gcdSECURE_CACHE_TABLE
764         /* Setup the head and tail of the cache. */
765         cache->cache[0].next    = &cache->cache[1];
766         cache->cache[0].prev    = &cache->cache[gcdSECURE_CACHE_SLOTS];
767         cache->cache[0].logical = gcvNULL;
768
769         /* Fix up the head and tail pointers. */
770         cache->cache[0].next->prev = &cache->cache[0];
771         cache->cache[0].prev->next = &cache->cache[0];
772 #   endif
773
774 #if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
775         /* Zero out the hash table. */
776         for (slot = 0; slot < gcmCOUNTOF(cache->hash); ++slot)
777         {
778             cache->hash[slot].logical  = gcvNULL;
779             cache->hash[slot].nextHash = gcvNULL;
780         }
781 #   endif
782
783         /* Initialize cache index. */
784         cache->cacheIndex = gcvNULL;
785         cache->cacheFree  = 1;
786         cache->cacheStamp = 0;
787     }
788 #endif
789
790     /* Reset idle timer. */
791     Kernel->db->lastIdle = 0;
792
793     /* Success. */
794     gcmkFOOTER_NO();
795     return gcvSTATUS_OK;
796
797 OnError:
798     /* Return the status. */
799     gcmkFOOTER();
800     return status;
801 }
802
803 /*******************************************************************************
804 **  gckKERNEL_AddProcessDB
805 **
806 **  Add a record to a process database.
807 **
808 **  INPUT:
809 **
810 **      gckKERNEL Kernel
811 **          Pointer to a gckKERNEL object.
812 **
813 **      gctUINT32 ProcessID
814 **          Process ID used to identify the database.
815 **
816 **      gceDATABASE_TYPE TYPE
817 **          Type of the record to add.
818 **
819 **      gctPOINTER Pointer
820 **          Data of the record to add.
821 **
822 **      gctPHYS_ADDR Physical
823 **          Physical address of the record to add.
824 **
825 **      gctSIZE_T Size
826 **          Size of the record to add.
827 **
828 **  OUTPUT:
829 **
830 **      Nothing.
831 */
832 gceSTATUS
833 gckKERNEL_AddProcessDB(
834     IN gckKERNEL Kernel,
835     IN gctUINT32 ProcessID,
836     IN gceDATABASE_TYPE Type,
837     IN gctPOINTER Pointer,
838     IN gctPHYS_ADDR Physical,
839     IN gctSIZE_T Size
840     )
841 {
842     gceSTATUS status;
843     gcsDATABASE_PTR database;
844     gcsDATABASE_RECORD_PTR record = gcvNULL;
845     gcsDATABASE_COUNTERS * count;
846     gctUINT32 vidMemType;
847     gcePOOL vidMemPool;
848
849     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x "
850                    "Physical=0x%x Size=%lu",
851                    Kernel, ProcessID, Type, Pointer, Physical, Size);
852
853     /* Verify the arguments. */
854     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
855
856     /* Decode type. */
857     vidMemType = (Type & gcdDB_VIDEO_MEMORY_TYPE_MASK) >> gcdDB_VIDEO_MEMORY_TYPE_SHIFT;
858     vidMemPool = (Type & gcdDB_VIDEO_MEMORY_POOL_MASK) >> gcdDB_VIDEO_MEMORY_POOL_SHIFT;
859
860     Type &= gcdDATABASE_TYPE_MASK;
861
862     /* Special case the idle record. */
863     if (Type == gcvDB_IDLE)
864     {
865         gctUINT64 time;
866
867         /* Get the current profile time. */
868         gcmkONERROR(gckOS_GetProfileTick(&time));
869
870         if ((ProcessID == 0) && (Kernel->db->lastIdle != 0))
871         {
872             /* Out of idle, adjust time it was idle. */
873             Kernel->db->idleTime += time - Kernel->db->lastIdle;
874             Kernel->db->lastIdle  = 0;
875         }
876         else if (ProcessID == 1)
877         {
878             /* Save current idle time. */
879             Kernel->db->lastIdle = time;
880         }
881
882 #if gcdDYNAMIC_SPEED
883         {
884             /* Test for first call. */
885             if (Kernel->db->lastSlowdown == 0)
886             {
887                 /* Save milliseconds. */
888                 Kernel->db->lastSlowdown     = time;
889                 Kernel->db->lastSlowdownIdle = Kernel->db->idleTime;
890             }
891             else
892             {
893                 /* Compute ellapsed time in milliseconds. */
894                 gctUINT delta = gckOS_ProfileToMS(time - Kernel->db->lastSlowdown);
895
896                 /* Test for end of period. */
897                 if (delta >= gcdDYNAMIC_SPEED)
898                 {
899                     /* Compute number of idle milliseconds. */
900                     gctUINT idle = gckOS_ProfileToMS(
901                         Kernel->db->idleTime  - Kernel->db->lastSlowdownIdle);
902
903                     /* Broadcast to slow down the GPU. */
904                     gcmkONERROR(gckOS_BroadcastCalibrateSpeed(Kernel->os,
905                                                               Kernel->hardware,
906                                                               idle,
907                                                               delta));
908
909                     /* Save current time. */
910                     Kernel->db->lastSlowdown     = time;
911                     Kernel->db->lastSlowdownIdle = Kernel->db->idleTime;
912                 }
913             }
914         }
915 #endif
916
917         /* Success. */
918         gcmkFOOTER_NO();
919         return gcvSTATUS_OK;
920     }
921
922     /* Verify the arguments. */
923     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
924
925     /* Find the database. */
926     gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
927
928     /* Create a new record in the database. */
929     gcmkONERROR(gckKERNEL_NewRecord(Kernel, database, _GetSlot(database, Pointer), &record));
930
931     /* Initialize the record. */
932     record->kernel   = Kernel;
933     record->type     = Type;
934     record->data     = Pointer;
935     record->physical = Physical;
936     record->bytes    = Size;
937
938     /* Get pointer to counters. */
939     switch (Type)
940     {
941     case gcvDB_VIDEO_MEMORY:
942         count = &database->vidMem;
943         break;
944
945     case gcvDB_NON_PAGED:
946         count = &database->nonPaged;
947         break;
948
949     case gcvDB_CONTIGUOUS:
950         count = &database->contiguous;
951         break;
952
953     case gcvDB_MAP_MEMORY:
954         count = &database->mapMemory;
955         break;
956
957     case gcvDB_MAP_USER_MEMORY:
958         count = &database->mapUserMemory;
959         break;
960
961     case gcvDB_COMMAND_BUFFER:
962         count = &database->virtualCommandBuffer;
963         break;
964
965     default:
966         count = gcvNULL;
967         break;
968     }
969
970     gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE));
971
972     if (count != gcvNULL)
973     {
974         /* Adjust counters. */
975         count->totalBytes += Size;
976         count->bytes      += Size;
977
978         if (count->bytes > count->maxBytes)
979         {
980             count->maxBytes = count->bytes;
981         }
982     }
983
984     if (Type == gcvDB_VIDEO_MEMORY)
985     {
986         count = &database->vidMemType[vidMemType];
987
988         /* Adjust counters. */
989         count->totalBytes += Size;
990         count->bytes      += Size;
991
992         if (count->bytes > count->maxBytes)
993         {
994             count->maxBytes = count->bytes;
995         }
996
997         count = &database->vidMemPool[vidMemPool];
998
999         /* Adjust counters. */
1000         count->totalBytes += Size;
1001         count->bytes      += Size;
1002
1003         if (count->bytes > count->maxBytes)
1004         {
1005             count->maxBytes = count->bytes;
1006         }
1007     }
1008
1009     gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex));
1010
1011     /* Success. */
1012     gcmkFOOTER_NO();
1013     return gcvSTATUS_OK;
1014
1015 OnError:
1016     /* Return the status. */
1017     gcmkFOOTER();
1018     return status;
1019 }
1020
1021 /*******************************************************************************
1022 **  gckKERNEL_RemoveProcessDB
1023 **
1024 **  Remove a record from a process database.
1025 **
1026 **  INPUT:
1027 **
1028 **      gckKERNEL Kernel
1029 **          Pointer to a gckKERNEL object.
1030 **
1031 **      gctUINT32 ProcessID
1032 **          Process ID used to identify the database.
1033 **
1034 **      gceDATABASE_TYPE TYPE
1035 **          Type of the record to remove.
1036 **
1037 **      gctPOINTER Pointer
1038 **          Data of the record to remove.
1039 **
1040 **  OUTPUT:
1041 **
1042 **      Nothing.
1043 */
1044 gceSTATUS
1045 gckKERNEL_RemoveProcessDB(
1046     IN gckKERNEL Kernel,
1047     IN gctUINT32 ProcessID,
1048     IN gceDATABASE_TYPE Type,
1049     IN gctPOINTER Pointer
1050     )
1051 {
1052     gceSTATUS status;
1053     gcsDATABASE_PTR database;
1054     gctSIZE_T bytes = 0;
1055     gctUINT32 vidMemType;
1056     gcePOOL vidMempool;
1057
1058     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x",
1059                    Kernel, ProcessID, Type, Pointer);
1060
1061     /* Verify the arguments. */
1062     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1063     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
1064
1065     /* Decode type. */
1066     vidMemType = (Type & gcdDB_VIDEO_MEMORY_TYPE_MASK) >> gcdDB_VIDEO_MEMORY_TYPE_SHIFT;
1067     vidMempool = (Type & gcdDB_VIDEO_MEMORY_POOL_MASK) >> gcdDB_VIDEO_MEMORY_POOL_SHIFT;
1068
1069     Type &= gcdDATABASE_TYPE_MASK;
1070
1071     /* Find the database. */
1072     gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1073
1074     /* Delete the record. */
1075     gcmkONERROR(
1076         gckKERNEL_DeleteRecord(Kernel, database, Type, Pointer, &bytes));
1077
1078     gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE));
1079
1080     /* Update counters. */
1081     switch (Type)
1082     {
1083     case gcvDB_VIDEO_MEMORY:
1084         database->vidMem.bytes -= bytes;
1085         database->vidMemType[vidMemType].bytes -= bytes;
1086         database->vidMemPool[vidMempool].bytes -= bytes;
1087         break;
1088
1089     case gcvDB_NON_PAGED:
1090         database->nonPaged.bytes -= bytes;
1091         break;
1092
1093     case gcvDB_CONTIGUOUS:
1094         database->contiguous.bytes -= bytes;
1095         break;
1096
1097     case gcvDB_MAP_MEMORY:
1098         database->mapMemory.bytes -= bytes;
1099         break;
1100
1101     case gcvDB_MAP_USER_MEMORY:
1102         database->mapUserMemory.bytes -= bytes;
1103         break;
1104
1105     case gcvDB_COMMAND_BUFFER:
1106         database->virtualCommandBuffer.bytes -= bytes;
1107         break;
1108
1109     default:
1110         break;
1111     }
1112
1113     gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex));
1114
1115     /* Success. */
1116     gcmkFOOTER_NO();
1117     return gcvSTATUS_OK;
1118
1119 OnError:
1120     /* Return the status. */
1121     gcmkFOOTER();
1122     return status;
1123 }
1124
1125 /*******************************************************************************
1126 **  gckKERNEL_FindProcessDB
1127 **
1128 **  Find a record from a process database.
1129 **
1130 **  INPUT:
1131 **
1132 **      gckKERNEL Kernel
1133 **          Pointer to a gckKERNEL object.
1134 **
1135 **      gctUINT32 ProcessID
1136 **          Process ID used to identify the database.
1137 **
1138 **      gceDATABASE_TYPE TYPE
1139 **          Type of the record to remove.
1140 **
1141 **      gctPOINTER Pointer
1142 **          Data of the record to remove.
1143 **
1144 **  OUTPUT:
1145 **
1146 **      gcsDATABASE_RECORD_PTR Record
1147 **          Copy of record.
1148 */
1149 gceSTATUS
1150 gckKERNEL_FindProcessDB(
1151     IN gckKERNEL Kernel,
1152     IN gctUINT32 ProcessID,
1153     IN gctUINT32 ThreadID,
1154     IN gceDATABASE_TYPE Type,
1155     IN gctPOINTER Pointer,
1156     OUT gcsDATABASE_RECORD_PTR Record
1157     )
1158 {
1159     gceSTATUS status;
1160     gcsDATABASE_PTR database;
1161
1162     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x",
1163                    Kernel, ProcessID, ThreadID, Type, Pointer);
1164
1165     /* Verify the arguments. */
1166     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1167     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
1168
1169     /* Find the database. */
1170     gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1171
1172     /* Find the record. */
1173     gcmkONERROR(
1174         gckKERNEL_FindRecord(Kernel, database, Type, Pointer, Record));
1175
1176     /* Success. */
1177     gcmkFOOTER_NO();
1178     return gcvSTATUS_OK;
1179
1180 OnError:
1181     /* Return the status. */
1182     gcmkFOOTER();
1183     return status;
1184 }
1185
1186 /*******************************************************************************
1187 **  gckKERNEL_DestroyProcessDB
1188 **
1189 **  Destroy a process database.  If the database contains any records, the data
1190 **  inside those records will be deleted as well.  This aids in the cleanup if
1191 **  a process has died unexpectedly or has memory leaks.
1192 **
1193 **  INPUT:
1194 **
1195 **      gckKERNEL Kernel
1196 **          Pointer to a gckKERNEL object.
1197 **
1198 **      gctUINT32 ProcessID
1199 **          Process ID used to identify the database.
1200 **
1201 **  OUTPUT:
1202 **
1203 **      Nothing.
1204 */
1205 gceSTATUS
1206 gckKERNEL_DestroyProcessDB(
1207     IN gckKERNEL Kernel,
1208     IN gctUINT32 ProcessID
1209     )
1210 {
1211     gceSTATUS status;
1212     gcsDATABASE_PTR database;
1213     gcsDATABASE_RECORD_PTR record, next;
1214     gctBOOL asynchronous = gcvTRUE;
1215     gckVIDMEM_NODE nodeObject;
1216     gctPHYS_ADDR physical;
1217     gckKERNEL kernel = Kernel;
1218     gctUINT32 handle;
1219     gctUINT32 i;
1220
1221     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
1222
1223     /* Verify the arguments. */
1224     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1225
1226     /* Find the database. */
1227     gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1228
1229     gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1230                    "DB(%d): VidMem: total=%lu max=%lu",
1231                    ProcessID, database->vidMem.totalBytes,
1232                    database->vidMem.maxBytes);
1233     gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1234                    "DB(%d): NonPaged: total=%lu max=%lu",
1235                    ProcessID, database->nonPaged.totalBytes,
1236                    database->nonPaged.maxBytes);
1237     gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1238                    "DB(%d): Contiguous: total=%lu max=%lu",
1239                    ProcessID, database->contiguous.totalBytes,
1240                    database->contiguous.maxBytes);
1241     gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1242                    "DB(%d): Idle time=%llu",
1243                    ProcessID, Kernel->db->idleTime);
1244     gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1245                    "DB(%d): Map: total=%lu max=%lu",
1246                    ProcessID, database->mapMemory.totalBytes,
1247                    database->mapMemory.maxBytes);
1248     gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1249                    "DB(%d): Map: total=%lu max=%lu",
1250                    ProcessID, database->mapUserMemory.totalBytes,
1251                    database->mapUserMemory.maxBytes);
1252
1253     if (database->list != gcvNULL)
1254     {
1255         gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1256                        "Process %d has entries in its database:",
1257                        ProcessID);
1258     }
1259
1260     for(i = 0; i < gcmCOUNTOF(database->list); i++)
1261     {
1262
1263     /* Walk all records. */
1264     for (record = database->list[i]; record != gcvNULL; record = next)
1265     {
1266         /* Next next record. */
1267         next = record->next;
1268
1269         /* Dispatch on record type. */
1270         switch (record->type)
1271         {
1272         case gcvDB_VIDEO_MEMORY:
1273             gcmkERR_BREAK(gckVIDMEM_HANDLE_Lookup(record->kernel,
1274                                                   ProcessID,
1275                                                   gcmPTR2INT32(record->data),
1276                                                   &nodeObject));
1277
1278             /* Free the video memory. */
1279             gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel,
1280                                                        ProcessID,
1281                                                        gcmPTR2INT32(record->data)));
1282
1283             gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel,
1284                                                      nodeObject));
1285
1286             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1287                            "DB: VIDEO_MEMORY 0x%x (status=%d)",
1288                            record->data, status);
1289             break;
1290
1291         case gcvDB_NON_PAGED:
1292             physical = gcmNAME_TO_PTR(record->physical);
1293             /* Unmap user logical memory first. */
1294             status = gckOS_UnmapUserLogical(Kernel->os,
1295                                             physical,
1296                                             record->bytes,
1297                                             record->data);
1298
1299             /* Free the non paged memory. */
1300             status = gckEVENT_FreeNonPagedMemory(Kernel->eventObj,
1301                                                  record->bytes,
1302                                                  physical,
1303                                                  record->data,
1304                                                  gcvKERNEL_PIXEL);
1305             gcmRELEASE_NAME(record->physical);
1306
1307             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1308                            "DB: NON_PAGED 0x%x, bytes=%lu (status=%d)",
1309                            record->data, record->bytes, status);
1310             break;
1311
1312         case gcvDB_COMMAND_BUFFER:
1313             /* Free the command buffer. */
1314             status = gckEVENT_DestroyVirtualCommandBuffer(record->kernel->eventObj,
1315                                                           record->bytes,
1316                                                           gcmNAME_TO_PTR(record->physical),
1317                                                           record->data,
1318                                                           gcvKERNEL_PIXEL);
1319             gcmRELEASE_NAME(record->physical);
1320
1321             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1322                            "DB: COMMAND_BUFFER 0x%x, bytes=%lu (status=%d)",
1323                            record->data, record->bytes, status);
1324             break;
1325
1326         case gcvDB_CONTIGUOUS:
1327             physical = gcmNAME_TO_PTR(record->physical);
1328             /* Unmap user logical memory first. */
1329             status = gckOS_UnmapUserLogical(Kernel->os,
1330                                             physical,
1331                                             record->bytes,
1332                                             record->data);
1333
1334             /* Free the contiguous memory. */
1335             status = gckEVENT_FreeContiguousMemory(Kernel->eventObj,
1336                                                    record->bytes,
1337                                                    physical,
1338                                                    record->data,
1339                                                    gcvKERNEL_PIXEL);
1340             gcmRELEASE_NAME(record->physical);
1341
1342             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1343                            "DB: CONTIGUOUS 0x%x bytes=%lu (status=%d)",
1344                            record->data, record->bytes, status);
1345             break;
1346
1347         case gcvDB_SIGNAL:
1348 #if USE_NEW_LINUX_SIGNAL
1349             status = gcvSTATUS_NOT_SUPPORTED;
1350 #else
1351             /* Free the user signal. */
1352             status = gckOS_DestroyUserSignal(Kernel->os,
1353                                              gcmPTR2INT32(record->data));
1354 #endif /* USE_NEW_LINUX_SIGNAL */
1355
1356             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1357                            "DB: SIGNAL %d (status=%d)",
1358                            (gctINT)(gctUINTPTR_T)record->data, status);
1359             break;
1360
1361         case gcvDB_VIDEO_MEMORY_LOCKED:
1362             handle = gcmPTR2INT32(record->data);
1363
1364             gcmkERR_BREAK(gckVIDMEM_HANDLE_Lookup(record->kernel,
1365                                                   ProcessID,
1366                                                   handle,
1367                                                   &nodeObject));
1368
1369             /* Unlock what we still locked */
1370             status = gckVIDMEM_Unlock(record->kernel,
1371                                       nodeObject,
1372                                       nodeObject->type,
1373                                       &asynchronous);
1374
1375 #if gcdENABLE_VG
1376             if (record->kernel->core == gcvCORE_VG)
1377             {
1378                 if (gcmIS_SUCCESS(status) && (gcvTRUE == asynchronous))
1379                 {
1380                     /* TODO: we maybe need to schedule a event here */
1381                     status = gckVIDMEM_Unlock(record->kernel,
1382                                               nodeObject,
1383                                               nodeObject->type,
1384                                               gcvNULL);
1385                 }
1386
1387                 gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel,
1388                                                            ProcessID,
1389                                                            handle));
1390
1391                 gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel,
1392                                                          nodeObject));
1393             }
1394             else
1395 #endif
1396             {
1397                 gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel,
1398                                                            ProcessID,
1399                                                            handle));
1400
1401                 if (gcmIS_SUCCESS(status) && (gcvTRUE == asynchronous))
1402                 {
1403                     status = gckEVENT_Unlock(record->kernel->eventObj,
1404                                              gcvKERNEL_PIXEL,
1405                                              nodeObject,
1406                                              nodeObject->type);
1407                 }
1408                 else
1409                 {
1410                     gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel,
1411                                                              nodeObject));
1412                 }
1413             }
1414
1415             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1416                            "DB: VIDEO_MEMORY_LOCKED 0x%x (status=%d)",
1417                            record->data, status);
1418             break;
1419
1420         case gcvDB_CONTEXT:
1421             /* TODO: Free the context */
1422             status = gckCOMMAND_Detach(Kernel->command, gcmNAME_TO_PTR(record->data));
1423             gcmRELEASE_NAME(record->data);
1424
1425             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1426                            "DB: CONTEXT 0x%x (status=%d)",
1427                            record->data, status);
1428             break;
1429
1430         case gcvDB_MAP_MEMORY:
1431             /* Unmap memory. */
1432             status = gckKERNEL_UnmapMemory(Kernel,
1433                                            record->physical,
1434                                            record->bytes,
1435                                            record->data);
1436
1437             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1438                            "DB: MAP MEMORY %d (status=%d)",
1439                            gcmPTR2INT32(record->data), status);
1440             break;
1441
1442         case gcvDB_MAP_USER_MEMORY:
1443             /* TODO: Unmap user memory. */
1444             status = gckOS_UnmapUserMemory(Kernel->os,
1445                                            Kernel->core,
1446                                            record->physical,
1447                                            record->bytes,
1448                                            gcmNAME_TO_PTR(record->data),
1449                                            0);
1450             gcmRELEASE_NAME(record->data);
1451
1452             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1453                            "DB: MAP USER MEMORY %d (status=%d)",
1454                            gcmPTR2INT32(record->data), status);
1455             break;
1456
1457 #if gcdANDROID_NATIVE_FENCE_SYNC
1458         case gcvDB_SYNC_POINT:
1459             /* Free the user signal. */
1460             status = gckOS_DestroySyncPoint(Kernel->os,
1461                                             (gctSYNC_POINT) record->data);
1462
1463             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1464                            "DB: SYNC POINT %d (status=%d)",
1465                            (gctINT)(gctUINTPTR_T)record->data, status);
1466             break;
1467 #endif
1468
1469         case gcvDB_SHBUF:
1470             /* Free shared buffer. */
1471             status = gckKERNEL_DestroyShBuffer(Kernel,
1472                                                (gctSHBUF) record->data);
1473
1474             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1475                            "DB: SHBUF %u (status=%d)",
1476                            (gctUINT32)(gctUINTPTR_T) record->data, status);
1477             break;
1478
1479         default:
1480             gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DATABASE,
1481                            "DB: Correcupted record=0x%08x type=%d",
1482                            record, record->type);
1483             break;
1484         }
1485
1486         /* Delete the record. */
1487         gcmkONERROR(gckKERNEL_DeleteRecord(Kernel,
1488                                            database,
1489                                            record->type,
1490                                            record->data,
1491                                            gcvNULL));
1492     }
1493
1494     }
1495
1496     /* Delete the database. */
1497     gcmkONERROR(gckKERNEL_DeleteDatabase(Kernel, database));
1498
1499     /* Success. */
1500     gcmkFOOTER_NO();
1501     return gcvSTATUS_OK;
1502
1503 OnError:
1504     /* Return the status. */
1505     gcmkFOOTER();
1506     return status;
1507 }
1508
1509 /*******************************************************************************
1510 **  gckKERNEL_QueryProcessDB
1511 **
1512 **  Query a process database for the current usage of a particular record type.
1513 **
1514 **  INPUT:
1515 **
1516 **      gckKERNEL Kernel
1517 **          Pointer to a gckKERNEL object.
1518 **
1519 **      gctUINT32 ProcessID
1520 **          Process ID used to identify the database.
1521 **
1522 **      gctBOOL LastProcessID
1523 **          gcvTRUE if searching for the last known process ID.  gcvFALSE if
1524 **          we need to search for the process ID specified by the ProcessID
1525 **          argument.
1526 **
1527 **      gceDATABASE_TYPE Type
1528 **          Type of the record to query.
1529 **
1530 **  OUTPUT:
1531 **
1532 **      gcuDATABASE_INFO * Info
1533 **          Pointer to a variable that receives the requested information.
1534 */
1535 gceSTATUS
1536 gckKERNEL_QueryProcessDB(
1537     IN gckKERNEL Kernel,
1538     IN gctUINT32 ProcessID,
1539     IN gctBOOL LastProcessID,
1540     IN gceDATABASE_TYPE Type,
1541     OUT gcuDATABASE_INFO * Info
1542     )
1543 {
1544     gceSTATUS status;
1545     gcsDATABASE_PTR database;
1546     gcePOOL vidMemPool;
1547
1548     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Info=0x%x",
1549                    Kernel, ProcessID, Type, Info);
1550
1551     /* Verify the arguments. */
1552     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1553     gcmkVERIFY_ARGUMENT(Info != gcvNULL);
1554
1555     /* Deocde pool. */
1556     vidMemPool = (Type & gcdDB_VIDEO_MEMORY_POOL_MASK) >> gcdDB_VIDEO_MEMORY_POOL_SHIFT;
1557
1558     Type &= gcdDATABASE_TYPE_MASK;
1559
1560     /* Find the database. */
1561     if(Type != gcvDB_IDLE)
1562     {
1563         gcmkONERROR(
1564             gckKERNEL_FindDatabase(Kernel, ProcessID, LastProcessID, &database));
1565
1566         gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE));
1567
1568         /* Get pointer to counters. */
1569         switch (Type)
1570         {
1571         case gcvDB_VIDEO_MEMORY:
1572             if (vidMemPool != gcvPOOL_UNKNOWN)
1573             {
1574                 gckOS_MemCopy(&Info->counters,
1575                               &database->vidMemPool[vidMemPool],
1576                               gcmSIZEOF(database->vidMemPool[vidMemPool]));
1577             }
1578             else
1579             {
1580                 gckOS_MemCopy(&Info->counters,
1581                               &database->vidMem,
1582                               gcmSIZEOF(database->vidMem));
1583             }
1584             break;
1585
1586         case gcvDB_NON_PAGED:
1587             gckOS_MemCopy(&Info->counters,
1588                                       &database->nonPaged,
1589                                       gcmSIZEOF(database->vidMem));
1590             break;
1591
1592         case gcvDB_CONTIGUOUS:
1593             gckOS_MemCopy(&Info->counters,
1594                                       &database->contiguous,
1595                                       gcmSIZEOF(database->vidMem));
1596             break;
1597
1598         case gcvDB_MAP_MEMORY:
1599             gckOS_MemCopy(&Info->counters,
1600                                       &database->mapMemory,
1601                                       gcmSIZEOF(database->mapMemory));
1602             break;
1603
1604         case gcvDB_MAP_USER_MEMORY:
1605             gckOS_MemCopy(&Info->counters,
1606                                       &database->mapUserMemory,
1607                                       gcmSIZEOF(database->mapUserMemory));
1608             break;
1609
1610         case gcvDB_COMMAND_BUFFER:
1611             gckOS_MemCopy(&Info->counters,
1612                                       &database->virtualCommandBuffer,
1613                                       gcmSIZEOF(database->virtualCommandBuffer));
1614             break;
1615
1616         default:
1617             break;
1618         }
1619
1620         gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex));
1621     }
1622     else
1623     {
1624         Info->time           = Kernel->db->idleTime;
1625         Kernel->db->idleTime = 0;
1626     }
1627     /* Success. */
1628     gcmkFOOTER_NO();
1629     return gcvSTATUS_OK;
1630
1631 OnError:
1632     /* Return the status. */
1633     gcmkFOOTER();
1634     return status;
1635 }
1636
1637 gceSTATUS
1638 gckKERNEL_FindHandleDatbase(
1639     IN gckKERNEL Kernel,
1640     IN gctUINT32 ProcessID,
1641     OUT gctPOINTER * HandleDatabase,
1642     OUT gctPOINTER * HandleDatabaseMutex
1643     )
1644 {
1645     gceSTATUS status;
1646     gcsDATABASE_PTR database;
1647
1648     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d",
1649                    Kernel, ProcessID);
1650
1651     /* Verify the arguments. */
1652     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1653
1654     /* Find the database. */
1655     gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1656
1657     *HandleDatabase = database->handleDatabase;
1658     *HandleDatabaseMutex = database->handleDatabaseMutex;
1659
1660     /* Success. */
1661     gcmkFOOTER_NO();
1662     return gcvSTATUS_OK;
1663
1664 OnError:
1665     /* Return the status. */
1666     gcmkFOOTER();
1667     return status;
1668 }
1669
1670 #if gcdPROCESS_ADDRESS_SPACE
1671 gceSTATUS
1672 gckKERNEL_GetProcessMMU(
1673     IN gckKERNEL Kernel,
1674     OUT gckMMU * Mmu
1675     )
1676 {
1677     gceSTATUS status;
1678     gcsDATABASE_PTR database;
1679     gctUINT32 processID;
1680
1681     gcmkONERROR(gckOS_GetProcessID(&processID));
1682
1683     gcmkONERROR(gckKERNEL_FindDatabase(Kernel, processID, gcvFALSE, &database));
1684
1685     *Mmu = database->mmu;
1686
1687     return gcvSTATUS_OK;
1688
1689 OnError:
1690     return status;
1691 }
1692 #endif
1693
1694 #if gcdSECURE_USER
1695 /*******************************************************************************
1696 **  gckKERNEL_GetProcessDBCache
1697 **
1698 **  Get teh secure cache from a process database.
1699 **
1700 **  INPUT:
1701 **
1702 **      gckKERNEL Kernel
1703 **          Pointer to a gckKERNEL object.
1704 **
1705 **      gctUINT32 ProcessID
1706 **          Process ID used to identify the database.
1707 **
1708 **  OUTPUT:
1709 **
1710 **      gcskSECURE_CACHE_PTR * Cache
1711 **          Pointer to a variable that receives the secure cache pointer.
1712 */
1713 gceSTATUS
1714 gckKERNEL_GetProcessDBCache(
1715     IN gckKERNEL Kernel,
1716     IN gctUINT32 ProcessID,
1717     OUT gcskSECURE_CACHE_PTR * Cache
1718     )
1719 {
1720     gceSTATUS status;
1721     gcsDATABASE_PTR database;
1722
1723     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
1724
1725     /* Verify the arguments. */
1726     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1727     gcmkVERIFY_ARGUMENT(Cache != gcvNULL);
1728
1729     /* Find the database. */
1730     gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1731
1732     /* Return the pointer to the cache. */
1733     *Cache = &database->cache;
1734
1735     /* Success. */
1736     gcmkFOOTER_ARG("*Cache=0x%x", *Cache);
1737     return gcvSTATUS_OK;
1738
1739 OnError:
1740     /* Return the status. */
1741     gcmkFOOTER();
1742     return status;
1743 }
1744 #endif
1745
1746 gceSTATUS
1747 gckKERNEL_DumpProcessDB(
1748     IN gckKERNEL Kernel
1749     )
1750 {
1751     gcsDATABASE_PTR database;
1752     gctINT i, pid;
1753     gctUINT8 name[24];
1754
1755     gcmkHEADER_ARG("Kernel=0x%x", Kernel);
1756
1757     /* Acquire the database mutex. */
1758     gcmkVERIFY_OK(
1759         gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
1760
1761     gcmkPRINT("**************************\n");
1762     gcmkPRINT("***  PROCESS DB DUMP   ***\n");
1763     gcmkPRINT("**************************\n");
1764
1765     gcmkPRINT_N(8, "%-8s%s\n", "PID", "NAME");
1766     /* Walk the databases. */
1767     for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i)
1768     {
1769         for (database = Kernel->db->db[i];
1770              database != gcvNULL;
1771              database = database->next)
1772         {
1773             pid = database->processID;
1774
1775             gcmkVERIFY_OK(gckOS_ZeroMemory(name, gcmSIZEOF(name)));
1776
1777             gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name));
1778
1779             gcmkPRINT_N(8, "%-8d%s\n", pid, name);
1780         }
1781     }
1782
1783     /* Release the database mutex. */
1784     gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
1785
1786     /* Success. */
1787     gcmkFOOTER_NO();
1788     return gcvSTATUS_OK;
1789 }
1790
1791 void
1792 _DumpCounter(
1793     IN gcsDATABASE_COUNTERS * Counter,
1794     IN gctCONST_STRING Name
1795     )
1796 {
1797     gcmkPRINT("%s:", Name);
1798     gcmkPRINT("  Currently allocated : %10lld", Counter->bytes);
1799     gcmkPRINT("  Maximum allocated   : %10lld", Counter->maxBytes);
1800     gcmkPRINT("  Total allocated     : %10lld", Counter->totalBytes);
1801 }
1802
1803 gceSTATUS
1804 gckKERNEL_DumpVidMemUsage(
1805     IN gckKERNEL Kernel,
1806     IN gctINT32 ProcessID
1807     )
1808 {
1809     gceSTATUS status;
1810     gcsDATABASE_PTR database;
1811     gcsDATABASE_COUNTERS * counter;
1812     gctUINT32 i = 0;
1813
1814     static gctCONST_STRING surfaceTypes[] = {
1815         "UNKNOWN",
1816         "INDEX",
1817         "VERTEX",
1818         "TEXTURE",
1819         "RENDER_TARGET",
1820         "DEPTH",
1821         "BITMAP",
1822         "TILE_STATUS",
1823         "IMAGE",
1824         "MASK",
1825         "SCISSOR",
1826         "HIERARCHICAL_DEPTH",
1827     };
1828
1829     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d",
1830                    Kernel, ProcessID);
1831
1832     /* Verify the arguments. */
1833     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1834
1835     /* Find the database. */
1836     gcmkONERROR(
1837         gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1838
1839     gcmkPRINT("VidMem Usage (Process %d):", ProcessID);
1840
1841     /* Get pointer to counters. */
1842     counter = &database->vidMem;
1843
1844     _DumpCounter(counter, "Total Video Memory");
1845
1846     for (i = 0; i < gcvSURF_NUM_TYPES; i++)
1847     {
1848         counter = &database->vidMemType[i];
1849
1850         _DumpCounter(counter, surfaceTypes[i]);
1851     }
1852
1853     /* Success. */
1854     gcmkFOOTER_NO();
1855     return gcvSTATUS_OK;
1856
1857 OnError:
1858     /* Return the status. */
1859     gcmkFOOTER();
1860     return status;
1861 }