]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_db.c
ENGR00284988 gpu:Sync gpu kernel driver code
[karo-tx-linux.git] / drivers / mxc / gpu-viv / hal / kernel / gc_hal_kernel_db.c
1 /****************************************************************************
2 *
3 *    Copyright (C) 2005 - 2013 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) >> 7) % 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         database = pointer;
101     }
102
103     /* Insert the database into the hash. */
104     database->next   = Kernel->db->db[slot];
105     Kernel->db->db[slot] = database;
106
107     /* Save the hash slot. */
108     database->slot = slot;
109
110     /* Release the database mutex. */
111     gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
112
113     /* Return the database. */
114     *Database = database;
115
116     /* Success. */
117     gcmkFOOTER_ARG("*Database=0x%x", *Database);
118     return gcvSTATUS_OK;
119
120 OnError:
121     if (acquired)
122     {
123         /* Release the database mutex. */
124         gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
125     }
126
127     /* Return the status. */
128     gcmkFOOTER();
129     return status;
130 }
131
132 /*******************************************************************************
133 **  gckKERNEL_FindDatabase
134 **
135 **  Find a database identified by a process ID and move it to the head of the
136 **  hash list.
137 **
138 **  INPUT:
139 **
140 **      gckKERNEL Kernel
141 **          Pointer to a gckKERNEL object.
142 **
143 **      gctUINT32 ProcessID
144 **          ProcessID that identifies the database.
145 **
146 **      gctBOOL LastProcessID
147 **          gcvTRUE if searching for the last known process ID.  gcvFALSE if
148 **          we need to search for the process ID specified by the ProcessID
149 **          argument.
150 **
151 **  OUTPUT:
152 **
153 **      gcsDATABASE_PTR * Database
154 **          Pointer to a variable receiving the database structure pointer on
155 **          success.
156 */
157 static gceSTATUS
158 gckKERNEL_FindDatabase(
159     IN gckKERNEL Kernel,
160     IN gctUINT32 ProcessID,
161     IN gctBOOL LastProcessID,
162     OUT gcsDATABASE_PTR * Database
163     )
164 {
165     gceSTATUS status;
166     gcsDATABASE_PTR database, previous;
167     gctSIZE_T slot;
168     gctBOOL acquired = gcvFALSE;
169
170     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d LastProcessID=%d",
171                    Kernel, ProcessID, LastProcessID);
172
173     /* Compute the hash for the database. */
174     slot = ProcessID % gcmCOUNTOF(Kernel->db->db);
175
176     /* Acquire the database mutex. */
177     gcmkONERROR(
178         gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
179     acquired = gcvTRUE;
180
181     /* Check whether we are getting the last known database. */
182     if (LastProcessID)
183     {
184         /* Use last database. */
185         database = Kernel->db->lastDatabase;
186
187         if (database == gcvNULL)
188         {
189             /* Database not found. */
190             gcmkONERROR(gcvSTATUS_INVALID_DATA);
191         }
192     }
193     else
194     {
195         /* Walk the hash list. */
196         for (previous = gcvNULL, database = Kernel->db->db[slot];
197              database != gcvNULL;
198              database = database->next)
199         {
200             if (database->processID == ProcessID)
201             {
202                 /* Found it! */
203                 break;
204             }
205
206             previous = database;
207         }
208
209         if (database == gcvNULL)
210         {
211             /* Database not found. */
212             gcmkONERROR(gcvSTATUS_INVALID_DATA);
213         }
214
215         if (previous != gcvNULL)
216         {
217             /* Move database to the head of the hash list. */
218             previous->next   = database->next;
219             database->next   = Kernel->db->db[slot];
220             Kernel->db->db[slot] = database;
221         }
222     }
223
224     /* Release the database mutex. */
225     gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
226
227     /* Return the database. */
228     *Database = database;
229
230     /* Success. */
231     gcmkFOOTER_ARG("*Database=0x%x", *Database);
232     return gcvSTATUS_OK;
233
234 OnError:
235     if (acquired)
236     {
237         /* Release the database mutex. */
238         gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
239     }
240
241     /* Return the status. */
242     gcmkFOOTER();
243     return status;
244 }
245
246 /*******************************************************************************
247 **  gckKERNEL_DeleteDatabase
248 **
249 **  Remove a database from the hash list and delete its structure.
250 **
251 **  INPUT:
252 **
253 **      gckKERNEL Kernel
254 **          Pointer to a gckKERNEL object.
255 **
256 **      gcsDATABASE_PTR Database
257 **          Pointer to the database structure to remove.
258 **
259 **  OUTPUT:
260 **
261 **      Nothing.
262 */
263 static gceSTATUS
264 gckKERNEL_DeleteDatabase(
265     IN gckKERNEL Kernel,
266     IN gcsDATABASE_PTR Database
267     )
268 {
269     gceSTATUS status;
270     gctBOOL acquired = gcvFALSE;
271     gcsDATABASE_PTR database;
272
273     gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database);
274
275     /* Acquire the database mutex. */
276     gcmkONERROR(
277         gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
278     acquired = gcvTRUE;
279
280     /* Check slot value. */
281     gcmkVERIFY_ARGUMENT(Database->slot < gcmCOUNTOF(Kernel->db->db));
282
283     if (Database->slot < gcmCOUNTOF(Kernel->db->db))
284     {
285         /* Check if database if the head of the hash list. */
286         if (Kernel->db->db[Database->slot] == Database)
287         {
288             /* Remove the database from the hash list. */
289             Kernel->db->db[Database->slot] = Database->next;
290         }
291         else
292         {
293             /* Walk the has list to find the database. */
294             for (database = Kernel->db->db[Database->slot];
295                  database != gcvNULL;
296                  database = database->next
297             )
298             {
299                 /* Check if the next list entry is this database. */
300                 if (database->next == Database)
301                 {
302                     /* Remove the database from the hash list. */
303                     database->next = Database->next;
304                     break;
305                 }
306             }
307
308             if (database == gcvNULL)
309             {
310                 /* Ouch!  Something got corrupted. */
311                 gcmkONERROR(gcvSTATUS_INVALID_DATA);
312             }
313         }
314     }
315
316     if (Kernel->db->lastDatabase != gcvNULL)
317     {
318         /* Insert database to the free list. */
319         Kernel->db->lastDatabase->next = Kernel->db->freeDatabase;
320         Kernel->db->freeDatabase       = Kernel->db->lastDatabase;
321     }
322
323     /* Keep database as the last database. */
324     Kernel->db->lastDatabase = Database;
325
326     /* Release the database mutex. */
327     gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
328
329     /* Success. */
330     gcmkFOOTER_NO();
331     return gcvSTATUS_OK;
332
333 OnError:
334     if (acquired)
335     {
336         /* Release the database mutex. */
337         gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
338     }
339
340     /* Return the status. */
341     gcmkFOOTER();
342     return status;
343 }
344
345 /*******************************************************************************
346 **  gckKERNEL_NewRecord
347 **
348 **  Create a new database record structure and insert it to the head of the
349 **  database.
350 **
351 **  INPUT:
352 **
353 **      gckKERNEL Kernel
354 **          Pointer to a gckKERNEL object.
355 **
356 **      gcsDATABASE_PTR Database
357 **          Pointer to a database structure.
358 **
359 **  OUTPUT:
360 **
361 **      gcsDATABASE_RECORD_PTR * Record
362 **          Pointer to a variable receiving the database record structure
363 **          pointer on success.
364 */
365 static gceSTATUS
366 gckKERNEL_NewRecord(
367     IN gckKERNEL Kernel,
368     IN gcsDATABASE_PTR Database,
369     IN gctUINT32 Slot,
370     OUT gcsDATABASE_RECORD_PTR * Record
371     )
372 {
373     gceSTATUS status;
374     gctBOOL acquired = gcvFALSE;
375     gcsDATABASE_RECORD_PTR record = gcvNULL;
376
377     gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database);
378
379     /* Acquire the database mutex. */
380     gcmkONERROR(
381         gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
382     acquired = gcvTRUE;
383
384     if (Kernel->db->freeRecord != gcvNULL)
385     {
386         /* Allocate the record from the free list. */
387         record             = Kernel->db->freeRecord;
388         Kernel->db->freeRecord = record->next;
389     }
390     else
391     {
392         gctPOINTER pointer = gcvNULL;
393
394         /* Allocate the record from the heap. */
395         gcmkONERROR(gckOS_Allocate(Kernel->os,
396                                    gcmSIZEOF(gcsDATABASE_RECORD),
397                                    &pointer));
398
399         record = pointer;
400     }
401
402     /* Insert the record in the database. */
403     record->next         = Database->list[Slot];
404     Database->list[Slot] = record;
405
406     /* Release the database mutex. */
407     gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
408
409     /* Return the record. */
410     *Record = record;
411
412     /* Success. */
413     gcmkFOOTER_ARG("*Record=0x%x", *Record);
414     return gcvSTATUS_OK;
415
416 OnError:
417     if (acquired)
418     {
419         /* Release the database mutex. */
420         gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
421     }
422     if (record != gcvNULL)
423     {
424         gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record));
425     }
426
427     /* Return the status. */
428     gcmkFOOTER();
429     return status;
430 }
431
432 /*******************************************************************************
433 **  gckKERNEL_DeleteRecord
434 **
435 **  Remove a database record from the database and delete its structure.
436 **
437 **  INPUT:
438 **
439 **      gckKERNEL Kernel
440 **          Pointer to a gckKERNEL object.
441 **
442 **      gcsDATABASE_PTR Database
443 **          Pointer to a database structure.
444 **
445 **      gceDATABASE_TYPE Type
446 **          Type of the record to remove.
447 **
448 **      gctPOINTER Data
449 **          Data of the record to remove.
450 **
451 **  OUTPUT:
452 **
453 **      gctSIZE_T_PTR Bytes
454 **          Pointer to a variable that receives the size of the record deleted.
455 **          Can be gcvNULL if the size is not required.
456 */
457 static gceSTATUS
458 gckKERNEL_DeleteRecord(
459     IN gckKERNEL Kernel,
460     IN gcsDATABASE_PTR Database,
461     IN gceDATABASE_TYPE Type,
462     IN gctPOINTER Data,
463     OUT gctSIZE_T_PTR Bytes OPTIONAL
464     )
465 {
466     gceSTATUS status;
467     gctBOOL acquired = gcvFALSE;
468     gcsDATABASE_RECORD_PTR record, previous;
469     gctUINT32 slot = _GetSlot(Database, Data);
470
471     gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x",
472                    Kernel, Database, Type, Data);
473
474     /* Acquire the database mutex. */
475     gcmkONERROR(
476         gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
477     acquired = gcvTRUE;
478
479
480     /* Scan the database for this record. */
481     for (record = Database->list[slot], previous = gcvNULL;
482          record != gcvNULL;
483          record = record->next
484     )
485     {
486         if ((record->type == Type)
487         &&  (record->data == Data)
488         )
489         {
490             /* Found it! */
491             break;
492         }
493
494         previous = record;
495     }
496
497     if (record == gcvNULL)
498     {
499         /* Ouch!  This record is not found? */
500         gcmkONERROR(gcvSTATUS_INVALID_DATA);
501     }
502
503     if (Bytes != gcvNULL)
504     {
505         /* Return size of record. */
506         *Bytes = record->bytes;
507     }
508
509     /* Remove record from database. */
510     if (previous == gcvNULL)
511     {
512         Database->list[slot] = record->next;
513     }
514     else
515     {
516         previous->next = record->next;
517     }
518
519     /* Insert record in free list. */
520     record->next       = Kernel->db->freeRecord;
521     Kernel->db->freeRecord = record;
522
523     /* Release the database mutex. */
524     gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
525
526     /* Success. */
527     gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
528     return gcvSTATUS_OK;
529
530 OnError:
531     if (acquired)
532     {
533         /* Release the database mutex. */
534         gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
535     }
536
537     /* Return the status. */
538     gcmkFOOTER();
539     return status;
540 }
541
542 /*******************************************************************************
543 **  gckKERNEL_FindRecord
544 **
545 **  Find a database record from the database.
546 **
547 **  INPUT:
548 **
549 **      gckKERNEL Kernel
550 **          Pointer to a gckKERNEL object.
551 **
552 **      gcsDATABASE_PTR Database
553 **          Pointer to a database structure.
554 **
555 **      gceDATABASE_TYPE Type
556 **          Type of the record to remove.
557 **
558 **      gctPOINTER Data
559 **          Data of the record to remove.
560 **
561 **  OUTPUT:
562 **
563 **      gctSIZE_T_PTR Bytes
564 **          Pointer to a variable that receives the size of the record deleted.
565 **          Can be gcvNULL if the size is not required.
566 */
567 static gceSTATUS
568 gckKERNEL_FindRecord(
569     IN gckKERNEL Kernel,
570     IN gcsDATABASE_PTR Database,
571     IN gceDATABASE_TYPE Type,
572     IN gctPOINTER Data,
573     OUT gcsDATABASE_RECORD_PTR Record
574     )
575 {
576     gceSTATUS status;
577     gctBOOL acquired = gcvFALSE;
578     gcsDATABASE_RECORD_PTR record;
579     gctUINT32 slot = _GetSlot(Database, Data);
580
581     gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x",
582                    Kernel, Database, Type, Data);
583
584     /* Acquire the database mutex. */
585     gcmkONERROR(
586         gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
587     acquired = gcvTRUE;
588
589     /* Scan the database for this record. */
590     for (record = Database->list[slot];
591          record != gcvNULL;
592          record = record->next
593     )
594     {
595         if ((record->type == Type)
596         &&  (record->data == Data)
597         )
598         {
599             /* Found it! */
600             break;
601         }
602     }
603
604     if (record == gcvNULL)
605     {
606         /* Ouch!  This record is not found? */
607         gcmkONERROR(gcvSTATUS_INVALID_DATA);
608     }
609
610     if (Record != gcvNULL)
611     {
612         /* Return information of record. */
613         gcmkONERROR(
614             gckOS_MemCopy(Record, record, sizeof(gcsDATABASE_RECORD)));
615     }
616
617     /* Release the database mutex. */
618     gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
619
620     /* Success. */
621     gcmkFOOTER_ARG("Record=0x%x", Record);
622     return gcvSTATUS_OK;
623
624 OnError:
625     if (acquired)
626     {
627         /* Release the database mutex. */
628         gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
629     }
630
631     /* Return the status. */
632     gcmkFOOTER();
633     return status;
634 }
635
636
637 /*******************************************************************************
638 ***** Public API **************************************************************/
639
640 /*******************************************************************************
641 **  gckKERNEL_CreateProcessDB
642 **
643 **  Create a new process database.
644 **
645 **  INPUT:
646 **
647 **      gckKERNEL Kernel
648 **          Pointer to a gckKERNEL object.
649 **
650 **      gctUINT32 ProcessID
651 **          Process ID used to identify the database.
652 **
653 **  OUTPUT:
654 **
655 **      Nothing.
656 */
657 gceSTATUS
658 gckKERNEL_CreateProcessDB(
659     IN gckKERNEL Kernel,
660     IN gctUINT32 ProcessID
661     )
662 {
663     gceSTATUS status;
664     gcsDATABASE_PTR database = gcvNULL;
665     gctUINT32 i;
666
667     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
668
669     /* Verify the arguments. */
670     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
671
672     /* Create a new database. */
673     gcmkONERROR(gckKERNEL_NewDatabase(Kernel, ProcessID, &database));
674
675     /* Initialize the database. */
676     database->processID             = ProcessID;
677     database->vidMem.bytes          = 0;
678     database->vidMem.maxBytes       = 0;
679     database->vidMem.totalBytes     = 0;
680     database->nonPaged.bytes        = 0;
681     database->nonPaged.maxBytes     = 0;
682     database->nonPaged.totalBytes   = 0;
683     database->contiguous.bytes      = 0;
684     database->contiguous.maxBytes   = 0;
685     database->contiguous.totalBytes = 0;
686     database->mapMemory.bytes          = 0;
687     database->mapMemory.maxBytes       = 0;
688     database->mapMemory.totalBytes     = 0;
689     database->mapUserMemory.bytes      = 0;
690     database->mapUserMemory.maxBytes   = 0;
691     database->mapUserMemory.totalBytes = 0;
692     database->vidMemResv.bytes         = 0;
693     database->vidMemResv.maxBytes      = 0;
694     database->vidMemResv.totalBytes    = 0;
695     database->vidMemCont.bytes         = 0;
696     database->vidMemCont.maxBytes      = 0;
697     database->vidMemCont.totalBytes    = 0;
698     database->vidMemVirt.bytes         = 0;
699     database->vidMemVirt.maxBytes      = 0;
700     database->vidMemVirt.totalBytes    = 0;
701
702     for (i = 0; i < gcmCOUNTOF(database->list); i++)
703     {
704         database->list[i]              = gcvNULL;
705     }
706
707 #if gcdSECURE_USER
708     {
709         gctINT slot;
710         gcskSECURE_CACHE * cache = &database->cache;
711
712         /* Setup the linked list of cache nodes. */
713         for (slot = 1; slot <= gcdSECURE_CACHE_SLOTS; ++slot)
714         {
715             cache->cache[slot].logical = gcvNULL;
716
717 #if gcdSECURE_CACHE_METHOD != gcdSECURE_CACHE_TABLE
718             cache->cache[slot].prev = &cache->cache[slot - 1];
719             cache->cache[slot].next = &cache->cache[slot + 1];
720 #   endif
721 #if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
722             cache->cache[slot].nextHash = gcvNULL;
723             cache->cache[slot].prevHash = gcvNULL;
724 #   endif
725         }
726
727 #if gcdSECURE_CACHE_METHOD != gcdSECURE_CACHE_TABLE
728         /* Setup the head and tail of the cache. */
729         cache->cache[0].next    = &cache->cache[1];
730         cache->cache[0].prev    = &cache->cache[gcdSECURE_CACHE_SLOTS];
731         cache->cache[0].logical = gcvNULL;
732
733         /* Fix up the head and tail pointers. */
734         cache->cache[0].next->prev = &cache->cache[0];
735         cache->cache[0].prev->next = &cache->cache[0];
736 #   endif
737
738 #if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
739         /* Zero out the hash table. */
740         for (slot = 0; slot < gcmCOUNTOF(cache->hash); ++slot)
741         {
742             cache->hash[slot].logical  = gcvNULL;
743             cache->hash[slot].nextHash = gcvNULL;
744         }
745 #   endif
746
747         /* Initialize cache index. */
748         cache->cacheIndex = gcvNULL;
749         cache->cacheFree  = 1;
750         cache->cacheStamp = 0;
751     }
752 #endif
753
754     /* Reset idle timer. */
755     Kernel->db->lastIdle = 0;
756
757     /* Success. */
758     gcmkFOOTER_NO();
759     return gcvSTATUS_OK;
760
761 OnError:
762     /* Return the status. */
763     gcmkFOOTER();
764     return status;
765 }
766
767 /*******************************************************************************
768 **  gckKERNEL_AddProcessDB
769 **
770 **  Add a record to a process database.
771 **
772 **  INPUT:
773 **
774 **      gckKERNEL Kernel
775 **          Pointer to a gckKERNEL object.
776 **
777 **      gctUINT32 ProcessID
778 **          Process ID used to identify the database.
779 **
780 **      gceDATABASE_TYPE TYPE
781 **          Type of the record to add.
782 **
783 **      gctPOINTER Pointer
784 **          Data of the record to add.
785 **
786 **      gctPHYS_ADDR Physical
787 **          Physical address of the record to add.
788 **
789 **      gctSIZE_T Size
790 **          Size of the record to add.
791 **
792 **  OUTPUT:
793 **
794 **      Nothing.
795 */
796 gceSTATUS
797 gckKERNEL_AddProcessDB(
798     IN gckKERNEL Kernel,
799     IN gctUINT32 ProcessID,
800     IN gceDATABASE_TYPE Type,
801     IN gctPOINTER Pointer,
802     IN gctPHYS_ADDR Physical,
803     IN gctSIZE_T Size
804     )
805 {
806     gceSTATUS status;
807     gcsDATABASE_PTR database;
808     gcsDATABASE_RECORD_PTR record = gcvNULL;
809     gcsDATABASE_COUNTERS * count;
810
811     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x "
812                    "Physical=0x%x Size=%lu",
813                    Kernel, ProcessID, Type, Pointer, Physical, Size);
814
815     /* Verify the arguments. */
816     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
817
818     /* Special case the idle record. */
819     if (Type == gcvDB_IDLE)
820     {
821         gctUINT64 time;
822
823         /* Get the current profile time. */
824         gcmkONERROR(gckOS_GetProfileTick(&time));
825
826         if ((ProcessID == 0) && (Kernel->db->lastIdle != 0))
827         {
828             /* Out of idle, adjust time it was idle. */
829             Kernel->db->idleTime += time - Kernel->db->lastIdle;
830             Kernel->db->lastIdle  = 0;
831         }
832         else if (ProcessID == 1)
833         {
834             /* Save current idle time. */
835             Kernel->db->lastIdle = time;
836         }
837
838 #if gcdDYNAMIC_SPEED
839         {
840             /* Test for first call. */
841             if (Kernel->db->lastSlowdown == 0)
842             {
843                 /* Save milliseconds. */
844                 Kernel->db->lastSlowdown     = time;
845                 Kernel->db->lastSlowdownIdle = Kernel->db->idleTime;
846             }
847             else
848             {
849                 /* Compute ellapsed time in milliseconds. */
850                 gctUINT delta = gckOS_ProfileToMS(time - Kernel->db->lastSlowdown);
851
852                 /* Test for end of period. */
853                 if (delta >= gcdDYNAMIC_SPEED)
854                 {
855                     /* Compute number of idle milliseconds. */
856                     gctUINT idle = gckOS_ProfileToMS(
857                         Kernel->db->idleTime  - Kernel->db->lastSlowdownIdle);
858
859                     /* Broadcast to slow down the GPU. */
860                     gcmkONERROR(gckOS_BroadcastCalibrateSpeed(Kernel->os,
861                                                               Kernel->hardware,
862                                                               idle,
863                                                               delta));
864
865                     /* Save current time. */
866                     Kernel->db->lastSlowdown     = time;
867                     Kernel->db->lastSlowdownIdle = Kernel->db->idleTime;
868                 }
869             }
870         }
871 #endif
872
873         /* Success. */
874         gcmkFOOTER_NO();
875         return gcvSTATUS_OK;
876     }
877
878     /* Verify the arguments. */
879     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
880
881     /* Find the database. */
882     gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
883
884     /* Create a new record in the database. */
885     gcmkONERROR(gckKERNEL_NewRecord(Kernel, database, _GetSlot(database, Pointer), &record));
886
887     /* Initialize the record. */
888     record->kernel   = Kernel;
889     record->type     = Type;
890     record->data     = Pointer;
891     record->physical = Physical;
892     record->bytes    = Size;
893
894     /* Get pointer to counters. */
895     switch (Type)
896     {
897     case gcvDB_VIDEO_MEMORY:
898         count = &database->vidMem;
899         break;
900
901     case gcvDB_NON_PAGED:
902         count = &database->nonPaged;
903         break;
904
905     case gcvDB_CONTIGUOUS:
906         count = &database->contiguous;
907         break;
908
909     case gcvDB_MAP_MEMORY:
910         count = &database->mapMemory;
911         break;
912
913     case gcvDB_MAP_USER_MEMORY:
914         count = &database->mapUserMemory;
915         break;
916
917     case gcvDB_VIDEO_MEMORY_RESERVED:
918         count = &database->vidMemResv;
919         break;
920
921     case gcvDB_VIDEO_MEMORY_CONTIGUOUS:
922         count = &database->vidMemCont;
923         break;
924
925     case gcvDB_VIDEO_MEMORY_VIRTUAL:
926         count = &database->vidMemVirt;
927         break;
928
929     default:
930         count = gcvNULL;
931         break;
932     }
933
934     if (count != gcvNULL)
935     {
936         /* Adjust counters. */
937         count->totalBytes += Size;
938         count->bytes      += Size;
939
940         if (count->bytes > count->maxBytes)
941         {
942             count->maxBytes = count->bytes;
943         }
944     }
945
946     /* Success. */
947     gcmkFOOTER_NO();
948     return gcvSTATUS_OK;
949
950 OnError:
951     /* Return the status. */
952     gcmkFOOTER();
953     return status;
954 }
955
956 /*******************************************************************************
957 **  gckKERNEL_RemoveProcessDB
958 **
959 **  Remove a record from a process database.
960 **
961 **  INPUT:
962 **
963 **      gckKERNEL Kernel
964 **          Pointer to a gckKERNEL object.
965 **
966 **      gctUINT32 ProcessID
967 **          Process ID used to identify the database.
968 **
969 **      gceDATABASE_TYPE TYPE
970 **          Type of the record to remove.
971 **
972 **      gctPOINTER Pointer
973 **          Data of the record to remove.
974 **
975 **  OUTPUT:
976 **
977 **      Nothing.
978 */
979 gceSTATUS
980 gckKERNEL_RemoveProcessDB(
981     IN gckKERNEL Kernel,
982     IN gctUINT32 ProcessID,
983     IN gceDATABASE_TYPE Type,
984     IN gctPOINTER Pointer
985     )
986 {
987     gceSTATUS status;
988     gcsDATABASE_PTR database;
989     gctSIZE_T bytes = 0;
990
991     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x",
992                    Kernel, ProcessID, Type, Pointer);
993
994     /* Verify the arguments. */
995     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
996     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
997
998     /* Find the database. */
999     gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1000
1001     /* Delete the record. */
1002     gcmkONERROR(
1003         gckKERNEL_DeleteRecord(Kernel, database, Type, Pointer, &bytes));
1004
1005     /* Update counters. */
1006     switch (Type)
1007     {
1008     case gcvDB_VIDEO_MEMORY:
1009         database->vidMem.bytes -= bytes;
1010         break;
1011
1012     case gcvDB_NON_PAGED:
1013         database->nonPaged.bytes -= bytes;
1014         break;
1015
1016     case gcvDB_CONTIGUOUS:
1017         database->contiguous.bytes -= bytes;
1018         break;
1019
1020     case gcvDB_MAP_MEMORY:
1021         database->mapMemory.bytes -= bytes;
1022         break;
1023
1024     case gcvDB_MAP_USER_MEMORY:
1025         database->mapUserMemory.bytes -= bytes;
1026         break;
1027
1028     case gcvDB_VIDEO_MEMORY_RESERVED:
1029         database->vidMemResv.bytes -= bytes;
1030         break;
1031
1032     case gcvDB_VIDEO_MEMORY_CONTIGUOUS:
1033         database->vidMemCont.bytes -= bytes;
1034         break;
1035
1036     case gcvDB_VIDEO_MEMORY_VIRTUAL:
1037         database->vidMemVirt.bytes -= bytes;
1038         break;
1039
1040     default:
1041         break;
1042     }
1043
1044     /* Success. */
1045     gcmkFOOTER_NO();
1046     return gcvSTATUS_OK;
1047
1048 OnError:
1049     /* Return the status. */
1050     gcmkFOOTER();
1051     return status;
1052 }
1053
1054 /*******************************************************************************
1055 **  gckKERNEL_FindProcessDB
1056 **
1057 **  Find a record from a process database.
1058 **
1059 **  INPUT:
1060 **
1061 **      gckKERNEL Kernel
1062 **          Pointer to a gckKERNEL object.
1063 **
1064 **      gctUINT32 ProcessID
1065 **          Process ID used to identify the database.
1066 **
1067 **      gceDATABASE_TYPE TYPE
1068 **          Type of the record to remove.
1069 **
1070 **      gctPOINTER Pointer
1071 **          Data of the record to remove.
1072 **
1073 **  OUTPUT:
1074 **
1075 **      gcsDATABASE_RECORD_PTR Record
1076 **          Copy of record.
1077 */
1078 gceSTATUS
1079 gckKERNEL_FindProcessDB(
1080     IN gckKERNEL Kernel,
1081     IN gctUINT32 ProcessID,
1082     IN gctUINT32 ThreadID,
1083     IN gceDATABASE_TYPE Type,
1084     IN gctPOINTER Pointer,
1085     OUT gcsDATABASE_RECORD_PTR Record
1086     )
1087 {
1088     gceSTATUS status;
1089     gcsDATABASE_PTR database;
1090
1091     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x",
1092                    Kernel, ProcessID, ThreadID, Type, Pointer);
1093
1094     /* Verify the arguments. */
1095     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1096     gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
1097
1098     /* Find the database. */
1099     gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1100
1101     /* Find the record. */
1102     gcmkONERROR(
1103         gckKERNEL_FindRecord(Kernel, database, Type, Pointer, Record));
1104
1105     /* Success. */
1106     gcmkFOOTER_NO();
1107     return gcvSTATUS_OK;
1108
1109 OnError:
1110     /* Return the status. */
1111     gcmkFOOTER();
1112     return status;
1113 }
1114
1115 /*******************************************************************************
1116 **  gckKERNEL_DestroyProcessDB
1117 **
1118 **  Destroy a process database.  If the database contains any records, the data
1119 **  inside those records will be deleted as well.  This aids in the cleanup if
1120 **  a process has died unexpectedly or has memory leaks.
1121 **
1122 **  INPUT:
1123 **
1124 **      gckKERNEL Kernel
1125 **          Pointer to a gckKERNEL object.
1126 **
1127 **      gctUINT32 ProcessID
1128 **          Process ID used to identify the database.
1129 **
1130 **  OUTPUT:
1131 **
1132 **      Nothing.
1133 */
1134 gceSTATUS
1135 gckKERNEL_DestroyProcessDB(
1136     IN gckKERNEL Kernel,
1137     IN gctUINT32 ProcessID
1138     )
1139 {
1140     gceSTATUS status;
1141     gcsDATABASE_PTR database;
1142     gcsDATABASE_RECORD_PTR record, next;
1143     gctBOOL asynchronous;
1144     gctPHYS_ADDR physical;
1145     gcuVIDMEM_NODE_PTR node;
1146     gckKERNEL kernel = Kernel;
1147     gctUINT32 i;
1148
1149     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
1150
1151     /* Verify the arguments. */
1152     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1153
1154     /* Find the database. */
1155     gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1156
1157     gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1158                    "DB(%d): VidMem: total=%lu max=%lu",
1159                    ProcessID, database->vidMem.totalBytes,
1160                    database->vidMem.maxBytes);
1161     gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1162                    "DB(%d): NonPaged: total=%lu max=%lu",
1163                    ProcessID, database->nonPaged.totalBytes,
1164                    database->nonPaged.maxBytes);
1165     gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1166                    "DB(%d): Contiguous: total=%lu max=%lu",
1167                    ProcessID, database->contiguous.totalBytes,
1168                    database->contiguous.maxBytes);
1169     gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1170                    "DB(%d): Idle time=%llu",
1171                    ProcessID, Kernel->db->idleTime);
1172     gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1173                    "DB(%d): Map: total=%lu max=%lu",
1174                    ProcessID, database->mapMemory.totalBytes,
1175                    database->mapMemory.maxBytes);
1176     gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1177                    "DB(%d): Map: total=%lu max=%lu",
1178                    ProcessID, database->mapUserMemory.totalBytes,
1179                    database->mapUserMemory.maxBytes);
1180
1181     if (database->list != gcvNULL)
1182     {
1183         gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1184                        "Process %d has entries in its database:",
1185                        ProcessID);
1186     }
1187
1188     for(i = 0; i < gcmCOUNTOF(database->list); i++)
1189     {
1190
1191     /* Walk all records. */
1192     for (record = database->list[i]; record != gcvNULL; record = next)
1193     {
1194         /* Next next record. */
1195         next = record->next;
1196
1197         /* Dispatch on record type. */
1198         switch (record->type)
1199         {
1200         case gcvDB_VIDEO_MEMORY:
1201             /* Free the video memory. */
1202             status = gckVIDMEM_Free(gcmUINT64_TO_PTR(record->data));
1203
1204             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1205                            "DB: VIDEO_MEMORY 0x%x (status=%d)",
1206                            record->data, status);
1207             break;
1208
1209         case gcvDB_NON_PAGED:
1210             physical = gcmNAME_TO_PTR(record->physical);
1211             /* Unmap user logical memory first. */
1212             status = gckOS_UnmapUserLogical(Kernel->os,
1213                                             physical,
1214                                             record->bytes,
1215                                             record->data);
1216
1217             /* Free the non paged memory. */
1218             status = gckOS_FreeNonPagedMemory(Kernel->os,
1219                                               record->bytes,
1220                                               physical,
1221                                               record->data);
1222             gcmRELEASE_NAME(record->physical);
1223
1224             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1225                            "DB: NON_PAGED 0x%x, bytes=%lu (status=%d)",
1226                            record->data, record->bytes, status);
1227             break;
1228
1229 #if gcdVIRTUAL_COMMAND_BUFFER
1230         case gcvDB_COMMAND_BUFFER:
1231             /* Free the command buffer. */
1232             status = gckEVENT_DestroyVirtualCommandBuffer(record->kernel->eventObj,
1233                                                           record->bytes,
1234                                                           gcmNAME_TO_PTR(record->physical),
1235                                                           record->data,
1236                                                           gcvKERNEL_PIXEL);
1237             gcmRELEASE_NAME(record->physical);
1238
1239             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1240                            "DB: COMMAND_BUFFER 0x%x, bytes=%lu (status=%d)",
1241                            record->data, record->bytes, status);
1242             break;
1243 #endif
1244
1245         case gcvDB_CONTIGUOUS:
1246             physical = gcmNAME_TO_PTR(record->physical);
1247             /* Unmap user logical memory first. */
1248             status = gckOS_UnmapUserLogical(Kernel->os,
1249                                             physical,
1250                                             record->bytes,
1251                                             record->data);
1252
1253             /* Free the contiguous memory. */
1254             status = gckEVENT_FreeContiguousMemory(Kernel->eventObj,
1255                                                    record->bytes,
1256                                                    physical,
1257                                                    record->data,
1258                                                    gcvKERNEL_PIXEL);
1259             gcmRELEASE_NAME(record->physical);
1260
1261             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1262                            "DB: CONTIGUOUS 0x%x bytes=%lu (status=%d)",
1263                            record->data, record->bytes, status);
1264             break;
1265
1266         case gcvDB_SIGNAL:
1267 #if USE_NEW_LINUX_SIGNAL
1268             status = gcvSTATUS_NOT_SUPPORTED;
1269 #else
1270             /* Free the user signal. */
1271             status = gckOS_DestroyUserSignal(Kernel->os,
1272                                              gcmPTR2INT(record->data));
1273 #endif /* USE_NEW_LINUX_SIGNAL */
1274
1275             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1276                            "DB: SIGNAL %d (status=%d)",
1277                            (gctINT)(gctUINTPTR_T)record->data, status);
1278             break;
1279
1280         case gcvDB_VIDEO_MEMORY_LOCKED:
1281             node = gcmUINT64_TO_PTR(record->data);
1282             /* Unlock what we still locked */
1283             status = gckVIDMEM_Unlock(record->kernel,
1284                                       node,
1285                                       gcvSURF_TYPE_UNKNOWN,
1286                                       &asynchronous);
1287
1288             if (gcmIS_SUCCESS(status) && (gcvTRUE == asynchronous))
1289             {
1290                 /* TODO: we maybe need to schedule a event here */
1291                 status = gckVIDMEM_Unlock(record->kernel,
1292                                           node,
1293                                           gcvSURF_TYPE_UNKNOWN,
1294                                           gcvNULL);
1295             }
1296
1297             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1298                            "DB: VIDEO_MEMORY_LOCKED 0x%x (status=%d)",
1299                            node, status);
1300             break;
1301
1302         case gcvDB_CONTEXT:
1303             /* TODO: Free the context */
1304             status = gckCOMMAND_Detach(Kernel->command, gcmNAME_TO_PTR(record->data));
1305             gcmRELEASE_NAME(record->data);
1306
1307             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1308                            "DB: CONTEXT 0x%x (status=%d)",
1309                            record->data, status);
1310             break;
1311
1312         case gcvDB_MAP_MEMORY:
1313             /* Unmap memory. */
1314             status = gckKERNEL_UnmapMemory(Kernel,
1315                                            record->physical,
1316                                            record->bytes,
1317                                            record->data);
1318
1319             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1320                            "DB: MAP MEMORY %d (status=%d)",
1321                            gcmPTR2INT(record->data), status);
1322             break;
1323
1324         case gcvDB_MAP_USER_MEMORY:
1325             /* TODO: Unmap user memory. */
1326             status = gckOS_UnmapUserMemory(Kernel->os,
1327                                            Kernel->core,
1328                                            record->physical,
1329                                            record->bytes,
1330                                            gcmNAME_TO_PTR(record->data),
1331                                            0);
1332             gcmRELEASE_NAME(record->data);
1333
1334             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1335                            "DB: MAP USER MEMORY %d (status=%d)",
1336                            gcmPTR2INT(record->data), status);
1337             break;
1338
1339         case gcvDB_SHARED_INFO:
1340             status = gckOS_FreeMemory(Kernel->os, record->physical);
1341             break;
1342
1343 #if gcdANDROID_NATIVE_FENCE_SYNC
1344         case gcvDB_SYNC_POINT:
1345             /* Free the user signal. */
1346             status = gckOS_DestroySyncPoint(Kernel->os,
1347                                             (gctSYNC_POINT) record->data);
1348
1349             gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1350                            "DB: SYNC POINT %d (status=%d)",
1351                            (gctINT)(gctUINTPTR_T)record->data, status);
1352             break;
1353 #endif
1354
1355         case gcvDB_VIDEO_MEMORY_RESERVED:
1356         case gcvDB_VIDEO_MEMORY_CONTIGUOUS:
1357         case gcvDB_VIDEO_MEMORY_VIRTUAL:
1358             break;//Nothing to do
1359
1360         default:
1361             gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DATABASE,
1362                            "DB: Correcupted record=0x%08x type=%d",
1363                            record, record->type);
1364             break;
1365         }
1366
1367         /* Delete the record. */
1368         gcmkONERROR(gckKERNEL_DeleteRecord(Kernel,
1369                                            database,
1370                                            record->type,
1371                                            record->data,
1372                                            gcvNULL));
1373     }
1374
1375     }
1376
1377     /* Delete the database. */
1378     gcmkONERROR(gckKERNEL_DeleteDatabase(Kernel, database));
1379
1380     /* Success. */
1381     gcmkFOOTER_NO();
1382     return gcvSTATUS_OK;
1383
1384 OnError:
1385     /* Return the status. */
1386     gcmkFOOTER();
1387     return status;
1388 }
1389
1390 /*******************************************************************************
1391 **  gckKERNEL_QueryProcessDB
1392 **
1393 **  Query a process database for the current usage of a particular record type.
1394 **
1395 **  INPUT:
1396 **
1397 **      gckKERNEL Kernel
1398 **          Pointer to a gckKERNEL object.
1399 **
1400 **      gctUINT32 ProcessID
1401 **          Process ID used to identify the database.
1402 **
1403 **      gctBOOL LastProcessID
1404 **          gcvTRUE if searching for the last known process ID.  gcvFALSE if
1405 **          we need to search for the process ID specified by the ProcessID
1406 **          argument.
1407 **
1408 **      gceDATABASE_TYPE Type
1409 **          Type of the record to query.
1410 **
1411 **  OUTPUT:
1412 **
1413 **      gcuDATABASE_INFO * Info
1414 **          Pointer to a variable that receives the requested information.
1415 */
1416 gceSTATUS
1417 gckKERNEL_QueryProcessDB(
1418     IN gckKERNEL Kernel,
1419     IN gctUINT32 ProcessID,
1420     IN gctBOOL LastProcessID,
1421     IN gceDATABASE_TYPE Type,
1422     OUT gcuDATABASE_INFO * Info
1423     )
1424 {
1425     gceSTATUS status;
1426     gcsDATABASE_PTR database;
1427
1428     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Info=0x%x",
1429                    Kernel, ProcessID, Type, Info);
1430
1431     /* Verify the arguments. */
1432     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1433     gcmkVERIFY_ARGUMENT(Info != gcvNULL);
1434
1435     /* Find the database. */
1436     gcmkONERROR(
1437         gckKERNEL_FindDatabase(Kernel, ProcessID, LastProcessID, &database));
1438
1439     /* Get pointer to counters. */
1440     switch (Type)
1441     {
1442     case gcvDB_VIDEO_MEMORY:
1443         gckOS_MemCopy(&Info->counters,
1444                                   &database->vidMem,
1445                                   gcmSIZEOF(database->vidMem));
1446         break;
1447
1448     case gcvDB_NON_PAGED:
1449         gckOS_MemCopy(&Info->counters,
1450                                   &database->nonPaged,
1451                                   gcmSIZEOF(database->vidMem));
1452         break;
1453
1454     case gcvDB_CONTIGUOUS:
1455         gckOS_MemCopy(&Info->counters,
1456                                   &database->contiguous,
1457                                   gcmSIZEOF(database->vidMem));
1458         break;
1459
1460     case gcvDB_IDLE:
1461         Info->time           = Kernel->db->idleTime;
1462         Kernel->db->idleTime = 0;
1463         break;
1464
1465     case gcvDB_MAP_MEMORY:
1466         gckOS_MemCopy(&Info->counters,
1467                                   &database->mapMemory,
1468                                   gcmSIZEOF(database->mapMemory));
1469         break;
1470
1471     case gcvDB_MAP_USER_MEMORY:
1472         gckOS_MemCopy(&Info->counters,
1473                                   &database->mapUserMemory,
1474                                   gcmSIZEOF(database->mapUserMemory));
1475         break;
1476
1477     case gcvDB_VIDEO_MEMORY_RESERVED:
1478         gckOS_MemCopy(&Info->counters,
1479                                   &database->vidMemResv,
1480                                   gcmSIZEOF(database->vidMemResv));
1481         break;
1482
1483     case gcvDB_VIDEO_MEMORY_CONTIGUOUS:
1484         gckOS_MemCopy(&Info->counters,
1485                                   &database->vidMemCont,
1486                                   gcmSIZEOF(database->vidMemCont));
1487         break;
1488
1489     case gcvDB_VIDEO_MEMORY_VIRTUAL:
1490         gckOS_MemCopy(&Info->counters,
1491                                   &database->vidMemVirt,
1492                                   gcmSIZEOF(database->vidMemVirt));
1493         break;
1494
1495     default:
1496         break;
1497     }
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 #if gcdSECURE_USER
1510 /*******************************************************************************
1511 **  gckKERNEL_GetProcessDBCache
1512 **
1513 **  Get teh secure cache from a process database.
1514 **
1515 **  INPUT:
1516 **
1517 **      gckKERNEL Kernel
1518 **          Pointer to a gckKERNEL object.
1519 **
1520 **      gctUINT32 ProcessID
1521 **          Process ID used to identify the database.
1522 **
1523 **  OUTPUT:
1524 **
1525 **      gcskSECURE_CACHE_PTR * Cache
1526 **          Pointer to a variable that receives the secure cache pointer.
1527 */
1528 gceSTATUS
1529 gckKERNEL_GetProcessDBCache(
1530     IN gckKERNEL Kernel,
1531     IN gctUINT32 ProcessID,
1532     OUT gcskSECURE_CACHE_PTR * Cache
1533     )
1534 {
1535     gceSTATUS status;
1536     gcsDATABASE_PTR database;
1537
1538     gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
1539
1540     /* Verify the arguments. */
1541     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1542     gcmkVERIFY_ARGUMENT(Cache != gcvNULL);
1543
1544     /* Find the database. */
1545     gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1546
1547     /* Return the pointer to the cache. */
1548     *Cache = &database->cache;
1549
1550     /* Success. */
1551     gcmkFOOTER_ARG("*Cache=0x%x", *Cache);
1552     return gcvSTATUS_OK;
1553
1554 OnError:
1555     /* Return the status. */
1556     gcmkFOOTER();
1557     return status;
1558 }
1559 #endif
1560
1561 gceSTATUS
1562 gckKERNEL_DumpProcessDB(
1563     IN gckKERNEL Kernel
1564     )
1565 {
1566     gcsDATABASE_PTR database;
1567     gctINT i, pid;
1568     gctUINT8 name[24];
1569
1570     gcmkHEADER_ARG("Kernel=0x%x", Kernel);
1571
1572     /* Acquire the database mutex. */
1573     gcmkVERIFY_OK(
1574         gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
1575
1576     gcmkPRINT("**************************\n");
1577     gcmkPRINT("***  PROCESS DB DUMP   ***\n");
1578     gcmkPRINT("**************************\n");
1579
1580     gcmkPRINT_N(8, "%-8s%s\n", "PID", "NAME");
1581     /* Walk the databases. */
1582     for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i)
1583     {
1584         for (database = Kernel->db->db[i];
1585              database != gcvNULL;
1586              database = database->next)
1587         {
1588             pid = database->processID;
1589
1590             gcmkVERIFY_OK(gckOS_ZeroMemory(name, gcmSIZEOF(name)));
1591
1592             gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name));
1593
1594             gcmkPRINT_N(8, "%-8d%s\n", pid, name);
1595         }
1596     }
1597
1598     /* Release the database mutex. */
1599     gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
1600
1601     /* Success. */
1602     gcmkFOOTER_NO();
1603     return gcvSTATUS_OK;
1604 }