1 /****************************************************************************
3 * Copyright (C) 2005 - 2014 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 *****************************************************************************/
22 #include "gc_hal_kernel_precomp.h"
24 #define _GC_OBJ_ZONE gcvZONE_DATABASE
26 /*******************************************************************************
27 ***** Private fuctions ********************************************************/
29 #define _GetSlot(database, x) \
30 (gctUINT32)(gcmPTR_TO_UINT64(x) % gcmCOUNTOF(database->list))
32 /*******************************************************************************
33 ** gckKERNEL_NewDatabase
35 ** Create a new database structure and insert it to the head of the hash list.
40 ** Pointer to a gckKERNEL object.
42 ** gctUINT32 ProcessID
43 ** ProcessID that identifies the database.
47 ** gcsDATABASE_PTR * Database
48 ** Pointer to a variable receiving the database structure pointer on
52 gckKERNEL_NewDatabase(
54 IN gctUINT32 ProcessID,
55 OUT gcsDATABASE_PTR * Database
59 gcsDATABASE_PTR database;
60 gctBOOL acquired = gcvFALSE;
62 gcsDATABASE_PTR existingDatabase;
64 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
66 /* Acquire the database mutex. */
67 gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
70 /* Compute the hash for the database. */
71 slot = ProcessID % gcmCOUNTOF(Kernel->db->db);
73 /* Walk the hash list. */
74 for (existingDatabase = Kernel->db->db[slot];
75 existingDatabase != gcvNULL;
76 existingDatabase = existingDatabase->next)
78 if (existingDatabase->processID == ProcessID)
80 /* One process can't be added twice. */
81 gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
85 if (Kernel->db->freeDatabase != gcvNULL)
87 /* Allocate a database from the free list. */
88 database = Kernel->db->freeDatabase;
89 Kernel->db->freeDatabase = database->next;
93 gctPOINTER pointer = gcvNULL;
95 /* Allocate a new database from the heap. */
96 gcmkONERROR(gckOS_Allocate(Kernel->os,
97 gcmSIZEOF(gcsDATABASE),
100 gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsDATABASE));
104 gcmkONERROR(gckOS_CreateMutex(Kernel->os, &database->counterMutex));
107 /* Insert the database into the hash. */
108 database->next = Kernel->db->db[slot];
109 Kernel->db->db[slot] = database;
111 /* Save the hash slot. */
112 database->slot = slot;
114 /* Release the database mutex. */
115 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
117 /* Return the database. */
118 *Database = database;
121 gcmkFOOTER_ARG("*Database=0x%x", *Database);
127 /* Release the database mutex. */
128 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
131 /* Return the status. */
136 /*******************************************************************************
137 ** gckKERNEL_FindDatabase
139 ** Find a database identified by a process ID and move it to the head of the
145 ** Pointer to a gckKERNEL object.
147 ** gctUINT32 ProcessID
148 ** ProcessID that identifies the database.
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
157 ** gcsDATABASE_PTR * Database
158 ** Pointer to a variable receiving the database structure pointer on
162 gckKERNEL_FindDatabase(
164 IN gctUINT32 ProcessID,
165 IN gctBOOL LastProcessID,
166 OUT gcsDATABASE_PTR * Database
170 gcsDATABASE_PTR database, previous;
172 gctBOOL acquired = gcvFALSE;
174 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d LastProcessID=%d",
175 Kernel, ProcessID, LastProcessID);
177 /* Compute the hash for the database. */
178 slot = ProcessID % gcmCOUNTOF(Kernel->db->db);
180 /* Acquire the database mutex. */
182 gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
185 /* Check whether we are getting the last known database. */
188 /* Use last database. */
189 database = Kernel->db->lastDatabase;
191 if (database == gcvNULL)
193 /* Database not found. */
194 gcmkONERROR(gcvSTATUS_INVALID_DATA);
199 /* Walk the hash list. */
200 for (previous = gcvNULL, database = Kernel->db->db[slot];
202 database = database->next)
204 if (database->processID == ProcessID)
213 if (database == gcvNULL)
215 /* Database not found. */
216 gcmkONERROR(gcvSTATUS_INVALID_DATA);
219 if (previous != gcvNULL)
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;
228 /* Release the database mutex. */
229 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
231 /* Return the database. */
232 *Database = database;
235 gcmkFOOTER_ARG("*Database=0x%x", *Database);
241 /* Release the database mutex. */
242 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
245 /* Return the status. */
250 /*******************************************************************************
251 ** gckKERNEL_DeleteDatabase
253 ** Remove a database from the hash list and delete its structure.
258 ** Pointer to a gckKERNEL object.
260 ** gcsDATABASE_PTR Database
261 ** Pointer to the database structure to remove.
268 gckKERNEL_DeleteDatabase(
270 IN gcsDATABASE_PTR Database
274 gctBOOL acquired = gcvFALSE;
275 gcsDATABASE_PTR database;
277 gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database);
279 /* Acquire the database mutex. */
281 gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
284 /* Check slot value. */
285 gcmkVERIFY_ARGUMENT(Database->slot < gcmCOUNTOF(Kernel->db->db));
287 if (Database->slot < gcmCOUNTOF(Kernel->db->db))
289 /* Check if database if the head of the hash list. */
290 if (Kernel->db->db[Database->slot] == Database)
292 /* Remove the database from the hash list. */
293 Kernel->db->db[Database->slot] = Database->next;
297 /* Walk the has list to find the database. */
298 for (database = Kernel->db->db[Database->slot];
300 database = database->next
303 /* Check if the next list entry is this database. */
304 if (database->next == Database)
306 /* Remove the database from the hash list. */
307 database->next = Database->next;
312 if (database == gcvNULL)
314 /* Ouch! Something got corrupted. */
315 gcmkONERROR(gcvSTATUS_INVALID_DATA);
320 if (Kernel->db->lastDatabase != gcvNULL)
322 /* Insert database to the free list. */
323 Kernel->db->lastDatabase->next = Kernel->db->freeDatabase;
324 Kernel->db->freeDatabase = Kernel->db->lastDatabase;
327 /* Keep database as the last database. */
328 Kernel->db->lastDatabase = Database;
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;
336 #if gcdPROCESS_ADDRESS_SPACE
337 /* Destory process MMU. */
338 gcmkVERIFY_OK(gckEVENT_DestroyMmu(Kernel->eventObj, Database->mmu, gcvKERNEL_PIXEL));
339 Database->mmu = gcvNULL;
342 /* Release the database mutex. */
343 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
352 /* Release the database mutex. */
353 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
356 /* Return the status. */
361 /*******************************************************************************
362 ** gckKERNEL_NewRecord
364 ** Create a new database record structure and insert it to the head of the
370 ** Pointer to a gckKERNEL object.
372 ** gcsDATABASE_PTR Database
373 ** Pointer to a database structure.
377 ** gcsDATABASE_RECORD_PTR * Record
378 ** Pointer to a variable receiving the database record structure
379 ** pointer on success.
384 IN gcsDATABASE_PTR Database,
386 OUT gcsDATABASE_RECORD_PTR * Record
390 gctBOOL acquired = gcvFALSE;
391 gcsDATABASE_RECORD_PTR record = gcvNULL;
393 gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database);
395 /* Acquire the database mutex. */
397 gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
400 if (Kernel->db->freeRecord != gcvNULL)
402 /* Allocate the record from the free list. */
403 record = Kernel->db->freeRecord;
404 Kernel->db->freeRecord = record->next;
408 gctPOINTER pointer = gcvNULL;
410 /* Allocate the record from the heap. */
411 gcmkONERROR(gckOS_Allocate(Kernel->os,
412 gcmSIZEOF(gcsDATABASE_RECORD),
418 /* Insert the record in the database. */
419 record->next = Database->list[Slot];
420 Database->list[Slot] = record;
422 /* Release the database mutex. */
423 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
425 /* Return the record. */
429 gcmkFOOTER_ARG("*Record=0x%x", *Record);
435 /* Release the database mutex. */
436 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
438 if (record != gcvNULL)
440 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record));
443 /* Return the status. */
448 /*******************************************************************************
449 ** gckKERNEL_DeleteRecord
451 ** Remove a database record from the database and delete its structure.
456 ** Pointer to a gckKERNEL object.
458 ** gcsDATABASE_PTR Database
459 ** Pointer to a database structure.
461 ** gceDATABASE_TYPE Type
462 ** Type of the record to remove.
465 ** Data of the record to remove.
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.
474 gckKERNEL_DeleteRecord(
476 IN gcsDATABASE_PTR Database,
477 IN gceDATABASE_TYPE Type,
479 OUT gctSIZE_T_PTR Bytes OPTIONAL
483 gctBOOL acquired = gcvFALSE;
484 gcsDATABASE_RECORD_PTR record, previous;
485 gctUINT32 slot = _GetSlot(Database, Data);
487 gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x",
488 Kernel, Database, Type, Data);
490 /* Acquire the database mutex. */
492 gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
495 /* Scan the database for this record. */
496 for (record = Database->list[slot], previous = gcvNULL;
498 record = record->next
501 if ((record->type == Type)
502 && (record->data == Data)
512 if (record == gcvNULL)
514 /* Ouch! This record is not found? */
515 gcmkONERROR(gcvSTATUS_INVALID_DATA);
518 if (Bytes != gcvNULL)
520 /* Return size of record. */
521 *Bytes = record->bytes;
524 /* Remove record from database. */
525 if (previous == gcvNULL)
527 Database->list[slot] = record->next;
531 previous->next = record->next;
534 /* Insert record in free list. */
535 record->next = Kernel->db->freeRecord;
536 Kernel->db->freeRecord = record;
538 /* Release the database mutex. */
539 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
542 gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
548 /* Release the database mutex. */
549 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
552 /* Return the status. */
557 /*******************************************************************************
558 ** gckKERNEL_FindRecord
560 ** Find a database record from the database.
565 ** Pointer to a gckKERNEL object.
567 ** gcsDATABASE_PTR Database
568 ** Pointer to a database structure.
570 ** gceDATABASE_TYPE Type
571 ** Type of the record to remove.
574 ** Data of the record to remove.
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.
583 gckKERNEL_FindRecord(
585 IN gcsDATABASE_PTR Database,
586 IN gceDATABASE_TYPE Type,
588 OUT gcsDATABASE_RECORD_PTR Record
592 gctBOOL acquired = gcvFALSE;
593 gcsDATABASE_RECORD_PTR record;
594 gctUINT32 slot = _GetSlot(Database, Data);
596 gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x",
597 Kernel, Database, Type, Data);
599 /* Acquire the database mutex. */
601 gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
604 /* Scan the database for this record. */
605 for (record = Database->list[slot];
607 record = record->next
610 if ((record->type == Type)
611 && (record->data == Data)
619 if (record == gcvNULL)
621 /* Ouch! This record is not found? */
622 gcmkONERROR(gcvSTATUS_INVALID_DATA);
625 if (Record != gcvNULL)
627 /* Return information of record. */
629 gckOS_MemCopy(Record, record, sizeof(gcsDATABASE_RECORD)));
632 /* Release the database mutex. */
633 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
636 gcmkFOOTER_ARG("Record=0x%x", Record);
642 /* Release the database mutex. */
643 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
646 /* Return the status. */
651 /*******************************************************************************
652 ***** Public API **************************************************************/
654 /*******************************************************************************
655 ** gckKERNEL_CreateProcessDB
657 ** Create a new process database.
662 ** Pointer to a gckKERNEL object.
664 ** gctUINT32 ProcessID
665 ** Process ID used to identify the database.
672 gckKERNEL_CreateProcessDB(
674 IN gctUINT32 ProcessID
678 gcsDATABASE_PTR database = gcvNULL;
681 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
683 /* Verify the arguments. */
684 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
686 /* Create a new database. */
687 gcmkONERROR(gckKERNEL_NewDatabase(Kernel, ProcessID, &database));
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;
710 for (i = 0; i < gcmCOUNTOF(database->list); i++)
712 database->list[i] = gcvNULL;
715 for (i = 0; i < gcvSURF_NUM_TYPES; i++)
717 database->vidMemType[i].bytes = 0;
718 database->vidMemType[i].maxBytes = 0;
719 database->vidMemType[i].totalBytes = 0;
722 for (i = 0; i < gcvPOOL_NUMBER_OF_POOLS; i++)
724 database->vidMemPool[i].bytes = 0;
725 database->vidMemPool[i].maxBytes = 0;
726 database->vidMemPool[i].totalBytes = 0;
729 gcmkASSERT(database->handleDatabase == gcvNULL);
731 gckKERNEL_CreateIntegerDatabase(Kernel, &database->handleDatabase));
733 gcmkASSERT(database->handleDatabaseMutex == gcvNULL);
735 gckOS_CreateMutex(Kernel->os, &database->handleDatabaseMutex));
737 #if gcdPROCESS_ADDRESS_SPACE
738 gcmkASSERT(database->mmu == gcvNULL);
740 gckMMU_Construct(Kernel, gcdMMU_SIZE, &database->mmu));
746 gcskSECURE_CACHE * cache = &database->cache;
748 /* Setup the linked list of cache nodes. */
749 for (slot = 1; slot <= gcdSECURE_CACHE_SLOTS; ++slot)
751 cache->cache[slot].logical = gcvNULL;
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];
757 #if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
758 cache->cache[slot].nextHash = gcvNULL;
759 cache->cache[slot].prevHash = gcvNULL;
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;
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];
774 #if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
775 /* Zero out the hash table. */
776 for (slot = 0; slot < gcmCOUNTOF(cache->hash); ++slot)
778 cache->hash[slot].logical = gcvNULL;
779 cache->hash[slot].nextHash = gcvNULL;
783 /* Initialize cache index. */
784 cache->cacheIndex = gcvNULL;
785 cache->cacheFree = 1;
786 cache->cacheStamp = 0;
790 /* Reset idle timer. */
791 Kernel->db->lastIdle = 0;
798 /* Return the status. */
803 /*******************************************************************************
804 ** gckKERNEL_AddProcessDB
806 ** Add a record to a process database.
811 ** Pointer to a gckKERNEL object.
813 ** gctUINT32 ProcessID
814 ** Process ID used to identify the database.
816 ** gceDATABASE_TYPE TYPE
817 ** Type of the record to add.
819 ** gctPOINTER Pointer
820 ** Data of the record to add.
822 ** gctPHYS_ADDR Physical
823 ** Physical address of the record to add.
826 ** Size of the record to add.
833 gckKERNEL_AddProcessDB(
835 IN gctUINT32 ProcessID,
836 IN gceDATABASE_TYPE Type,
837 IN gctPOINTER Pointer,
838 IN gctPHYS_ADDR Physical,
843 gcsDATABASE_PTR database;
844 gcsDATABASE_RECORD_PTR record = gcvNULL;
845 gcsDATABASE_COUNTERS * count;
846 gctUINT32 vidMemType;
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);
853 /* Verify the arguments. */
854 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
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;
860 Type &= gcdDATABASE_TYPE_MASK;
862 /* Special case the idle record. */
863 if (Type == gcvDB_IDLE)
867 /* Get the current profile time. */
868 gcmkONERROR(gckOS_GetProfileTick(&time));
870 if ((ProcessID == 0) && (Kernel->db->lastIdle != 0))
872 /* Out of idle, adjust time it was idle. */
873 Kernel->db->idleTime += time - Kernel->db->lastIdle;
874 Kernel->db->lastIdle = 0;
876 else if (ProcessID == 1)
878 /* Save current idle time. */
879 Kernel->db->lastIdle = time;
884 /* Test for first call. */
885 if (Kernel->db->lastSlowdown == 0)
887 /* Save milliseconds. */
888 Kernel->db->lastSlowdown = time;
889 Kernel->db->lastSlowdownIdle = Kernel->db->idleTime;
893 /* Compute ellapsed time in milliseconds. */
894 gctUINT delta = gckOS_ProfileToMS(time - Kernel->db->lastSlowdown);
896 /* Test for end of period. */
897 if (delta >= gcdDYNAMIC_SPEED)
899 /* Compute number of idle milliseconds. */
900 gctUINT idle = gckOS_ProfileToMS(
901 Kernel->db->idleTime - Kernel->db->lastSlowdownIdle);
903 /* Broadcast to slow down the GPU. */
904 gcmkONERROR(gckOS_BroadcastCalibrateSpeed(Kernel->os,
909 /* Save current time. */
910 Kernel->db->lastSlowdown = time;
911 Kernel->db->lastSlowdownIdle = Kernel->db->idleTime;
922 /* Verify the arguments. */
923 gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
925 /* Find the database. */
926 gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
928 /* Create a new record in the database. */
929 gcmkONERROR(gckKERNEL_NewRecord(Kernel, database, _GetSlot(database, Pointer), &record));
931 /* Initialize the record. */
932 record->kernel = Kernel;
934 record->data = Pointer;
935 record->physical = Physical;
936 record->bytes = Size;
938 /* Get pointer to counters. */
941 case gcvDB_VIDEO_MEMORY:
942 count = &database->vidMem;
945 case gcvDB_NON_PAGED:
946 count = &database->nonPaged;
949 case gcvDB_CONTIGUOUS:
950 count = &database->contiguous;
953 case gcvDB_MAP_MEMORY:
954 count = &database->mapMemory;
957 case gcvDB_MAP_USER_MEMORY:
958 count = &database->mapUserMemory;
961 case gcvDB_COMMAND_BUFFER:
962 count = &database->virtualCommandBuffer;
970 gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE));
972 if (count != gcvNULL)
974 /* Adjust counters. */
975 count->totalBytes += Size;
976 count->bytes += Size;
978 if (count->bytes > count->maxBytes)
980 count->maxBytes = count->bytes;
984 if (Type == gcvDB_VIDEO_MEMORY)
986 count = &database->vidMemType[vidMemType];
988 /* Adjust counters. */
989 count->totalBytes += Size;
990 count->bytes += Size;
992 if (count->bytes > count->maxBytes)
994 count->maxBytes = count->bytes;
997 count = &database->vidMemPool[vidMemPool];
999 /* Adjust counters. */
1000 count->totalBytes += Size;
1001 count->bytes += Size;
1003 if (count->bytes > count->maxBytes)
1005 count->maxBytes = count->bytes;
1009 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex));
1013 return gcvSTATUS_OK;
1016 /* Return the status. */
1021 /*******************************************************************************
1022 ** gckKERNEL_RemoveProcessDB
1024 ** Remove a record from a process database.
1029 ** Pointer to a gckKERNEL object.
1031 ** gctUINT32 ProcessID
1032 ** Process ID used to identify the database.
1034 ** gceDATABASE_TYPE TYPE
1035 ** Type of the record to remove.
1037 ** gctPOINTER Pointer
1038 ** Data of the record to remove.
1045 gckKERNEL_RemoveProcessDB(
1046 IN gckKERNEL Kernel,
1047 IN gctUINT32 ProcessID,
1048 IN gceDATABASE_TYPE Type,
1049 IN gctPOINTER Pointer
1053 gcsDATABASE_PTR database;
1054 gctSIZE_T bytes = 0;
1055 gctUINT32 vidMemType;
1058 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x",
1059 Kernel, ProcessID, Type, Pointer);
1061 /* Verify the arguments. */
1062 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1063 gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
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;
1069 Type &= gcdDATABASE_TYPE_MASK;
1071 /* Find the database. */
1072 gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1074 /* Delete the record. */
1076 gckKERNEL_DeleteRecord(Kernel, database, Type, Pointer, &bytes));
1078 gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE));
1080 /* Update counters. */
1083 case gcvDB_VIDEO_MEMORY:
1084 database->vidMem.bytes -= bytes;
1085 database->vidMemType[vidMemType].bytes -= bytes;
1086 database->vidMemPool[vidMempool].bytes -= bytes;
1089 case gcvDB_NON_PAGED:
1090 database->nonPaged.bytes -= bytes;
1093 case gcvDB_CONTIGUOUS:
1094 database->contiguous.bytes -= bytes;
1097 case gcvDB_MAP_MEMORY:
1098 database->mapMemory.bytes -= bytes;
1101 case gcvDB_MAP_USER_MEMORY:
1102 database->mapUserMemory.bytes -= bytes;
1105 case gcvDB_COMMAND_BUFFER:
1106 database->virtualCommandBuffer.bytes -= bytes;
1113 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex));
1117 return gcvSTATUS_OK;
1120 /* Return the status. */
1125 /*******************************************************************************
1126 ** gckKERNEL_FindProcessDB
1128 ** Find a record from a process database.
1133 ** Pointer to a gckKERNEL object.
1135 ** gctUINT32 ProcessID
1136 ** Process ID used to identify the database.
1138 ** gceDATABASE_TYPE TYPE
1139 ** Type of the record to remove.
1141 ** gctPOINTER Pointer
1142 ** Data of the record to remove.
1146 ** gcsDATABASE_RECORD_PTR Record
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
1160 gcsDATABASE_PTR database;
1162 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x",
1163 Kernel, ProcessID, ThreadID, Type, Pointer);
1165 /* Verify the arguments. */
1166 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1167 gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
1169 /* Find the database. */
1170 gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1172 /* Find the record. */
1174 gckKERNEL_FindRecord(Kernel, database, Type, Pointer, Record));
1178 return gcvSTATUS_OK;
1181 /* Return the status. */
1186 /*******************************************************************************
1187 ** gckKERNEL_DestroyProcessDB
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.
1196 ** Pointer to a gckKERNEL object.
1198 ** gctUINT32 ProcessID
1199 ** Process ID used to identify the database.
1206 gckKERNEL_DestroyProcessDB(
1207 IN gckKERNEL Kernel,
1208 IN gctUINT32 ProcessID
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;
1221 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
1223 /* Verify the arguments. */
1224 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1226 /* Find the database. */
1227 gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
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);
1253 if (database->list != gcvNULL)
1255 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1256 "Process %d has entries in its database:",
1260 for(i = 0; i < gcmCOUNTOF(database->list); i++)
1263 /* Walk all records. */
1264 for (record = database->list[i]; record != gcvNULL; record = next)
1266 /* Next next record. */
1267 next = record->next;
1269 /* Dispatch on record type. */
1270 switch (record->type)
1272 case gcvDB_VIDEO_MEMORY:
1273 gcmkERR_BREAK(gckVIDMEM_HANDLE_Lookup(record->kernel,
1275 gcmPTR2INT32(record->data),
1278 /* Free the video memory. */
1279 gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel,
1281 gcmPTR2INT32(record->data)));
1283 gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel,
1286 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1287 "DB: VIDEO_MEMORY 0x%x (status=%d)",
1288 record->data, status);
1291 case gcvDB_NON_PAGED:
1292 physical = gcmNAME_TO_PTR(record->physical);
1293 /* Unmap user logical memory first. */
1294 status = gckOS_UnmapUserLogical(Kernel->os,
1299 /* Free the non paged memory. */
1300 status = gckEVENT_FreeNonPagedMemory(Kernel->eventObj,
1305 gcmRELEASE_NAME(record->physical);
1307 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1308 "DB: NON_PAGED 0x%x, bytes=%lu (status=%d)",
1309 record->data, record->bytes, status);
1312 case gcvDB_COMMAND_BUFFER:
1313 /* Free the command buffer. */
1314 status = gckEVENT_DestroyVirtualCommandBuffer(record->kernel->eventObj,
1316 gcmNAME_TO_PTR(record->physical),
1319 gcmRELEASE_NAME(record->physical);
1321 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1322 "DB: COMMAND_BUFFER 0x%x, bytes=%lu (status=%d)",
1323 record->data, record->bytes, status);
1326 case gcvDB_CONTIGUOUS:
1327 physical = gcmNAME_TO_PTR(record->physical);
1328 /* Unmap user logical memory first. */
1329 status = gckOS_UnmapUserLogical(Kernel->os,
1334 /* Free the contiguous memory. */
1335 status = gckEVENT_FreeContiguousMemory(Kernel->eventObj,
1340 gcmRELEASE_NAME(record->physical);
1342 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1343 "DB: CONTIGUOUS 0x%x bytes=%lu (status=%d)",
1344 record->data, record->bytes, status);
1348 #if USE_NEW_LINUX_SIGNAL
1349 status = gcvSTATUS_NOT_SUPPORTED;
1351 /* Free the user signal. */
1352 status = gckOS_DestroyUserSignal(Kernel->os,
1353 gcmPTR2INT32(record->data));
1354 #endif /* USE_NEW_LINUX_SIGNAL */
1356 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1357 "DB: SIGNAL %d (status=%d)",
1358 (gctINT)(gctUINTPTR_T)record->data, status);
1361 case gcvDB_VIDEO_MEMORY_LOCKED:
1362 handle = gcmPTR2INT32(record->data);
1364 gcmkERR_BREAK(gckVIDMEM_HANDLE_Lookup(record->kernel,
1369 /* Unlock what we still locked */
1370 status = gckVIDMEM_Unlock(record->kernel,
1376 if (record->kernel->core == gcvCORE_VG)
1378 if (gcmIS_SUCCESS(status) && (gcvTRUE == asynchronous))
1380 /* TODO: we maybe need to schedule a event here */
1381 status = gckVIDMEM_Unlock(record->kernel,
1387 gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel,
1391 gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel,
1397 gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel,
1401 if (gcmIS_SUCCESS(status) && (gcvTRUE == asynchronous))
1403 status = gckEVENT_Unlock(record->kernel->eventObj,
1410 gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel,
1415 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1416 "DB: VIDEO_MEMORY_LOCKED 0x%x (status=%d)",
1417 record->data, status);
1421 /* TODO: Free the context */
1422 status = gckCOMMAND_Detach(Kernel->command, gcmNAME_TO_PTR(record->data));
1423 gcmRELEASE_NAME(record->data);
1425 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1426 "DB: CONTEXT 0x%x (status=%d)",
1427 record->data, status);
1430 case gcvDB_MAP_MEMORY:
1432 status = gckKERNEL_UnmapMemory(Kernel,
1437 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1438 "DB: MAP MEMORY %d (status=%d)",
1439 gcmPTR2INT32(record->data), status);
1442 case gcvDB_MAP_USER_MEMORY:
1443 /* TODO: Unmap user memory. */
1444 status = gckOS_UnmapUserMemory(Kernel->os,
1448 gcmNAME_TO_PTR(record->data),
1450 gcmRELEASE_NAME(record->data);
1452 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1453 "DB: MAP USER MEMORY %d (status=%d)",
1454 gcmPTR2INT32(record->data), status);
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);
1463 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1464 "DB: SYNC POINT %d (status=%d)",
1465 (gctINT)(gctUINTPTR_T)record->data, status);
1470 /* Free shared buffer. */
1471 status = gckKERNEL_DestroyShBuffer(Kernel,
1472 (gctSHBUF) record->data);
1474 gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
1475 "DB: SHBUF %u (status=%d)",
1476 (gctUINT32)(gctUINTPTR_T) record->data, status);
1480 gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DATABASE,
1481 "DB: Correcupted record=0x%08x type=%d",
1482 record, record->type);
1486 /* Delete the record. */
1487 gcmkONERROR(gckKERNEL_DeleteRecord(Kernel,
1496 /* Delete the database. */
1497 gcmkONERROR(gckKERNEL_DeleteDatabase(Kernel, database));
1501 return gcvSTATUS_OK;
1504 /* Return the status. */
1509 /*******************************************************************************
1510 ** gckKERNEL_QueryProcessDB
1512 ** Query a process database for the current usage of a particular record type.
1517 ** Pointer to a gckKERNEL object.
1519 ** gctUINT32 ProcessID
1520 ** Process ID used to identify the database.
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
1527 ** gceDATABASE_TYPE Type
1528 ** Type of the record to query.
1532 ** gcuDATABASE_INFO * Info
1533 ** Pointer to a variable that receives the requested information.
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
1545 gcsDATABASE_PTR database;
1548 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Info=0x%x",
1549 Kernel, ProcessID, Type, Info);
1551 /* Verify the arguments. */
1552 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1553 gcmkVERIFY_ARGUMENT(Info != gcvNULL);
1556 vidMemPool = (Type & gcdDB_VIDEO_MEMORY_POOL_MASK) >> gcdDB_VIDEO_MEMORY_POOL_SHIFT;
1558 Type &= gcdDATABASE_TYPE_MASK;
1560 /* Find the database. */
1561 if(Type != gcvDB_IDLE)
1564 gckKERNEL_FindDatabase(Kernel, ProcessID, LastProcessID, &database));
1566 gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE));
1568 /* Get pointer to counters. */
1571 case gcvDB_VIDEO_MEMORY:
1572 if (vidMemPool != gcvPOOL_UNKNOWN)
1574 gckOS_MemCopy(&Info->counters,
1575 &database->vidMemPool[vidMemPool],
1576 gcmSIZEOF(database->vidMemPool[vidMemPool]));
1580 gckOS_MemCopy(&Info->counters,
1582 gcmSIZEOF(database->vidMem));
1586 case gcvDB_NON_PAGED:
1587 gckOS_MemCopy(&Info->counters,
1588 &database->nonPaged,
1589 gcmSIZEOF(database->vidMem));
1592 case gcvDB_CONTIGUOUS:
1593 gckOS_MemCopy(&Info->counters,
1594 &database->contiguous,
1595 gcmSIZEOF(database->vidMem));
1598 case gcvDB_MAP_MEMORY:
1599 gckOS_MemCopy(&Info->counters,
1600 &database->mapMemory,
1601 gcmSIZEOF(database->mapMemory));
1604 case gcvDB_MAP_USER_MEMORY:
1605 gckOS_MemCopy(&Info->counters,
1606 &database->mapUserMemory,
1607 gcmSIZEOF(database->mapUserMemory));
1610 case gcvDB_COMMAND_BUFFER:
1611 gckOS_MemCopy(&Info->counters,
1612 &database->virtualCommandBuffer,
1613 gcmSIZEOF(database->virtualCommandBuffer));
1620 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex));
1624 Info->time = Kernel->db->idleTime;
1625 Kernel->db->idleTime = 0;
1629 return gcvSTATUS_OK;
1632 /* Return the status. */
1638 gckKERNEL_FindHandleDatbase(
1639 IN gckKERNEL Kernel,
1640 IN gctUINT32 ProcessID,
1641 OUT gctPOINTER * HandleDatabase,
1642 OUT gctPOINTER * HandleDatabaseMutex
1646 gcsDATABASE_PTR database;
1648 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d",
1651 /* Verify the arguments. */
1652 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1654 /* Find the database. */
1655 gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1657 *HandleDatabase = database->handleDatabase;
1658 *HandleDatabaseMutex = database->handleDatabaseMutex;
1662 return gcvSTATUS_OK;
1665 /* Return the status. */
1670 #if gcdPROCESS_ADDRESS_SPACE
1672 gckKERNEL_GetProcessMMU(
1673 IN gckKERNEL Kernel,
1678 gcsDATABASE_PTR database;
1679 gctUINT32 processID;
1681 gcmkONERROR(gckOS_GetProcessID(&processID));
1683 gcmkONERROR(gckKERNEL_FindDatabase(Kernel, processID, gcvFALSE, &database));
1685 *Mmu = database->mmu;
1687 return gcvSTATUS_OK;
1695 /*******************************************************************************
1696 ** gckKERNEL_GetProcessDBCache
1698 ** Get teh secure cache from a process database.
1703 ** Pointer to a gckKERNEL object.
1705 ** gctUINT32 ProcessID
1706 ** Process ID used to identify the database.
1710 ** gcskSECURE_CACHE_PTR * Cache
1711 ** Pointer to a variable that receives the secure cache pointer.
1714 gckKERNEL_GetProcessDBCache(
1715 IN gckKERNEL Kernel,
1716 IN gctUINT32 ProcessID,
1717 OUT gcskSECURE_CACHE_PTR * Cache
1721 gcsDATABASE_PTR database;
1723 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
1725 /* Verify the arguments. */
1726 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1727 gcmkVERIFY_ARGUMENT(Cache != gcvNULL);
1729 /* Find the database. */
1730 gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1732 /* Return the pointer to the cache. */
1733 *Cache = &database->cache;
1736 gcmkFOOTER_ARG("*Cache=0x%x", *Cache);
1737 return gcvSTATUS_OK;
1740 /* Return the status. */
1747 gckKERNEL_DumpProcessDB(
1751 gcsDATABASE_PTR database;
1755 gcmkHEADER_ARG("Kernel=0x%x", Kernel);
1757 /* Acquire the database mutex. */
1759 gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
1761 gcmkPRINT("**************************\n");
1762 gcmkPRINT("*** PROCESS DB DUMP ***\n");
1763 gcmkPRINT("**************************\n");
1765 gcmkPRINT_N(8, "%-8s%s\n", "PID", "NAME");
1766 /* Walk the databases. */
1767 for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i)
1769 for (database = Kernel->db->db[i];
1770 database != gcvNULL;
1771 database = database->next)
1773 pid = database->processID;
1775 gcmkVERIFY_OK(gckOS_ZeroMemory(name, gcmSIZEOF(name)));
1777 gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name));
1779 gcmkPRINT_N(8, "%-8d%s\n", pid, name);
1783 /* Release the database mutex. */
1784 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
1788 return gcvSTATUS_OK;
1793 IN gcsDATABASE_COUNTERS * Counter,
1794 IN gctCONST_STRING Name
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);
1804 gckKERNEL_DumpVidMemUsage(
1805 IN gckKERNEL Kernel,
1806 IN gctINT32 ProcessID
1810 gcsDATABASE_PTR database;
1811 gcsDATABASE_COUNTERS * counter;
1814 static gctCONST_STRING surfaceTypes[] = {
1826 "HIERARCHICAL_DEPTH",
1829 gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d",
1832 /* Verify the arguments. */
1833 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1835 /* Find the database. */
1837 gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
1839 gcmkPRINT("VidMem Usage (Process %d):", ProcessID);
1841 /* Get pointer to counters. */
1842 counter = &database->vidMem;
1844 _DumpCounter(counter, "Total Video Memory");
1846 for (i = 0; i < gcvSURF_NUM_TYPES; i++)
1848 counter = &database->vidMemType[i];
1850 _DumpCounter(counter, surfaceTypes[i]);
1855 return gcvSTATUS_OK;
1858 /* Return the status. */