ENGR00156850 gpu-viv: add gpu-viv driver source
[wandboard.git] / drivers / mxc / gpu-viv / hal / kernel / gc_hal_kernel_db.c
bloba394b8e76a89c3d035bfbc532f210b6f4c0505bc
1 /****************************************************************************
3 * Copyright (C) 2005 - 2011 by Vivante Corp.
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.
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.
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.
19 *****************************************************************************/
24 #include "gc_hal_kernel_precomp.h"
26 #define _GC_OBJ_ZONE gcvZONE_DATABASE
28 /*******************************************************************************
29 ***** Private fuctions ********************************************************/
31 /*******************************************************************************
32 ** gckKERNEL_NewDatabase
34 ** Create a new database structure and insert it to the head of the hash list.
36 ** INPUT:
38 ** gckKERNEL Kernel
39 ** Pointer to a gckKERNEL object.
41 ** gctUINT32 ProcessID
42 ** ProcessID that identifies the database.
44 ** OUTPUT:
46 ** gcsDATABASE_PTR * Database
47 ** Pointer to a variable receiving the database structure pointer on
48 ** success.
50 static gceSTATUS
51 gckKERNEL_NewDatabase(
52 IN gckKERNEL Kernel,
53 IN gctUINT32 ProcessID,
54 OUT gcsDATABASE_PTR * Database
57 gceSTATUS status;
58 gcsDATABASE_PTR database;
59 gctBOOL acquired = gcvFALSE;
60 gctSIZE_T slot;
62 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
64 /* Acquire the database mutex. */
65 gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
66 acquired = gcvTRUE;
68 if (Kernel->db->freeDatabase != gcvNULL)
70 /* Allocate a database from the free list. */
71 database = Kernel->db->freeDatabase;
72 Kernel->db->freeDatabase = database->next;
74 else
76 gctPOINTER pointer = gcvNULL;
78 /* Allocate a new database from the heap. */
79 gcmkONERROR(gckOS_Allocate(Kernel->os,
80 gcmSIZEOF(gcsDATABASE),
81 &pointer));
83 database = pointer;
86 /* Compute the hash for the database. */
87 slot = ProcessID % gcmCOUNTOF(Kernel->db->db);
89 /* Insert the database into the hash. */
90 database->next = Kernel->db->db[slot];
91 Kernel->db->db[slot] = database;
93 /* Save the hash slot. */
94 database->slot = slot;
96 /* Release the database mutex. */
97 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
99 /* Return the database. */
100 *Database = database;
102 /* Success. */
103 gcmkFOOTER_ARG("*Database=0x%x", *Database);
104 return gcvSTATUS_OK;
106 OnError:
107 if (acquired)
109 /* Release the database mutex. */
110 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
113 /* Return the status. */
114 gcmkFOOTER();
115 return status;
118 /*******************************************************************************
119 ** gckKERNEL_FindDatabase
121 ** Find a database identified by a process ID and move it to the head of the
122 ** hash list.
124 ** INPUT:
126 ** gckKERNEL Kernel
127 ** Pointer to a gckKERNEL object.
129 ** gctUINT32 ProcessID
130 ** ProcessID that identifies the database.
132 ** gctBOOL LastProcessID
133 ** gcvTRUE if searching for the last known process ID. gcvFALSE if
134 ** we need to search for the process ID specified by the ProcessID
135 ** argument.
137 ** OUTPUT:
139 ** gcsDATABASE_PTR * Database
140 ** Pointer to a variable receiving the database structure pointer on
141 ** success.
143 static gceSTATUS
144 gckKERNEL_FindDatabase(
145 IN gckKERNEL Kernel,
146 IN gctUINT32 ProcessID,
147 IN gctBOOL LastProcessID,
148 OUT gcsDATABASE_PTR * Database
151 gceSTATUS status;
152 gcsDATABASE_PTR database, previous;
153 gctSIZE_T slot;
154 gctBOOL acquired = gcvFALSE;
156 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d LastProcessID=%d",
157 Kernel, ProcessID, LastProcessID);
159 /* Compute the hash for the database. */
160 slot = ProcessID % gcmCOUNTOF(Kernel->db->db);
162 /* Acquire the database mutex. */
163 gcmkONERROR(
164 gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
165 acquired = gcvTRUE;
167 /* Check whether we are getting the last known database. */
168 if (LastProcessID)
170 /* Use last database. */
171 database = Kernel->db->lastDatabase;
173 if (database == gcvNULL)
175 /* Database not found. */
176 gcmkONERROR(gcvSTATUS_INVALID_DATA);
179 else
181 /* Walk the hash list. */
182 for (previous = gcvNULL, database = Kernel->db->db[slot];
183 database != gcvNULL;
184 database = database->next)
186 if (database->processID == ProcessID)
188 /* Found it! */
189 break;
192 previous = database;
195 if (database == gcvNULL)
197 /* Database not found. */
198 gcmkONERROR(gcvSTATUS_INVALID_DATA);
201 if (previous != gcvNULL)
203 /* Move database to the head of the hash list. */
204 previous->next = database->next;
205 database->next = Kernel->db->db[slot];
206 Kernel->db->db[slot] = database;
210 /* Release the database mutex. */
211 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
213 /* Return the database. */
214 *Database = database;
216 /* Success. */
217 gcmkFOOTER_ARG("*Database=0x%x", *Database);
218 return gcvSTATUS_OK;
220 OnError:
221 if (acquired)
223 /* Release the database mutex. */
224 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
227 /* Return the status. */
228 gcmkFOOTER();
229 return status;
232 /*******************************************************************************
233 ** gckKERNEL_DeleteDatabase
235 ** Remove a database from the hash list and delete its structure.
237 ** INPUT:
239 ** gckKERNEL Kernel
240 ** Pointer to a gckKERNEL object.
242 ** gcsDATABASE_PTR Database
243 ** Pointer to the database structure to remove.
245 ** OUTPUT:
247 ** Nothing.
249 static gceSTATUS
250 gckKERNEL_DeleteDatabase(
251 IN gckKERNEL Kernel,
252 IN gcsDATABASE_PTR Database
255 gceSTATUS status;
256 gctBOOL acquired = gcvFALSE;
257 gcsDATABASE_PTR database;
259 gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database);
261 /* Acquire the database mutex. */
262 gcmkONERROR(
263 gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
264 acquired = gcvTRUE;
266 /* Check slot value. */
267 gcmkVERIFY_ARGUMENT(Database->slot < gcmCOUNTOF(Kernel->db->db));
269 if (Database->slot < gcmCOUNTOF(Kernel->db->db))
271 /* Check if database if the head of the hash list. */
272 if (Kernel->db->db[Database->slot] == Database)
274 /* Remove the database from the hash list. */
275 Kernel->db->db[Database->slot] = Database->next;
277 else
279 /* Walk the has list to find the database. */
280 for (database = Kernel->db->db[Database->slot];
281 database != gcvNULL;
282 database = database->next
285 /* Check if the next list entry is this database. */
286 if (database->next == Database)
288 /* Remove the database from the hash list. */
289 database->next = Database->next;
290 break;
294 if (database == gcvNULL)
296 /* Ouch! Something got corrupted. */
297 gcmkONERROR(gcvSTATUS_INVALID_DATA);
302 if (Kernel->db->lastDatabase != gcvNULL)
304 /* Insert database to the free list. */
305 Kernel->db->lastDatabase->next = Kernel->db->freeDatabase;
306 Kernel->db->freeDatabase = Kernel->db->lastDatabase;
309 /* Keep database as the last database. */
310 Kernel->db->lastDatabase = Database;
312 /* Release the database mutex. */
313 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
315 /* Success. */
316 gcmkFOOTER_NO();
317 return gcvSTATUS_OK;
319 OnError:
320 if (acquired)
322 /* Release the database mutex. */
323 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
326 /* Return the status. */
327 gcmkFOOTER();
328 return status;
331 /*******************************************************************************
332 ** gckKERNEL_NewRecord
334 ** Create a new database record structure and insert it to the head of the
335 ** database.
337 ** INPUT:
339 ** gckKERNEL Kernel
340 ** Pointer to a gckKERNEL object.
342 ** gcsDATABASE_PTR Database
343 ** Pointer to a database structure.
345 ** OUTPUT:
347 ** gcsDATABASE_RECORD_PTR * Record
348 ** Pointer to a variable receiving the database record structure
349 ** pointer on success.
351 static gceSTATUS
352 gckKERNEL_NewRecord(
353 IN gckKERNEL Kernel,
354 IN gcsDATABASE_PTR Database,
355 OUT gcsDATABASE_RECORD_PTR * Record
358 gceSTATUS status;
359 gctBOOL acquired = gcvFALSE;
360 gcsDATABASE_RECORD_PTR record = gcvNULL;
362 gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database);
364 /* Acquire the database mutex. */
365 gcmkONERROR(
366 gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
367 acquired = gcvTRUE;
369 if (Kernel->db->freeRecord != gcvNULL)
371 /* Allocate the record from the free list. */
372 record = Kernel->db->freeRecord;
373 Kernel->db->freeRecord = record->next;
375 else
377 gctPOINTER pointer = gcvNULL;
379 /* Allocate the record from the heap. */
380 gcmkONERROR(gckOS_Allocate(Kernel->os,
381 gcmSIZEOF(gcsDATABASE_RECORD),
382 &pointer));
384 record = pointer;
387 /* Insert the record in the database. */
388 record->next = Database->list;
389 Database->list = record;
391 /* Release the database mutex. */
392 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
394 /* Return the record. */
395 *Record = record;
397 /* Success. */
398 gcmkFOOTER_ARG("*Record=0x%x", *Record);
399 return gcvSTATUS_OK;
401 OnError:
402 if (acquired)
404 /* Release the database mutex. */
405 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
407 if (record != gcvNULL)
409 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record));
412 /* Return the status. */
413 gcmkFOOTER();
414 return status;
417 /*******************************************************************************
418 ** gckKERNEL_DeleteRecord
420 ** Remove a database record from the database and delete its structure.
422 ** INPUT:
424 ** gckKERNEL Kernel
425 ** Pointer to a gckKERNEL object.
427 ** gcsDATABASE_PTR Database
428 ** Pointer to a database structure.
430 ** gceDATABASE_TYPE Type
431 ** Type of the record to remove.
433 ** gctPOINTER Data
434 ** Data of the record to remove.
436 ** OUTPUT:
438 ** gctSIZE_T_PTR Bytes
439 ** Pointer to a variable that receives the size of the record deleted.
440 ** Can be gcvNULL if the size is not required.
442 static gceSTATUS
443 gckKERNEL_DeleteRecord(
444 IN gckKERNEL Kernel,
445 IN gcsDATABASE_PTR Database,
446 IN gceDATABASE_TYPE Type,
447 IN gctPOINTER Data,
448 OUT gctSIZE_T_PTR Bytes OPTIONAL
451 gceSTATUS status;
452 gctBOOL acquired = gcvFALSE;
453 gcsDATABASE_RECORD_PTR record, previous;
455 gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x",
456 Kernel, Database, Type, Data);
458 /* Acquire the database mutex. */
459 gcmkONERROR(
460 gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
461 acquired = gcvTRUE;
463 /* Scan the database for this record. */
464 for (record = Database->list, previous = gcvNULL;
465 record != gcvNULL;
466 record = record->next
469 if ((record->type == Type)
470 && (record->data == Data)
473 /* Found it! */
474 break;
477 previous = record;
480 if (record == gcvNULL)
482 /* Ouch! This record is not found? */
483 gcmkONERROR(gcvSTATUS_INVALID_DATA);
486 if (Bytes != gcvNULL)
488 /* Return size of record. */
489 *Bytes = record->bytes;
492 /* Remove record from database. */
493 if (previous == gcvNULL)
495 Database->list = record->next;
497 else
499 previous->next = record->next;
502 /* Insert record in free list. */
503 record->next = Kernel->db->freeRecord;
504 Kernel->db->freeRecord = record;
506 /* Release the database mutex. */
507 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
509 /* Success. */
510 gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
511 return gcvSTATUS_OK;
513 OnError:
514 if (acquired)
516 /* Release the database mutex. */
517 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
520 /* Return the status. */
521 gcmkFOOTER();
522 return status;
525 /*******************************************************************************
526 ** gckKERNEL_FindRecord
528 ** Find a database record from the database.
530 ** INPUT:
532 ** gckKERNEL Kernel
533 ** Pointer to a gckKERNEL object.
535 ** gcsDATABASE_PTR Database
536 ** Pointer to a database structure.
538 ** gceDATABASE_TYPE Type
539 ** Type of the record to remove.
541 ** gctPOINTER Data
542 ** Data of the record to remove.
544 ** OUTPUT:
546 ** gctSIZE_T_PTR Bytes
547 ** Pointer to a variable that receives the size of the record deleted.
548 ** Can be gcvNULL if the size is not required.
550 static gceSTATUS
551 gckKERNEL_FindRecord(
552 IN gckKERNEL Kernel,
553 IN gcsDATABASE_PTR Database,
554 IN gceDATABASE_TYPE Type,
555 IN gctPOINTER Data,
556 OUT gcsDATABASE_RECORD_PTR Record
559 gceSTATUS status;
560 gctBOOL acquired = gcvFALSE;
561 gcsDATABASE_RECORD_PTR record, previous;
563 gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x",
564 Kernel, Database, Type, Data);
566 /* Acquire the database mutex. */
567 gcmkONERROR(
568 gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
569 acquired = gcvTRUE;
571 /* Scan the database for this record. */
572 for (record = Database->list, previous = gcvNULL;
573 record != gcvNULL;
574 record = record->next
577 if ((record->type == Type)
578 && (record->data == Data)
581 /* Found it! */
582 break;
585 previous = record;
588 if (record == gcvNULL)
590 /* Ouch! This record is not found? */
591 gcmkONERROR(gcvSTATUS_INVALID_DATA);
594 if (Record != gcvNULL)
596 /* Return information of record. */
597 gcmkONERROR(
598 gckOS_MemCopy(Record, record, sizeof(gcsDATABASE_RECORD)));
601 /* Release the database mutex. */
602 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
604 /* Success. */
605 gcmkFOOTER_ARG("Record=0x%x", Record);
606 return gcvSTATUS_OK;
608 OnError:
609 if (acquired)
611 /* Release the database mutex. */
612 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
615 /* Return the status. */
616 gcmkFOOTER();
617 return status;
621 /*******************************************************************************
622 ***** Public API **************************************************************/
624 /*******************************************************************************
625 ** gckKERNEL_CreateProcessDB
627 ** Create a new process database.
629 ** INPUT:
631 ** gckKERNEL Kernel
632 ** Pointer to a gckKERNEL object.
634 ** gctUINT32 ProcessID
635 ** Process ID used to identify the database.
637 ** OUTPUT:
639 ** Nothing.
641 gceSTATUS
642 gckKERNEL_CreateProcessDB(
643 IN gckKERNEL Kernel,
644 IN gctUINT32 ProcessID
647 gceSTATUS status;
648 gcsDATABASE_PTR database = gcvNULL;
650 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
652 /* Verify the arguments. */
653 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
655 /* Create a new database. */
656 gcmkONERROR(gckKERNEL_NewDatabase(Kernel, ProcessID, &database));
658 /* Initialize the database. */
659 database->processID = ProcessID;
660 database->vidMem.bytes = 0;
661 database->vidMem.maxBytes = 0;
662 database->vidMem.totalBytes = 0;
663 database->nonPaged.bytes = 0;
664 database->nonPaged.maxBytes = 0;
665 database->nonPaged.totalBytes = 0;
666 database->contiguous.bytes = 0;
667 database->contiguous.maxBytes = 0;
668 database->contiguous.totalBytes = 0;
669 database->mapMemory.bytes = 0;
670 database->mapMemory.maxBytes = 0;
671 database->mapMemory.totalBytes = 0;
672 database->mapUserMemory.bytes = 0;
673 database->mapUserMemory.maxBytes = 0;
674 database->mapUserMemory.totalBytes = 0;
675 database->list = gcvNULL;
677 #if gcdSECURE_USER
679 gctINT slot;
680 gcskSECURE_CACHE * cache = &database->cache;
682 /* Setup the linked list of cache nodes. */
683 for (slot = 1; slot <= gcdSECURE_CACHE_SLOTS; ++slot)
685 cache->cache[slot].logical = gcvNULL;
687 #if gcdSECURE_CACHE_METHOD != gcdSECURE_CACHE_TABLE
688 cache->cache[slot].prev = &cache->cache[slot - 1];
689 cache->cache[slot].next = &cache->cache[slot + 1];
690 # endif
691 #if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
692 cache->cache[slot].nextHash = gcvNULL;
693 cache->cache[slot].prevHash = gcvNULL;
694 # endif
697 #if gcdSECURE_CACHE_METHOD != gcdSECURE_CACHE_TABLE
698 /* Setup the head and tail of the cache. */
699 cache->cache[0].next = &cache->cache[1];
700 cache->cache[0].prev = &cache->cache[gcdSECURE_CACHE_SLOTS];
701 cache->cache[0].logical = gcvNULL;
703 /* Fix up the head and tail pointers. */
704 cache->cache[0].next->prev = &cache->cache[0];
705 cache->cache[0].prev->next = &cache->cache[0];
706 # endif
708 #if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
709 /* Zero out the hash table. */
710 for (slot = 0; slot < gcmCOUNTOF(cache->hash); ++slot)
712 cache->hash[slot].logical = gcvNULL;
713 cache->hash[slot].nextHash = gcvNULL;
715 # endif
717 /* Initialize cache index. */
718 cache->cacheIndex = gcvNULL;
719 cache->cacheFree = 1;
720 cache->cacheStamp = 0;
722 #endif
724 /* Reset idle timer. */
725 Kernel->db->lastIdle = 0;
727 /* Success. */
728 gcmkFOOTER_NO();
729 return gcvSTATUS_OK;
731 OnError:
732 /* Return the status. */
733 gcmkFOOTER();
734 return status;
737 /*******************************************************************************
738 ** gckKERNEL_AddProcessDB
740 ** Add a record to a process database.
742 ** INPUT:
744 ** gckKERNEL Kernel
745 ** Pointer to a gckKERNEL object.
747 ** gctUINT32 ProcessID
748 ** Process ID used to identify the database.
750 ** gceDATABASE_TYPE TYPE
751 ** Type of the record to add.
753 ** gctPOINTER Pointer
754 ** Data of the record to add.
756 ** gctPHYS_ADDR Physical
757 ** Physical address of the record to add.
759 ** gctSIZE_T Size
760 ** Size of the record to add.
762 ** OUTPUT:
764 ** Nothing.
766 gceSTATUS
767 gckKERNEL_AddProcessDB(
768 IN gckKERNEL Kernel,
769 IN gctUINT32 ProcessID,
770 IN gceDATABASE_TYPE Type,
771 IN gctPOINTER Pointer,
772 IN gctPHYS_ADDR Physical,
773 IN gctSIZE_T Size
776 gceSTATUS status;
777 gcsDATABASE_PTR database;
778 gcsDATABASE_RECORD_PTR record = gcvNULL;
779 gcsDATABASE_COUNTERS * count;
781 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x "
782 "Physical=0x%x Size=%lu",
783 Kernel, ProcessID, Type, Pointer, Physical, Size);
785 /* Verify the arguments. */
786 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
788 /* Special case the idle record. */
789 if (Type == gcvDB_IDLE)
791 gctUINT64 time;
793 /* Get the current profile time. */
794 gcmkONERROR(gckOS_GetProfileTick(&time));
796 if ((ProcessID == 0) && (Kernel->db->lastIdle != 0))
798 /* Out of idle, adjust time it was idle. */
799 Kernel->db->idleTime += time - Kernel->db->lastIdle;
800 Kernel->db->lastIdle = 0;
802 else if (ProcessID == 1)
804 /* Save current idle time. */
805 Kernel->db->lastIdle = time;
808 #if gcdDYNAMIC_SPEED
810 /* Test for first call. */
811 if (Kernel->db->lastSlowdown == 0)
813 /* Save milliseconds. */
814 Kernel->db->lastSlowdown = time;
815 Kernel->db->lastSlowdownIdle = Kernel->db->idleTime;
817 else
819 /* Compute ellapsed time in milliseconds. */
820 gctUINT delta = gckOS_ProfileToMS(time - Kernel->db->lastSlowdown);
822 /* Test for end of period. */
823 if (delta >= gcdDYNAMIC_SPEED)
825 /* Compute number of idle milliseconds. */
826 gctUINT idle = gckOS_ProfileToMS(
827 Kernel->db->idleTime - Kernel->db->lastSlowdownIdle);
829 /* Broadcast to slow down the GPU. */
830 gcmkONERROR(gckOS_BroadcastCalibrateSpeed(Kernel->os,
831 Kernel->hardware,
832 idle,
833 delta));
835 /* Save current time. */
836 Kernel->db->lastSlowdown = time;
837 Kernel->db->lastSlowdownIdle = Kernel->db->idleTime;
841 #endif
843 /* Success. */
844 gcmkFOOTER_NO();
845 return gcvSTATUS_OK;
848 /* Verify the arguments. */
849 gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
851 /* Find the database. */
852 gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
854 /* Create a new record in the database. */
855 gcmkONERROR(gckKERNEL_NewRecord(Kernel, database, &record));
857 /* Initialize the record. */
858 record->kernel = Kernel;
859 record->type = Type;
860 record->data = Pointer;
861 record->physical = Physical;
862 record->bytes = Size;
864 /* Get pointer to counters. */
865 switch (Type)
867 case gcvDB_VIDEO_MEMORY:
868 count = &database->vidMem;
869 break;
871 case gcvDB_NON_PAGED:
872 count = &database->nonPaged;
873 break;
875 case gcvDB_CONTIGUOUS:
876 count = &database->contiguous;
877 break;
879 case gcvDB_MAP_MEMORY:
880 count = &database->mapMemory;
881 break;
883 case gcvDB_MAP_USER_MEMORY:
884 count = &database->mapUserMemory;
885 break;
887 default:
888 count = gcvNULL;
889 break;
892 if (count != gcvNULL)
894 /* Adjust counters. */
895 count->totalBytes += Size;
896 count->bytes += Size;
898 if (count->bytes > count->maxBytes)
900 count->maxBytes = count->bytes;
904 /* Success. */
905 gcmkFOOTER_NO();
906 return gcvSTATUS_OK;
908 OnError:
909 /* Return the status. */
910 gcmkFOOTER();
911 return status;
914 /*******************************************************************************
915 ** gckKERNEL_RemoveProcessDB
917 ** Remove a record from a process database.
919 ** INPUT:
921 ** gckKERNEL Kernel
922 ** Pointer to a gckKERNEL object.
924 ** gctUINT32 ProcessID
925 ** Process ID used to identify the database.
927 ** gceDATABASE_TYPE TYPE
928 ** Type of the record to remove.
930 ** gctPOINTER Pointer
931 ** Data of the record to remove.
933 ** OUTPUT:
935 ** Nothing.
937 gceSTATUS
938 gckKERNEL_RemoveProcessDB(
939 IN gckKERNEL Kernel,
940 IN gctUINT32 ProcessID,
941 IN gceDATABASE_TYPE Type,
942 IN gctPOINTER Pointer
945 gceSTATUS status;
946 gcsDATABASE_PTR database;
947 gctSIZE_T bytes = 0;
949 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x",
950 Kernel, ProcessID, Type, Pointer);
952 /* Verify the arguments. */
953 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
954 gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
956 /* Find the database. */
957 gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
959 /* Delete the record. */
960 gcmkONERROR(
961 gckKERNEL_DeleteRecord(Kernel, database, Type, Pointer, &bytes));
963 /* Update counters. */
964 switch (Type)
966 case gcvDB_VIDEO_MEMORY:
967 database->vidMem.bytes -= bytes;
968 break;
970 case gcvDB_NON_PAGED:
971 database->nonPaged.bytes -= bytes;
972 break;
974 case gcvDB_CONTIGUOUS:
975 database->contiguous.bytes -= bytes;
976 break;
978 case gcvDB_MAP_MEMORY:
979 database->mapMemory.bytes -= bytes;
980 break;
982 case gcvDB_MAP_USER_MEMORY:
983 database->mapUserMemory.bytes -= bytes;
984 break;
986 default:
987 break;
990 /* Success. */
991 gcmkFOOTER_NO();
992 return gcvSTATUS_OK;
994 OnError:
995 /* Return the status. */
996 gcmkFOOTER();
997 return status;
1000 /*******************************************************************************
1001 ** gckKERNEL_FindProcessDB
1003 ** Find a record from a process database.
1005 ** INPUT:
1007 ** gckKERNEL Kernel
1008 ** Pointer to a gckKERNEL object.
1010 ** gctUINT32 ProcessID
1011 ** Process ID used to identify the database.
1013 ** gceDATABASE_TYPE TYPE
1014 ** Type of the record to remove.
1016 ** gctPOINTER Pointer
1017 ** Data of the record to remove.
1019 ** OUTPUT:
1021 ** gcsDATABASE_RECORD_PTR Record
1022 ** Copy of record.
1024 gceSTATUS
1025 gckKERNEL_FindProcessDB(
1026 IN gckKERNEL Kernel,
1027 IN gctUINT32 ProcessID,
1028 IN gctUINT32 ThreadID,
1029 IN gceDATABASE_TYPE Type,
1030 IN gctPOINTER Pointer,
1031 OUT gcsDATABASE_RECORD_PTR Record
1034 gceSTATUS status;
1035 gcsDATABASE_PTR database;
1037 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x",
1038 Kernel, ProcessID, ThreadID, Type, Pointer);
1040 /* Verify the arguments. */
1041 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1042 gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
1044 /* Find the database. */
1045 gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1047 /* Find the record. */
1048 gcmkONERROR(
1049 gckKERNEL_FindRecord(Kernel, database, Type, Pointer, Record));
1051 /* Success. */
1052 gcmkFOOTER_NO();
1053 return gcvSTATUS_OK;
1055 OnError:
1056 /* Return the status. */
1057 gcmkFOOTER();
1058 return status;
1061 /*******************************************************************************
1062 ** gckKERNEL_DestroyProcessDB
1064 ** Destroy a process database. If the database contains any records, the data
1065 ** inside those records will be deleted as well. This aids in the cleanup if
1066 ** a process has died unexpectedly or has memory leaks.
1068 ** INPUT:
1070 ** gckKERNEL Kernel
1071 ** Pointer to a gckKERNEL object.
1073 ** gctUINT32 ProcessID
1074 ** Process ID used to identify the database.
1076 ** OUTPUT:
1078 ** Nothing.
1080 gceSTATUS
1081 gckKERNEL_DestroyProcessDB(
1082 IN gckKERNEL Kernel,
1083 IN gctUINT32 ProcessID
1086 gceSTATUS status;
1087 gcsDATABASE_PTR database;
1088 gcsDATABASE_RECORD_PTR record, next;
1089 gctBOOL asynchronous;
1091 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
1093 /* Verify the arguments. */
1094 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1096 /* Find the database. */
1097 gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1099 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1100 "DB(%d): VidMem: total=%lu max=%lu",
1101 ProcessID, database->vidMem.totalBytes,
1102 database->vidMem.maxBytes);
1103 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1104 "DB(%d): NonPaged: total=%lu max=%lu",
1105 ProcessID, database->nonPaged.totalBytes,
1106 database->nonPaged.maxBytes);
1107 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1108 "DB(%d): Contiguous: total=%lu max=%lu",
1109 ProcessID, database->contiguous.totalBytes,
1110 database->contiguous.maxBytes);
1111 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1112 "DB(%d): Idle time=%llu",
1113 ProcessID, Kernel->db->idleTime);
1114 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1115 "DB(%d): Map: total=%lu max=%lu",
1116 ProcessID, database->mapMemory.totalBytes,
1117 database->mapMemory.maxBytes);
1118 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
1119 "DB(%d): Map: total=%lu max=%lu",
1120 ProcessID, database->mapUserMemory.totalBytes,
1121 database->mapUserMemory.maxBytes);
1123 if (database->list != gcvNULL)
1125 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1126 "Process %d has entries in its database:",
1127 ProcessID);
1130 /* Walk all records. */
1131 for (record = database->list; record != gcvNULL; record = next)
1133 /* Next next record. */
1134 next = record->next;
1136 /* Dispatch on record type. */
1137 switch (record->type)
1139 case gcvDB_VIDEO_MEMORY:
1140 /* Free the video memory. */
1141 status = gckVIDMEM_Free(record->data);
1143 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1144 "DB: VIDEO_MEMORY 0x%x (status=%d)",
1145 record->data, status);
1146 break;
1148 case gcvDB_NON_PAGED:
1149 /* Free the non paged memory. */
1150 status = gckOS_FreeNonPagedMemory(Kernel->os,
1151 record->bytes,
1152 record->physical,
1153 record->data);
1155 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1156 "DB: NON_PAGED 0x%x, bytes=%lu (status=%d)",
1157 record->data, record->bytes, status);
1158 break;
1160 case gcvDB_CONTIGUOUS:
1161 /* Free the contiguous memory. */
1162 status = gckOS_FreeContiguous(Kernel->os,
1163 record->physical,
1164 record->data,
1165 record->bytes);
1167 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1168 "DB: CONTIGUOUS 0x%x bytes=%lu (status=%d)",
1169 record->data, record->bytes, status);
1170 break;
1172 case gcvDB_SIGNAL:
1173 #if USE_NEW_LINUX_SIGNAL
1174 status = gcvSTATUS_NOT_SUPPORTED;
1175 #else
1176 /* Free the user signal. */
1177 status = gckOS_DestroyUserSignal(Kernel->os,
1178 gcmPTR2INT(record->data));
1179 #endif /* USE_NEW_LINUX_SIGNAL */
1181 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1182 "DB: SIGNAL %d (status=%d)",
1183 (gctINT) record->data, status);
1184 break;
1186 case gcvDB_VIDEO_MEMORY_LOCKED:
1187 /* Unlock what we still locked */
1188 status = gckVIDMEM_Unlock(record->kernel,
1189 record->data,
1190 gcvSURF_TYPE_UNKNOWN,
1191 &asynchronous);
1193 if (gcmIS_SUCCESS(status) && (gcvTRUE == asynchronous))
1195 /* TODO: we maybe need to schedule a event here */
1196 status = gckVIDMEM_Unlock(record->kernel,
1197 record->data,
1198 gcvSURF_TYPE_UNKNOWN,
1199 gcvNULL);
1202 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1203 "DB: VIDEO_MEMORY_LOCKED 0x%x (status=%d)",
1204 record->data, status);
1205 break;
1207 case gcvDB_CONTEXT:
1208 /* TODO: Free the context */
1209 status = gckCOMMAND_Detach(Kernel->command, record->data);
1211 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1212 "DB: CONTEXT 0x%x (status=%d)",
1213 record->data, status);
1214 break;
1216 case gcvDB_MAP_MEMORY:
1217 /* Unmap memory. */
1218 status = gckKERNEL_UnmapMemory(Kernel,
1219 record->physical,
1220 record->bytes,
1221 record->data);
1223 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1224 "DB: MAP MEMORY %d (status=%d)",
1225 gcmPTR2INT(record->data), status);
1226 break;
1228 case gcvDB_MAP_USER_MEMORY:
1229 /* TODO: Unmap user memory. */
1230 status = gckOS_UnmapUserMemoryEx(Kernel->os,
1231 Kernel->core,
1232 record->data,
1233 record->bytes,
1234 record->physical,
1237 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1238 "DB: MAP USER MEMORY %d (status=%d)",
1239 gcmPTR2INT(record->data), status);
1240 break;
1242 case gcvDB_SHARED_INFO:
1243 status = gckOS_FreeMemory(Kernel->os, record->physical);
1244 break;
1246 default:
1247 gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DATABASE,
1248 "DB: Correcupted record=0x%08x type=%d",
1249 record, record->type);
1250 break;
1253 /* Delete the record. */
1254 gcmkONERROR(gckKERNEL_DeleteRecord(Kernel,
1255 database,
1256 record->type,
1257 record->data,
1258 gcvNULL));
1261 /* Delete the database. */
1262 gcmkONERROR(gckKERNEL_DeleteDatabase(Kernel, database));
1264 /* Success. */
1265 gcmkFOOTER_NO();
1266 return gcvSTATUS_OK;
1268 OnError:
1269 /* Return the status. */
1270 gcmkFOOTER();
1271 return status;
1274 /*******************************************************************************
1275 ** gckKERNEL_QueryProcessDB
1277 ** Query a process database for the current usage of a particular record type.
1279 ** INPUT:
1281 ** gckKERNEL Kernel
1282 ** Pointer to a gckKERNEL object.
1284 ** gctUINT32 ProcessID
1285 ** Process ID used to identify the database.
1287 ** gctBOOL LastProcessID
1288 ** gcvTRUE if searching for the last known process ID. gcvFALSE if
1289 ** we need to search for the process ID specified by the ProcessID
1290 ** argument.
1292 ** gceDATABASE_TYPE Type
1293 ** Type of the record to query.
1295 ** OUTPUT:
1297 ** gcuDATABASE_INFO * Info
1298 ** Pointer to a variable that receives the requested information.
1300 gceSTATUS
1301 gckKERNEL_QueryProcessDB(
1302 IN gckKERNEL Kernel,
1303 IN gctUINT32 ProcessID,
1304 IN gctBOOL LastProcessID,
1305 IN gceDATABASE_TYPE Type,
1306 OUT gcuDATABASE_INFO * Info
1309 gceSTATUS status;
1310 gcsDATABASE_PTR database;
1312 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Info=0x%x",
1313 Kernel, ProcessID, Type, Info);
1315 /* Verify the arguments. */
1316 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1317 gcmkVERIFY_ARGUMENT(Info != gcvNULL);
1319 /* Find the database. */
1320 gcmkONERROR(
1321 gckKERNEL_FindDatabase(Kernel, ProcessID, LastProcessID, &database));
1323 /* Get pointer to counters. */
1324 switch (Type)
1326 case gcvDB_VIDEO_MEMORY:
1327 gcmkONERROR(gckOS_MemCopy(&Info->counters,
1328 &database->vidMem,
1329 gcmSIZEOF(database->vidMem)));
1330 break;
1332 case gcvDB_NON_PAGED:
1333 gcmkONERROR(gckOS_MemCopy(&Info->counters,
1334 &database->nonPaged,
1335 gcmSIZEOF(database->vidMem)));
1336 break;
1338 case gcvDB_CONTIGUOUS:
1339 gcmkONERROR(gckOS_MemCopy(&Info->counters,
1340 &database->contiguous,
1341 gcmSIZEOF(database->vidMem)));
1342 break;
1344 case gcvDB_IDLE:
1345 Info->time = Kernel->db->idleTime;
1346 Kernel->db->idleTime = 0;
1347 break;
1349 case gcvDB_MAP_MEMORY:
1350 gcmkONERROR(gckOS_MemCopy(&Info->counters,
1351 &database->mapMemory,
1352 gcmSIZEOF(database->mapMemory)));
1353 break;
1355 case gcvDB_MAP_USER_MEMORY:
1356 gcmkONERROR(gckOS_MemCopy(&Info->counters,
1357 &database->mapUserMemory,
1358 gcmSIZEOF(database->mapUserMemory)));
1359 break;
1361 default:
1362 break;
1365 /* Success. */
1366 gcmkFOOTER_NO();
1367 return gcvSTATUS_OK;
1369 OnError:
1370 /* Return the status. */
1371 gcmkFOOTER();
1372 return status;
1375 #if gcdSECURE_USER
1376 /*******************************************************************************
1377 ** gckKERNEL_GetProcessDBCache
1379 ** Get teh secure cache from a process database.
1381 ** INPUT:
1383 ** gckKERNEL Kernel
1384 ** Pointer to a gckKERNEL object.
1386 ** gctUINT32 ProcessID
1387 ** Process ID used to identify the database.
1389 ** OUTPUT:
1391 ** gcskSECURE_CACHE_PTR * Cache
1392 ** Pointer to a variable that receives the secure cache pointer.
1394 gceSTATUS
1395 gckKERNEL_GetProcessDBCache(
1396 IN gckKERNEL Kernel,
1397 IN gctUINT32 ProcessID,
1398 OUT gcskSECURE_CACHE_PTR * Cache
1401 gceSTATUS status;
1402 gcsDATABASE_PTR database;
1404 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
1406 /* Verify the arguments. */
1407 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1408 gcmkVERIFY_ARGUMENT(Cache != gcvNULL);
1410 /* Find the database. */
1411 gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1413 /* Return the pointer to the cache. */
1414 *Cache = &database->cache;
1416 /* Success. */
1417 gcmkFOOTER_ARG("*Cache=0x%x", *Cache);
1418 return gcvSTATUS_OK;
1420 OnError:
1421 /* Return the status. */
1422 gcmkFOOTER();
1423 return status;
1425 #endif