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_KERNEL
26 /*******************************************************************************
27 ***** Version Signature *******************************************************/
29 #define _gcmTXT2STR(t) #t
30 #define gcmTXT2STR(t) _gcmTXT2STR(t)
31 const char * _VERSION = "\n\0$VERSION$"
32 gcmTXT2STR(gcvVERSION_MAJOR) "."
33 gcmTXT2STR(gcvVERSION_MINOR) "."
34 gcmTXT2STR(gcvVERSION_PATCH) ":"
35 gcmTXT2STR(gcvVERSION_BUILD) "$\n";
37 /******************************************************************************\
38 ******************************* gckKERNEL API Code ******************************
39 \******************************************************************************/
41 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
42 #define gcmDEFINE2TEXT(d) #d
43 gctCONST_STRING _DispatchText[] =
45 gcmDEFINE2TEXT(gcvHAL_QUERY_VIDEO_MEMORY),
46 gcmDEFINE2TEXT(gcvHAL_QUERY_CHIP_IDENTITY),
47 gcmDEFINE2TEXT(gcvHAL_ALLOCATE_NON_PAGED_MEMORY),
48 gcmDEFINE2TEXT(gcvHAL_FREE_NON_PAGED_MEMORY),
49 gcmDEFINE2TEXT(gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY),
50 gcmDEFINE2TEXT(gcvHAL_FREE_CONTIGUOUS_MEMORY),
51 gcmDEFINE2TEXT(gcvHAL_ALLOCATE_VIDEO_MEMORY),
52 gcmDEFINE2TEXT(gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY),
53 gcmDEFINE2TEXT(gcvHAL_RELEASE_VIDEO_MEMORY),
54 gcmDEFINE2TEXT(gcvHAL_MAP_MEMORY),
55 gcmDEFINE2TEXT(gcvHAL_UNMAP_MEMORY),
56 gcmDEFINE2TEXT(gcvHAL_MAP_USER_MEMORY),
57 gcmDEFINE2TEXT(gcvHAL_UNMAP_USER_MEMORY),
58 gcmDEFINE2TEXT(gcvHAL_LOCK_VIDEO_MEMORY),
59 gcmDEFINE2TEXT(gcvHAL_UNLOCK_VIDEO_MEMORY),
60 gcmDEFINE2TEXT(gcvHAL_EVENT_COMMIT),
61 gcmDEFINE2TEXT(gcvHAL_USER_SIGNAL),
62 gcmDEFINE2TEXT(gcvHAL_SIGNAL),
63 gcmDEFINE2TEXT(gcvHAL_WRITE_DATA),
64 gcmDEFINE2TEXT(gcvHAL_COMMIT),
65 gcmDEFINE2TEXT(gcvHAL_STALL),
66 gcmDEFINE2TEXT(gcvHAL_READ_REGISTER),
67 gcmDEFINE2TEXT(gcvHAL_WRITE_REGISTER),
68 gcmDEFINE2TEXT(gcvHAL_GET_PROFILE_SETTING),
69 gcmDEFINE2TEXT(gcvHAL_SET_PROFILE_SETTING),
70 gcmDEFINE2TEXT(gcvHAL_READ_ALL_PROFILE_REGISTERS),
71 gcmDEFINE2TEXT(gcvHAL_PROFILE_REGISTERS_2D),
72 #if VIVANTE_PROFILER_PERDRAW
73 gcvHAL_READ_PROFILER_REGISTER_SETTING,
75 gcmDEFINE2TEXT(gcvHAL_SET_POWER_MANAGEMENT_STATE),
76 gcmDEFINE2TEXT(gcvHAL_QUERY_POWER_MANAGEMENT_STATE),
77 gcmDEFINE2TEXT(gcvHAL_GET_BASE_ADDRESS),
78 gcmDEFINE2TEXT(gcvHAL_SET_IDLE),
79 gcmDEFINE2TEXT(gcvHAL_QUERY_KERNEL_SETTINGS),
80 gcmDEFINE2TEXT(gcvHAL_RESET),
81 gcmDEFINE2TEXT(gcvHAL_MAP_PHYSICAL),
82 gcmDEFINE2TEXT(gcvHAL_DEBUG),
83 gcmDEFINE2TEXT(gcvHAL_CACHE),
84 gcmDEFINE2TEXT(gcvHAL_TIMESTAMP),
85 gcmDEFINE2TEXT(gcvHAL_DATABASE),
86 gcmDEFINE2TEXT(gcvHAL_VERSION),
87 gcmDEFINE2TEXT(gcvHAL_CHIP_INFO),
88 gcmDEFINE2TEXT(gcvHAL_ATTACH),
89 gcmDEFINE2TEXT(gcvHAL_DETACH),
90 gcmDEFINE2TEXT(gcvHAL_COMPOSE),
91 gcmDEFINE2TEXT(gcvHAL_SET_TIMEOUT),
92 gcmDEFINE2TEXT(gcvHAL_GET_FRAME_INFO),
93 gcmDEFINE2TEXT(gcvHAL_QUERY_COMMAND_BUFFER),
94 gcmDEFINE2TEXT(gcvHAL_COMMIT_DONE),
95 gcmDEFINE2TEXT(gcvHAL_DUMP_GPU_STATE),
96 gcmDEFINE2TEXT(gcvHAL_DUMP_EVENT),
97 gcmDEFINE2TEXT(gcvHAL_ALLOCATE_VIRTUAL_COMMAND_BUFFER),
98 gcmDEFINE2TEXT(gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER),
99 gcmDEFINE2TEXT(gcvHAL_SET_FSCALE_VALUE),
100 gcmDEFINE2TEXT(gcvHAL_GET_FSCALE_VALUE),
101 gcmDEFINE2TEXT(gcvHAL_NAME_VIDEO_MEMORY),
102 gcmDEFINE2TEXT(gcvHAL_IMPORT_VIDEO_MEMORY),
103 gcmDEFINE2TEXT(gcvHAL_QUERY_RESET_TIME_STAMP),
104 gcmDEFINE2TEXT(gcvHAL_READ_REGISTER_EX),
105 gcmDEFINE2TEXT(gcvHAL_WRITE_REGISTER_EX),
106 gcmDEFINE2TEXT(gcvHAL_SYNC_POINT),
107 gcmDEFINE2TEXT(gcvHAL_CREATE_NATIVE_FENCE),
108 gcmDEFINE2TEXT(gcvHAL_DESTROY_MMU),
109 gcmDEFINE2TEXT(gcvHAL_SHBUF),
113 #if gcdGPU_TIMEOUT && gcdINTERRUPT_STATISTIC
115 _MonitorTimerFunction(
119 gckKERNEL kernel = (gckKERNEL)Data;
120 gctUINT32 pendingInterrupt;
121 gctBOOL reset = gcvFALSE;
123 gctUINT32 advance = kernel->timeOut/2;
126 if (kernel->core == gcvCORE_VG)
132 if (kernel->monitorTimerStop)
138 gckOS_AtomGet(kernel->os, kernel->eventObj->interruptCount, &pendingInterrupt);
140 if (kernel->monitoring == gcvFALSE)
142 if (pendingInterrupt)
144 /* Begin to mointor GPU state. */
145 kernel->monitoring = gcvTRUE;
147 /* Record current state. */
148 kernel->lastCommitStamp = kernel->eventObj->lastCommitStamp;
149 kernel->restoreAddress = kernel->hardware->lastWaitLink;
150 gcmkVERIFY_OK(gckOS_AtomGet(
152 kernel->hardware->pendingEvent,
162 if (pendingInterrupt)
164 gcmkVERIFY_OK(gckOS_AtomGet(
166 kernel->hardware->pendingEvent,
170 if (kernel->eventObj->lastCommitStamp == kernel->lastCommitStamp
171 && kernel->hardware->lastWaitLink == kernel->restoreAddress
172 && mask == kernel->restoreMask
175 /* GPU state is not changed, accumlate timeout. */
176 kernel->timer += advance;
178 if (kernel->timer >= kernel->timeOut)
180 /* GPU stuck, trigger reset. */
186 /* GPU state changed, cancel current timeout.*/
187 kernel->monitoring = gcvFALSE;
192 /* GPU finish all jobs, cancel current timeout*/
193 kernel->monitoring = gcvFALSE;
199 gckKERNEL_Recovery(kernel);
201 /* Work in this timeout is done. */
202 kernel->monitoring = gcvFALSE;
205 gcmkVERIFY_OK(gckOS_StartTimer(kernel->os, kernel->monitorTimer, advance));
209 #if gcdPROCESS_ADDRESS_SPACE
220 gcmkONERROR(gckKERNEL_GetProcessMMU(Kernel, &mmu));
222 for (i = 0; i < gcdCOMMAND_QUEUES; i++)
224 gcmkONERROR(gckOS_GetPhysicalAddress(
226 Kernel->command->queues[i].logical,
230 gcmkONERROR(gckMMU_FlatMapping(mmu, physical));
241 _DumpDriverConfigure(
245 gcmkPRINT_N(0, "**************************\n");
246 gcmkPRINT_N(0, "*** GPU DRV CONFIG ***\n");
247 gcmkPRINT_N(0, "**************************\n");
249 gcmkPRINT("Galcore version %d.%d.%d.%d\n",
250 gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, gcvVERSION_BUILD);
260 /* Dump GPU Debug registers. */
261 gcmkVERIFY_OK(gckHARDWARE_DumpGPUState(Kernel->hardware));
263 if (Kernel->virtualCommandBuffer)
265 gcmkVERIFY_OK(gckCOMMAND_DumpExecutingBuffer(Kernel->command));
268 /* Dump Pending event. */
269 gcmkVERIFY_OK(gckEVENT_Dump(Kernel->eventObj));
271 /* Dump Process DB. */
272 gcmkVERIFY_OK(gckKERNEL_DumpProcessDB(Kernel));
274 #if gcdRECORD_COMMAND
276 gckRECORDER_Dump(Kernel->command->recorder);
280 /*******************************************************************************
282 ** gckKERNEL_Construct
284 ** Construct a new gckKERNEL object.
289 ** Pointer to an gckOS object.
294 ** IN gctPOINTER Context
295 ** Pointer to a driver defined context.
297 ** IN gckDB SharedDB,
298 ** Pointer to a shared DB.
302 ** gckKERNEL * Kernel
303 ** Pointer to a variable that will hold the pointer to the gckKERNEL
311 IN gctPOINTER Context,
313 OUT gckKERNEL * Kernel
316 gckKERNEL kernel = gcvNULL;
319 gctPOINTER pointer = gcvNULL;
321 gcmkHEADER_ARG("Os=0x%x Context=0x%x", Os, Context);
323 /* Verify the arguments. */
324 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
325 gcmkVERIFY_ARGUMENT(Kernel != gcvNULL);
327 /* Allocate the gckKERNEL object. */
328 gcmkONERROR(gckOS_Allocate(Os,
329 gcmSIZEOF(struct _gckKERNEL),
334 /* Zero the object pointers. */
335 kernel->hardware = gcvNULL;
336 kernel->command = gcvNULL;
337 kernel->eventObj = gcvNULL;
338 kernel->mmu = gcvNULL;
340 kernel->dvfs = gcvNULL;
342 kernel->monitorTimer = gcvNULL;
344 /* Initialize the gckKERNEL object. */
345 kernel->object.type = gcvOBJ_KERNEL;
349 if (SharedDB == gcvNULL)
351 gcmkONERROR(gckOS_Allocate(Os,
352 gcmSIZEOF(struct _gckDB),
355 kernel->db = pointer;
356 kernel->dbCreated = gcvTRUE;
357 kernel->db->freeDatabase = gcvNULL;
358 kernel->db->freeRecord = gcvNULL;
359 kernel->db->dbMutex = gcvNULL;
360 kernel->db->lastDatabase = gcvNULL;
361 kernel->db->idleTime = 0;
362 kernel->db->lastIdle = 0;
363 kernel->db->lastSlowdown = 0;
365 for (i = 0; i < gcmCOUNTOF(kernel->db->db); ++i)
367 kernel->db->db[i] = gcvNULL;
370 /* Construct a database mutex. */
371 gcmkONERROR(gckOS_CreateMutex(Os, &kernel->db->dbMutex));
373 /* Construct a video memory name database. */
374 gcmkONERROR(gckKERNEL_CreateIntegerDatabase(kernel, &kernel->db->nameDatabase));
376 /* Construct a video memory name database mutex. */
377 gcmkONERROR(gckOS_CreateMutex(Os, &kernel->db->nameDatabaseMutex));
379 /* Construct a pointer name database. */
380 gcmkONERROR(gckKERNEL_CreateIntegerDatabase(kernel, &kernel->db->pointerDatabase));
382 /* Construct a pointer name database mutex. */
383 gcmkONERROR(gckOS_CreateMutex(Os, &kernel->db->pointerDatabaseMutex));
387 kernel->db = SharedDB;
388 kernel->dbCreated = gcvFALSE;
391 for (i = 0; i < gcmCOUNTOF(kernel->timers); ++i)
393 kernel->timers[i].startTime = 0;
394 kernel->timers[i].stopTime = 0;
398 kernel->context = Context;
400 /* Construct atom holding number of clients. */
401 kernel->atomClients = gcvNULL;
402 gcmkONERROR(gckOS_AtomConstruct(Os, &kernel->atomClients));
405 kernel->vg = gcvNULL;
407 if (Core == gcvCORE_VG)
409 /* Construct the gckMMU object. */
411 gckVGKERNEL_Construct(Os, Context, kernel, &kernel->vg));
413 kernel->timeOut = gcdGPU_TIMEOUT;
418 /* Construct the gckHARDWARE object. */
420 gckHARDWARE_Construct(Os, kernel->core, &kernel->hardware));
422 /* Set pointer to gckKERNEL object in gckHARDWARE object. */
423 kernel->hardware->kernel = kernel;
425 kernel->timeOut = kernel->hardware->type == gcvHARDWARE_2D
430 /* Initialize virtual command buffer. */
431 /* TODO: Remove platform limitation after porting. */
432 #if (defined(LINUX) || defined(__QNXNTO__))
433 kernel->virtualCommandBuffer = gcvTRUE;
435 kernel->virtualCommandBuffer = gcvFALSE;
439 kernel->virtualCommandBuffer = gcvFALSE;
442 /* Construct the gckCOMMAND object. */
444 gckCOMMAND_Construct(kernel, &kernel->command));
446 /* Construct the gckEVENT object. */
448 gckEVENT_Construct(kernel, &kernel->eventObj));
450 /* Construct the gckMMU object. */
452 gckMMU_Construct(kernel, gcdMMU_SIZE, &kernel->mmu));
454 gcmkVERIFY_OK(gckOS_GetTime(&kernel->resetTimeStamp));
456 gcmkONERROR(gckHARDWARE_PrepareFunctions(kernel->hardware));
458 /* Initialize the hardware. */
460 gckHARDWARE_InitializeHardware(kernel->hardware));
463 if (gckHARDWARE_IsFeatureAvailable(kernel->hardware,
464 gcvFEATURE_DYNAMIC_FREQUENCY_SCALING))
466 gcmkONERROR(gckDVFS_Construct(kernel->hardware, &kernel->dvfs));
467 gcmkONERROR(gckDVFS_Start(kernel->dvfs));
473 /* Initialize profile setting */
474 kernel->profileEnable = gcvFALSE;
475 kernel->profileCleanRegister = gcvTRUE;
478 #if gcdANDROID_NATIVE_FENCE_SYNC
479 gcmkONERROR(gckOS_CreateSyncTimeline(Os, &kernel->timeline));
482 kernel->recovery = gcvTRUE;
483 kernel->stuckDump = 1;
485 kernel->virtualBufferHead =
486 kernel->virtualBufferTail = gcvNULL;
489 gckOS_CreateMutex(Os, (gctPOINTER)&kernel->virtualBufferLock));
492 /* Connect to security service for this GPU. */
493 gcmkONERROR(gckKERNEL_SecurityOpen(kernel, kernel->core, &kernel->securityChannel));
496 #if gcdGPU_TIMEOUT && gcdINTERRUPT_STATISTIC
499 gcmkVERIFY_OK(gckOS_CreateTimer(
501 (gctTIMERFUNCTION)_MonitorTimerFunction,
503 &kernel->monitorTimer
506 kernel->monitoring = gcvFALSE;
508 kernel->monitorTimerStop = gcvFALSE;
510 gcmkVERIFY_OK(gckOS_StartTimer(
512 kernel->monitorTimer,
518 /* Return pointer to the gckKERNEL object. */
522 gcmkFOOTER_ARG("*Kernel=0x%x", *Kernel);
526 if (kernel != gcvNULL)
529 if (Core != gcvCORE_VG)
532 if (kernel->eventObj != gcvNULL)
534 gcmkVERIFY_OK(gckEVENT_Destroy(kernel->eventObj));
537 if (kernel->command != gcvNULL)
539 gcmkVERIFY_OK(gckCOMMAND_Destroy(kernel->command));
542 if (kernel->hardware != gcvNULL)
544 /* Turn off the power. */
545 gcmkVERIFY_OK(gckOS_SetGPUPower(kernel->hardware->os,
546 kernel->hardware->core,
549 gcmkVERIFY_OK(gckHARDWARE_Destroy(kernel->hardware));
553 if (kernel->atomClients != gcvNULL)
555 gcmkVERIFY_OK(gckOS_AtomDestroy(Os, kernel->atomClients));
558 if (kernel->dbCreated && kernel->db != gcvNULL)
560 if (kernel->db->dbMutex != gcvNULL)
562 /* Destroy the database mutex. */
563 gcmkVERIFY_OK(gckOS_DeleteMutex(Os, kernel->db->dbMutex));
566 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, kernel->db));
569 if (kernel->virtualBufferLock != gcvNULL)
571 /* Destroy the virtual command buffer mutex. */
572 gcmkVERIFY_OK(gckOS_DeleteMutex(Os, kernel->virtualBufferLock));
578 gcmkVERIFY_OK(gckDVFS_Stop(kernel->dvfs));
579 gcmkVERIFY_OK(gckDVFS_Destroy(kernel->dvfs));
583 #if gcdANDROID_NATIVE_FENCE_SYNC
584 if (kernel->timeline)
586 gcmkVERIFY_OK(gckOS_DestroySyncTimeline(Os, kernel->timeline));
590 if (kernel->monitorTimer)
592 gcmkVERIFY_OK(gckOS_StopTimer(Os, kernel->monitorTimer));
593 gcmkVERIFY_OK(gckOS_DestroyTimer(Os, kernel->monitorTimer));
596 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, kernel));
599 /* Return the error. */
604 /*******************************************************************************
608 ** Destroy an gckKERNEL object.
613 ** Pointer to an gckKERNEL object to destroy.
625 gcsDATABASE_PTR database, databaseNext;
626 gcsDATABASE_RECORD_PTR record, recordNext;
628 gcmkHEADER_ARG("Kernel=0x%x", Kernel);
630 /* Verify the arguments. */
631 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
632 #if QNX_SINGLE_THREADED_DEBUGGING
633 gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->debugMutex));
636 /* Destroy the database. */
637 if (Kernel->dbCreated)
639 for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i)
641 if (Kernel->db->db[i] != gcvNULL)
644 gckKERNEL_DestroyProcessDB(Kernel, Kernel->db->db[i]->processID));
648 /* Free all databases. */
649 for (database = Kernel->db->freeDatabase;
651 database = databaseNext)
653 databaseNext = database->next;
655 gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, database->counterMutex));
656 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, database));
659 if (Kernel->db->lastDatabase != gcvNULL)
661 gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->lastDatabase->counterMutex));
662 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel->db->lastDatabase));
665 /* Free all database records. */
666 for (record = Kernel->db->freeRecord; record != gcvNULL; record = recordNext)
668 recordNext = record->next;
669 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record));
672 /* Destroy the database mutex. */
673 gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->dbMutex));
675 /* Destroy video memory name database. */
676 gcmkVERIFY_OK(gckKERNEL_DestroyIntegerDatabase(Kernel, Kernel->db->nameDatabase));
678 /* Destroy video memory name database mutex. */
679 gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->nameDatabaseMutex));
682 /* Destroy id-pointer database. */
683 gcmkVERIFY_OK(gckKERNEL_DestroyIntegerDatabase(Kernel, Kernel->db->pointerDatabase));
685 /* Destroy id-pointer database mutex. */
686 gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
688 /* Destroy the database. */
689 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel->db));
691 /* Notify stuck timer to quit. */
692 Kernel->monitorTimerStop = gcvTRUE;
698 gcmkVERIFY_OK(gckVGKERNEL_Destroy(Kernel->vg));
703 /* Destroy the gckMMU object. */
704 gcmkVERIFY_OK(gckMMU_Destroy(Kernel->mmu));
706 /* Destroy the gckCOMMNAND object. */
707 gcmkVERIFY_OK(gckCOMMAND_Destroy(Kernel->command));
709 /* Destroy the gckEVENT object. */
710 gcmkVERIFY_OK(gckEVENT_Destroy(Kernel->eventObj));
712 /* Destroy the gckHARDWARE object. */
713 gcmkVERIFY_OK(gckHARDWARE_Destroy(Kernel->hardware));
716 /* Detsroy the client atom. */
717 gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Kernel->atomClients));
719 gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->virtualBufferLock));
724 gcmkVERIFY_OK(gckDVFS_Stop(Kernel->dvfs));
725 gcmkVERIFY_OK(gckDVFS_Destroy(Kernel->dvfs));
729 #if gcdANDROID_NATIVE_FENCE_SYNC
730 gcmkVERIFY_OK(gckOS_DestroySyncTimeline(Kernel->os, Kernel->timeline));
734 gcmkVERIFY_OK(gckKERNEL_SecurityClose(Kernel->securityChannel));
737 if (Kernel->monitorTimer)
739 gcmkVERIFY_OK(gckOS_StopTimer(Kernel->os, Kernel->monitorTimer));
740 gcmkVERIFY_OK(gckOS_DestroyTimer(Kernel->os, Kernel->monitorTimer));
743 /* Mark the gckKERNEL object as unknown. */
744 Kernel->object.type = gcvOBJ_UNKNOWN;
746 /* Free the gckKERNEL object. */
747 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel));
754 /*******************************************************************************
758 ** Private function to walk all required memory pools to allocate the requested
759 ** amount of video memory.
764 ** Pointer to an gckKERNEL object.
766 ** gcsHAL_INTERFACE * Interface
767 ** Pointer to a gcsHAL_INTERFACE structure that defines the command to
772 ** gcsHAL_INTERFACE * Interface
773 ** Pointer to a gcsHAL_INTERFACE structure that receives any data to be
777 gckKERNEL_AllocateLinearMemory(
779 IN gctUINT32 ProcessID,
780 IN OUT gcePOOL * Pool,
782 IN gctUINT32 Alignment,
783 IN gceSURF_TYPE Type,
790 gckVIDMEM videoMemory;
792 gcuVIDMEM_NODE_PTR node = gcvNULL;
793 gctBOOL tileStatusInVirtual;
794 gctBOOL contiguous = gcvFALSE;
795 gctBOOL cacheable = gcvFALSE;
796 gctSIZE_T bytes = Bytes;
797 gctUINT32 handle = 0;
798 gceDATABASE_TYPE type;
800 gcmkHEADER_ARG("Kernel=0x%x *Pool=%d Bytes=%lu Alignment=%lu Type=%d",
801 Kernel, *Pool, Bytes, Alignment, Type);
803 gcmkVERIFY_ARGUMENT(Pool != gcvNULL);
804 gcmkVERIFY_ARGUMENT(Bytes != 0);
806 /* Get basic type. */
810 contiguous = Flag & gcvALLOC_FLAG_CONTIGUOUS;
811 cacheable = Flag & gcvALLOC_FLAG_CACHEABLE;
815 /* Get initial pool. */
816 switch (pool = *Pool)
818 case gcvPOOL_DEFAULT:
820 pool = gcvPOOL_LOCAL_INTERNAL;
821 loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS;
824 case gcvPOOL_UNIFIED:
825 pool = gcvPOOL_SYSTEM;
826 loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS;
829 case gcvPOOL_CONTIGUOUS:
830 loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS;
838 while (loopCount-- > 0)
840 if (pool == gcvPOOL_VIRTUAL)
842 /* Create a gcuVIDMEM_NODE for virtual memory. */
844 gckVIDMEM_ConstructVirtual(Kernel, Flag | gcvALLOC_FLAG_NON_CONTIGUOUS, Bytes, &node));
846 bytes = node->Virtual.bytes;
847 node->Virtual.type = Type;
854 if (pool == gcvPOOL_CONTIGUOUS)
856 #if gcdCONTIGUOUS_SIZE_LIMIT
857 if (Bytes > gcdCONTIGUOUS_SIZE_LIMIT && contiguous == gcvFALSE)
859 status = gcvSTATUS_OUT_OF_MEMORY;
864 /* Create a gcuVIDMEM_NODE from contiguous memory. */
865 status = gckVIDMEM_ConstructVirtual(
867 Flag | gcvALLOC_FLAG_CONTIGUOUS,
872 if (gcmIS_SUCCESS(status))
874 bytes = node->Virtual.bytes;
875 node->Virtual.type = Type;
877 /* Memory allocated. */
883 /* gcvPOOL_SYSTEM can't be cacheable. */
884 if (cacheable == gcvFALSE)
886 /* Get pointer to gckVIDMEM object for pool. */
887 status = gckKERNEL_GetVideoMemoryPool(Kernel, pool, &videoMemory);
889 if (gcmIS_SUCCESS(status))
891 /* Allocate memory. */
892 #if defined(gcdLINEAR_SIZE_LIMIT)
894 if (Bytes > gcdLINEAR_SIZE_LIMIT)
896 status = gcvSTATUS_OUT_OF_MEMORY;
901 status = gckVIDMEM_AllocateLinear(Kernel,
906 (*Pool == gcvPOOL_SYSTEM),
910 if (gcmIS_SUCCESS(status))
912 /* Memory allocated. */
913 node->VidMem.pool = pool;
914 bytes = node->VidMem.bytes;
920 if (pool == gcvPOOL_LOCAL_INTERNAL)
922 /* Advance to external memory. */
923 pool = gcvPOOL_LOCAL_EXTERNAL;
927 if (pool == gcvPOOL_LOCAL_EXTERNAL)
929 /* Advance to contiguous system memory. */
930 pool = gcvPOOL_SYSTEM;
934 if (pool == gcvPOOL_SYSTEM)
936 /* Advance to contiguous memory. */
937 pool = gcvPOOL_CONTIGUOUS;
941 if (pool == gcvPOOL_CONTIGUOUS)
946 tileStatusInVirtual = gcvFALSE;
951 tileStatusInVirtual =
952 gckHARDWARE_IsFeatureAvailable(Kernel->hardware,
956 if (Type == gcvSURF_TILE_STATUS && tileStatusInVirtual != gcvTRUE)
958 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
966 /* Advance to virtual memory. */
967 pool = gcvPOOL_VIRTUAL;
973 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
981 /* Broadcast OOM message. */
982 status = gckOS_Broadcast(Kernel->os, Kernel->hardware, gcvBROADCAST_OUT_OF_MEMORY);
984 if (gcmIS_SUCCESS(status))
986 /* Get some memory. */
987 gckOS_Delay(gcvNULL, 1);
992 /* Nothing allocated. */
993 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
996 /* Allocate handle for this video memory. */
998 gckVIDMEM_NODE_Allocate(Kernel, node, Type, pool, &handle));
1000 /* Return node and pool used for allocation. */
1004 /* Encode surface type and pool to database type. */
1005 type = gcvDB_VIDEO_MEMORY
1006 | (Type << gcdDB_VIDEO_MEMORY_TYPE_SHIFT)
1007 | (pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT);
1009 /* Record in process db. */
1011 gckKERNEL_AddProcessDB(Kernel,
1018 /* Return status. */
1019 gcmkFOOTER_ARG("*Pool=%d *Node=0x%x", *Pool, *Node);
1020 return gcvSTATUS_OK;
1025 /* Destroy handle allocated. */
1026 gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(Kernel, ProcessID, handle));
1031 /* Free video memory allocated. */
1032 gcmkVERIFY_OK(gckVIDMEM_Free(Kernel, node));
1035 /* For some case like chrome with webgl test, it needs too much memory so that it invokes oom_killer
1036 * And the case is killed by oom_killer, the user wants not to see the crash and hope the case iteself handles the condition
1037 * So the patch reports the out_of_memory to the case */
1038 if ( status == gcvSTATUS_OUT_OF_MEMORY && (Flag & gcvALLOC_FLAG_MEMLIMIT) )
1039 gcmkPRINT("The running case is out_of_memory");
1041 /* Return the status. */
1046 /*******************************************************************************
1048 ** gckKERNEL_ReleaseVideoMemory
1050 ** Release handle of a video memory.
1055 ** Pointer to an gckKERNEL object.
1057 ** gctUINT32 ProcessID
1058 ** ProcessID of current process.
1061 ** Handle of video memory.
1068 gckKERNEL_ReleaseVideoMemory(
1069 IN gckKERNEL Kernel,
1070 IN gctUINT32 ProcessID,
1075 gckVIDMEM_NODE nodeObject;
1076 gceDATABASE_TYPE type;
1078 gcmkHEADER_ARG("Kernel=0x%08X ProcessID=%d Handle=%d",
1079 Kernel, ProcessID, Handle);
1082 gckVIDMEM_HANDLE_Lookup(Kernel, ProcessID, Handle, &nodeObject));
1084 type = gcvDB_VIDEO_MEMORY
1085 | (nodeObject->type << gcdDB_VIDEO_MEMORY_TYPE_SHIFT)
1086 | (nodeObject->pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT);
1089 gckKERNEL_RemoveProcessDB(Kernel,
1092 gcmINT2PTR(Handle)));
1094 gckVIDMEM_HANDLE_Dereference(Kernel, ProcessID, Handle);
1096 gckVIDMEM_NODE_Dereference(Kernel, nodeObject);
1099 return gcvSTATUS_OK;
1106 /*******************************************************************************
1108 ** gckKERNEL_LockVideoMemory
1110 ** Lock a video memory node. It will generate a cpu virtual address used
1111 ** by software and a GPU address used by GPU.
1116 ** Pointer to an gckKERNEL object.
1119 ** GPU to which video memory is locked.
1121 ** gcsHAL_INTERFACE * Interface
1122 ** Pointer to a gcsHAL_INTERFACE structure that defines the command to
1127 ** gcsHAL_INTERFACE * Interface
1128 ** Pointer to a gcsHAL_INTERFACE structure that receives any data to be
1132 gckKERNEL_LockVideoMemory(
1133 IN gckKERNEL Kernel,
1135 IN gctUINT32 ProcessID,
1136 IN gctBOOL FromUser,
1137 IN OUT gcsHAL_INTERFACE * Interface
1141 gckVIDMEM_NODE nodeObject = gcvNULL;
1142 gcuVIDMEM_NODE_PTR node = gcvNULL;
1143 gctBOOL locked = gcvFALSE;
1144 gctBOOL asynchronous = gcvFALSE;
1146 gctPOINTER pointer = gcvNULL;
1149 gcmkHEADER_ARG("Kernel=0x%08X ProcessID=%d",
1153 gckVIDMEM_HANDLE_LookupAndReference(Kernel,
1154 Interface->u.LockVideoMemory.node,
1157 node = nodeObject->node;
1159 Interface->u.LockVideoMemory.gid = 0;
1161 /* Lock video memory. */
1163 gckVIDMEM_Lock(Kernel,
1165 Interface->u.LockVideoMemory.cacheable,
1166 &Interface->u.LockVideoMemory.address,
1167 &Interface->u.LockVideoMemory.gid,
1168 &Interface->u.LockVideoMemory.physicalAddress));
1172 if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
1174 /* Map video memory address into user space. */
1176 if (node->VidMem.logical == gcvNULL)
1179 gckKERNEL_MapVideoMemory(Kernel,
1181 Interface->u.LockVideoMemory.address,
1184 &node->VidMem.logical));
1186 gcmkASSERT(node->VidMem.logical != gcvNULL);
1188 Interface->u.LockVideoMemory.memory = gcmPTR_TO_UINT64(node->VidMem.logical);
1191 gckKERNEL_MapVideoMemoryEx(Kernel,
1194 Interface->u.LockVideoMemory.address,
1197 Interface->u.LockVideoMemory.memory = gcmPTR_TO_UINT64(pointer);
1202 Interface->u.LockVideoMemory.memory = gcmPTR_TO_UINT64(node->Virtual.logical);
1205 status = gcvSTATUS_OK;
1208 #if gcdPROCESS_ADDRESS_SPACE
1209 gcmkONERROR(gckVIDMEM_Node_Lock(
1212 &Interface->u.LockVideoMemory.address
1218 /* Return logical address as physical address. */
1219 Interface->u.LockVideoMemory.address =
1220 (gctUINT32)(Interface->u.LockVideoMemory.memory);
1223 gckKERNEL_AddProcessDB(Kernel,
1224 ProcessID, gcvDB_VIDEO_MEMORY_LOCKED,
1225 gcmINT2PTR(Interface->u.LockVideoMemory.node),
1229 gckVIDMEM_HANDLE_Reference(
1230 Kernel, ProcessID, (gctUINT32)Interface->u.LockVideoMemory.node);
1233 return gcvSTATUS_OK;
1238 /* Roll back the lock. */
1239 gcmkVERIFY_OK(gckVIDMEM_Unlock(Kernel,
1241 gcvSURF_TYPE_UNKNOWN,
1244 if (gcvTRUE == asynchronous)
1247 gcmkVERIFY_OK(gckVIDMEM_Unlock(Kernel,
1249 gcvSURF_TYPE_UNKNOWN,
1254 if (nodeObject != gcvNULL)
1256 gckVIDMEM_NODE_Dereference(Kernel, nodeObject);
1263 /*******************************************************************************
1265 ** gckKERNEL_UnlockVideoMemory
1267 ** Unlock a video memory node.
1272 ** Pointer to an gckKERNEL object.
1274 ** gctUINT32 ProcessID
1275 ** ProcessID of current process.
1277 ** gcsHAL_INTERFACE * Interface
1278 ** Pointer to a gcsHAL_INTERFACE structure that defines the command to
1283 ** gcsHAL_INTERFACE * Interface
1284 ** Pointer to a gcsHAL_INTERFACE structure that receives any data to be
1288 gckKERNEL_UnlockVideoMemory(
1289 IN gckKERNEL Kernel,
1290 IN gctUINT32 ProcessID,
1291 IN OUT gcsHAL_INTERFACE * Interface
1295 gckVIDMEM_NODE nodeObject;
1296 gcuVIDMEM_NODE_PTR node;
1298 gcmkHEADER_ARG("Kernel=0x%08X ProcessID=%d",
1301 gcmkONERROR(gckVIDMEM_HANDLE_Lookup(
1304 (gctUINT32)Interface->u.UnlockVideoMemory.node,
1307 node = nodeObject->node;
1309 /* Unlock video memory. */
1311 /* Save node information before it disappears. */
1312 if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
1319 logical = node->Virtual.logical;
1320 bytes = node->Virtual.bytes;
1324 /* Unlock video memory. */
1325 gcmkONERROR(gckVIDMEM_Unlock(
1328 Interface->u.UnlockVideoMemory.type,
1329 &Interface->u.UnlockVideoMemory.asynchroneous));
1332 /* Flush the translation cache for virtual surfaces. */
1333 if (logical != gcvNULL)
1335 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(Kernel,
1343 return gcvSTATUS_OK;
1351 gckKERNEL_QueryDatabase(
1352 IN gckKERNEL Kernel,
1353 IN gctUINT32 ProcessID,
1354 IN OUT gcsHAL_INTERFACE * Interface
1359 gcuDATABASE_INFO tmp;
1361 gceDATABASE_TYPE type[3] = {
1362 gcvDB_VIDEO_MEMORY | (gcvPOOL_SYSTEM << gcdDB_VIDEO_MEMORY_POOL_SHIFT),
1363 gcvDB_VIDEO_MEMORY | (gcvPOOL_CONTIGUOUS << gcdDB_VIDEO_MEMORY_POOL_SHIFT),
1364 gcvDB_VIDEO_MEMORY | (gcvPOOL_VIRTUAL << gcdDB_VIDEO_MEMORY_POOL_SHIFT),
1369 /* Query video memory. */
1371 gckKERNEL_QueryProcessDB(Kernel,
1372 Interface->u.Database.processID,
1373 !Interface->u.Database.validProcessID,
1375 &Interface->u.Database.vidMem));
1377 /* Query non-paged memory. */
1379 gckKERNEL_QueryProcessDB(Kernel,
1380 Interface->u.Database.processID,
1381 !Interface->u.Database.validProcessID,
1383 &Interface->u.Database.nonPaged));
1385 /* Query contiguous memory. */
1387 gckKERNEL_QueryProcessDB(Kernel,
1388 Interface->u.Database.processID,
1389 !Interface->u.Database.validProcessID,
1391 &Interface->u.Database.contiguous));
1393 /* Query GPU idle time. */
1395 gckKERNEL_QueryProcessDB(Kernel,
1396 Interface->u.Database.processID,
1397 !Interface->u.Database.validProcessID,
1399 &Interface->u.Database.gpuIdle));
1400 for (i = 0; i < 3; i++)
1402 /* Query each video memory pool. */
1404 gckKERNEL_QueryProcessDB(Kernel,
1405 Interface->u.Database.processID,
1406 !Interface->u.Database.validProcessID,
1408 &Interface->u.Database.vidMemPool[i]));
1411 /* Query virtual command buffer pool. */
1413 gckKERNEL_QueryProcessDB(Kernel,
1414 Interface->u.Database.processID,
1415 !Interface->u.Database.validProcessID,
1416 gcvDB_COMMAND_BUFFER,
1419 Interface->u.Database.vidMemPool[2].counters.bytes += tmp.counters.bytes;
1420 Interface->u.Database.vidMemPool[2].counters.maxBytes += tmp.counters.maxBytes;
1421 Interface->u.Database.vidMemPool[2].counters.totalBytes += tmp.counters.totalBytes;
1423 Interface->u.Database.vidMem.counters.bytes += tmp.counters.bytes;
1424 Interface->u.Database.vidMem.counters.maxBytes += tmp.counters.maxBytes;
1425 Interface->u.Database.vidMem.counters.totalBytes += tmp.counters.totalBytes;
1427 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
1428 gckKERNEL_DumpVidMemUsage(Kernel, Interface->u.Database.processID);
1432 return gcvSTATUS_OK;
1440 gckKERNEL_ConfigPowerManagement(
1441 IN gckKERNEL Kernel,
1442 IN OUT gcsHAL_INTERFACE * Interface
1446 gctBOOL enable = Interface->u.ConfigPowerManagement.enable;
1450 gcmkONERROR(gckHARDWARE_SetPowerManagement(Kernel->hardware, enable));
1452 if (enable == gcvTRUE)
1455 gckHARDWARE_SetPowerManagementState(Kernel->hardware, gcvPOWER_ON));
1459 return gcvSTATUS_OK;
1466 /*******************************************************************************
1468 ** gckKERNEL_Dispatch
1470 ** Dispatch a command received from the user HAL layer.
1475 ** Pointer to an gckKERNEL object.
1478 ** whether the call is from the user space.
1480 ** gcsHAL_INTERFACE * Interface
1481 ** Pointer to a gcsHAL_INTERFACE structure that defines the command to
1486 ** gcsHAL_INTERFACE * Interface
1487 ** Pointer to a gcsHAL_INTERFACE structure that receives any data to be
1492 IN gckKERNEL Kernel,
1493 IN gctBOOL FromUser,
1494 IN OUT gcsHAL_INTERFACE * Interface
1497 gceSTATUS status = gcvSTATUS_OK;
1498 gctPHYS_ADDR physical = gcvNULL;
1500 gctPOINTER logical = gcvNULL;
1501 gctPOINTER info = gcvNULL;
1502 #if (gcdENABLE_3D || gcdENABLE_2D)
1503 gckCONTEXT context = gcvNULL;
1505 gckKERNEL kernel = Kernel;
1507 gctUINT32 processID;
1509 gcskSECURE_CACHE_PTR cache;
1512 gctUINT32 paddr = gcvINVALID_ADDRESS;
1513 #if !USE_NEW_LINUX_SIGNAL
1516 gckVIRTUAL_COMMAND_BUFFER_PTR buffer;
1518 gckVIDMEM_NODE nodeObject;
1519 gctBOOL powerMutexAcquired = gcvFALSE;
1521 gcmkHEADER_ARG("Kernel=0x%x FromUser=%d Interface=0x%x",
1522 Kernel, FromUser, Interface);
1524 /* Verify the arguments. */
1525 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1526 gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
1528 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
1529 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
1530 "Dispatching command %d (%s)",
1531 Interface->command, _DispatchText[Interface->command]);
1533 #if QNX_SINGLE_THREADED_DEBUGGING
1534 gckOS_AcquireMutex(Kernel->os, Kernel->debugMutex, gcvINFINITE);
1537 /* Get the current process ID. */
1538 gcmkONERROR(gckOS_GetProcessID(&processID));
1541 gcmkONERROR(gckKERNEL_GetProcessDBCache(Kernel, processID, &cache));
1544 /* Dispatch on command. */
1545 switch (Interface->command)
1547 case gcvHAL_GET_BASE_ADDRESS:
1548 /* Get base address. */
1550 gckOS_GetBaseAddress(Kernel->os,
1551 &Interface->u.GetBaseAddress.baseAddress));
1554 case gcvHAL_QUERY_VIDEO_MEMORY:
1555 /* Query video memory size. */
1556 gcmkONERROR(gckKERNEL_QueryVideoMemory(Kernel, Interface));
1559 case gcvHAL_QUERY_CHIP_IDENTITY:
1560 /* Query chip identity. */
1562 gckHARDWARE_QueryChipIdentity(
1564 &Interface->u.QueryChipIdentity));
1567 case gcvHAL_MAP_MEMORY:
1568 physical = gcmINT2PTR(Interface->u.MapMemory.physical);
1572 gckKERNEL_MapMemory(Kernel,
1574 (gctSIZE_T) Interface->u.MapMemory.bytes,
1577 Interface->u.MapMemory.logical = gcmPTR_TO_UINT64(logical);
1580 gckKERNEL_AddProcessDB(Kernel,
1581 processID, gcvDB_MAP_MEMORY,
1584 (gctSIZE_T) Interface->u.MapMemory.bytes));
1587 case gcvHAL_UNMAP_MEMORY:
1588 physical = gcmINT2PTR(Interface->u.UnmapMemory.physical);
1591 gckKERNEL_RemoveProcessDB(Kernel,
1592 processID, gcvDB_MAP_MEMORY,
1593 gcmUINT64_TO_PTR(Interface->u.UnmapMemory.logical)));
1597 gckKERNEL_UnmapMemory(Kernel,
1599 (gctSIZE_T) Interface->u.UnmapMemory.bytes,
1600 gcmUINT64_TO_PTR(Interface->u.UnmapMemory.logical)));
1603 case gcvHAL_ALLOCATE_NON_PAGED_MEMORY:
1604 bytes = (gctSIZE_T) Interface->u.AllocateNonPagedMemory.bytes;
1606 /* Allocate non-paged memory. */
1608 gckOS_AllocateNonPagedMemory(
1615 Interface->u.AllocateNonPagedMemory.bytes = bytes;
1616 Interface->u.AllocateNonPagedMemory.logical = gcmPTR_TO_UINT64(logical);
1617 Interface->u.AllocateNonPagedMemory.physical = gcmPTR_TO_NAME(physical);
1620 gckKERNEL_AddProcessDB(Kernel,
1621 processID, gcvDB_NON_PAGED,
1623 gcmINT2PTR(Interface->u.AllocateNonPagedMemory.physical),
1627 case gcvHAL_ALLOCATE_VIRTUAL_COMMAND_BUFFER:
1628 bytes = (gctSIZE_T) Interface->u.AllocateVirtualCommandBuffer.bytes;
1631 gckKERNEL_AllocateVirtualCommandBuffer(
1638 Interface->u.AllocateVirtualCommandBuffer.bytes = bytes;
1639 Interface->u.AllocateVirtualCommandBuffer.logical = gcmPTR_TO_UINT64(logical);
1640 Interface->u.AllocateVirtualCommandBuffer.physical = gcmPTR_TO_NAME(physical);
1643 gckKERNEL_AddProcessDB(Kernel,
1644 processID, gcvDB_COMMAND_BUFFER,
1646 gcmINT2PTR(Interface->u.AllocateVirtualCommandBuffer.physical),
1650 case gcvHAL_FREE_NON_PAGED_MEMORY:
1651 physical = gcmNAME_TO_PTR(Interface->u.FreeNonPagedMemory.physical);
1654 gckKERNEL_RemoveProcessDB(Kernel,
1655 processID, gcvDB_NON_PAGED,
1656 gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical)));
1658 /* Unmap user logical out of physical memory first. */
1659 gcmkONERROR(gckOS_UnmapUserLogical(Kernel->os,
1661 (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes,
1662 gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical)));
1664 /* Free non-paged memory. */
1666 gckOS_FreeNonPagedMemory(Kernel->os,
1667 (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes,
1669 gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical)));
1672 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
1675 gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical),
1676 (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes));
1679 gcmRELEASE_NAME(Interface->u.FreeNonPagedMemory.physical);
1682 case gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY:
1683 bytes = (gctSIZE_T) Interface->u.AllocateContiguousMemory.bytes;
1685 /* Allocate contiguous memory. */
1686 gcmkONERROR(gckOS_AllocateContiguous(
1693 Interface->u.AllocateContiguousMemory.bytes = bytes;
1694 Interface->u.AllocateContiguousMemory.logical = gcmPTR_TO_UINT64(logical);
1695 Interface->u.AllocateContiguousMemory.physical = gcmPTR_TO_NAME(physical);
1697 gcmkONERROR(gckHARDWARE_ConvertLogical(
1701 &Interface->u.AllocateContiguousMemory.address));
1703 gcmkVERIFY_OK(gckKERNEL_AddProcessDB(
1705 processID, gcvDB_CONTIGUOUS,
1707 gcmINT2PTR(Interface->u.AllocateContiguousMemory.physical),
1711 case gcvHAL_FREE_CONTIGUOUS_MEMORY:
1712 physical = gcmNAME_TO_PTR(Interface->u.FreeContiguousMemory.physical);
1715 gckKERNEL_RemoveProcessDB(Kernel,
1716 processID, gcvDB_CONTIGUOUS,
1717 gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical)));
1719 /* Unmap user logical out of physical memory first. */
1720 gcmkONERROR(gckOS_UnmapUserLogical(Kernel->os,
1722 (gctSIZE_T) Interface->u.FreeContiguousMemory.bytes,
1723 gcmUINT64_TO_PTR(Interface->u.FreeContiguousMemory.logical)));
1725 /* Free contiguous memory. */
1727 gckOS_FreeContiguous(Kernel->os,
1729 gcmUINT64_TO_PTR(Interface->u.FreeContiguousMemory.logical),
1730 (gctSIZE_T) Interface->u.FreeContiguousMemory.bytes));
1733 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
1736 gcmUINT64_TO_PTR(Interface->u.FreeContiguousMemory.logical),
1737 (gctSIZE_T) Interface->u.FreeContiguousMemory.bytes));
1740 gcmRELEASE_NAME(Interface->u.FreeContiguousMemory.physical);
1743 case gcvHAL_ALLOCATE_VIDEO_MEMORY:
1745 gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
1749 case gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY:
1750 /* Allocate memory. */
1752 gckKERNEL_AllocateLinearMemory(Kernel, processID,
1753 &Interface->u.AllocateLinearVideoMemory.pool,
1754 Interface->u.AllocateLinearVideoMemory.bytes,
1755 Interface->u.AllocateLinearVideoMemory.alignment,
1756 Interface->u.AllocateLinearVideoMemory.type,
1757 Interface->u.AllocateLinearVideoMemory.flag,
1758 &Interface->u.AllocateLinearVideoMemory.node));
1761 case gcvHAL_RELEASE_VIDEO_MEMORY:
1762 /* Release video memory. */
1763 gcmkONERROR(gckKERNEL_ReleaseVideoMemory(
1765 (gctUINT32)Interface->u.ReleaseVideoMemory.node
1769 case gcvHAL_LOCK_VIDEO_MEMORY:
1770 /* Lock video memory. */
1771 gcmkONERROR(gckKERNEL_LockVideoMemory(Kernel, Kernel->core, processID, FromUser, Interface));
1774 case gcvHAL_UNLOCK_VIDEO_MEMORY:
1775 /* Unlock video memory. */
1776 gcmkONERROR(gckKERNEL_UnlockVideoMemory(Kernel, processID, Interface));
1779 case gcvHAL_EVENT_COMMIT:
1780 /* Commit an event queue. */
1782 if (Interface->u.Event.gpuMode == gcvMULTI_GPU_MODE_INDEPENDENT)
1785 gckEVENT_Commit(Kernel->eventObj,
1786 gcmUINT64_TO_PTR(Interface->u.Event.queue),
1787 Interface->u.Event.chipEnable));
1792 gckEVENT_Commit(Kernel->eventObj,
1793 gcmUINT64_TO_PTR(Interface->u.Event.queue),
1794 gcvCORE_3D_ALL_MASK));
1798 gckEVENT_Commit(Kernel->eventObj,
1799 gcmUINT64_TO_PTR(Interface->u.Event.queue)));
1804 /* Commit a command and context buffer. */
1806 if (Interface->u.Commit.gpuMode == gcvMULTI_GPU_MODE_INDEPENDENT)
1809 gckCOMMAND_Commit(Kernel->command,
1810 Interface->u.Commit.context ?
1811 gcmNAME_TO_PTR(Interface->u.Commit.context) : gcvNULL,
1812 gcmUINT64_TO_PTR(Interface->u.Commit.commandBuffer),
1813 gcmUINT64_TO_PTR(Interface->u.Commit.delta),
1814 gcmUINT64_TO_PTR(Interface->u.Commit.queue),
1816 Interface->u.Commit.chipEnable));
1821 gckCOMMAND_Commit(Kernel->command,
1822 Interface->u.Commit.context ?
1823 gcmNAME_TO_PTR(Interface->u.Commit.context) : gcvNULL,
1824 gcmUINT64_TO_PTR(Interface->u.Commit.commandBuffer),
1825 gcmUINT64_TO_PTR(Interface->u.Commit.delta),
1826 gcmUINT64_TO_PTR(Interface->u.Commit.queue),
1828 gcvCORE_3D_ALL_MASK));
1832 gckCOMMAND_Commit(Kernel->command,
1833 Interface->u.Commit.context ?
1834 gcmNAME_TO_PTR(Interface->u.Commit.context) : gcvNULL,
1835 gcmUINT64_TO_PTR(Interface->u.Commit.commandBuffer),
1836 gcmUINT64_TO_PTR(Interface->u.Commit.delta),
1837 gcmUINT64_TO_PTR(Interface->u.Commit.queue),
1844 /* Stall the command queue. */
1846 gcmkONERROR(gckCOMMAND_Stall(Kernel->command, gcvFALSE, gcvCORE_3D_ALL_MASK));
1848 gcmkONERROR(gckCOMMAND_Stall(Kernel->command, gcvFALSE));
1852 case gcvHAL_MAP_USER_MEMORY:
1853 /* Map user memory to DMA. */
1855 gckOS_MapUserMemory(Kernel->os,
1857 gcmUINT64_TO_PTR(Interface->u.MapUserMemory.memory),
1858 Interface->u.MapUserMemory.physical,
1859 (gctSIZE_T) Interface->u.MapUserMemory.size,
1861 &Interface->u.MapUserMemory.address));
1863 Interface->u.MapUserMemory.info = gcmPTR_TO_NAME(info);
1866 gckKERNEL_AddProcessDB(Kernel,
1867 processID, gcvDB_MAP_USER_MEMORY,
1868 gcmINT2PTR(Interface->u.MapUserMemory.info),
1869 gcmUINT64_TO_PTR(Interface->u.MapUserMemory.memory),
1870 (gctSIZE_T) Interface->u.MapUserMemory.size));
1873 case gcvHAL_UNMAP_USER_MEMORY:
1874 address = Interface->u.UnmapUserMemory.address;
1875 info = gcmNAME_TO_PTR(Interface->u.UnmapUserMemory.info);
1878 gckKERNEL_RemoveProcessDB(Kernel,
1879 processID, gcvDB_MAP_USER_MEMORY,
1880 gcmINT2PTR(Interface->u.UnmapUserMemory.info)));
1881 /* Unmap user memory. */
1883 gckOS_UnmapUserMemory(Kernel->os,
1885 gcmUINT64_TO_PTR(Interface->u.UnmapUserMemory.memory),
1886 (gctSIZE_T) Interface->u.UnmapUserMemory.size,
1891 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
1894 gcmUINT64_TO_PTR(Interface->u.UnmapUserMemory.memory),
1895 (gctSIZE_T) Interface->u.UnmapUserMemory.size));
1898 gcmRELEASE_NAME(Interface->u.UnmapUserMemory.info);
1901 #if !USE_NEW_LINUX_SIGNAL
1902 case gcvHAL_USER_SIGNAL:
1903 /* Dispatch depends on the user signal subcommands. */
1904 switch(Interface->u.UserSignal.command)
1906 case gcvUSER_SIGNAL_CREATE:
1907 /* Create a signal used in the user space. */
1909 gckOS_CreateUserSignal(Kernel->os,
1910 Interface->u.UserSignal.manualReset,
1911 &Interface->u.UserSignal.id));
1914 gckKERNEL_AddProcessDB(Kernel,
1915 processID, gcvDB_SIGNAL,
1916 gcmINT2PTR(Interface->u.UserSignal.id),
1921 case gcvUSER_SIGNAL_DESTROY:
1922 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
1924 processID, gcvDB_SIGNAL,
1925 gcmINT2PTR(Interface->u.UserSignal.id)));
1927 /* Destroy the signal. */
1929 gckOS_DestroyUserSignal(Kernel->os,
1930 Interface->u.UserSignal.id));
1933 case gcvUSER_SIGNAL_SIGNAL:
1934 /* Signal the signal. */
1936 gckOS_SignalUserSignal(Kernel->os,
1937 Interface->u.UserSignal.id,
1938 Interface->u.UserSignal.state));
1941 case gcvUSER_SIGNAL_WAIT:
1942 /* Wait on the signal. */
1943 status = gckOS_WaitUserSignal(Kernel->os,
1944 Interface->u.UserSignal.id,
1945 Interface->u.UserSignal.wait);
1949 case gcvUSER_SIGNAL_MAP:
1951 gckOS_MapSignal(Kernel->os,
1952 (gctSIGNAL)(gctUINTPTR_T)Interface->u.UserSignal.id,
1953 (gctHANDLE)(gctUINTPTR_T)processID,
1957 gckKERNEL_AddProcessDB(Kernel,
1958 processID, gcvDB_SIGNAL,
1959 gcmINT2PTR(Interface->u.UserSignal.id),
1964 case gcvUSER_SIGNAL_UNMAP:
1965 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
1967 processID, gcvDB_SIGNAL,
1968 gcmINT2PTR(Interface->u.UserSignal.id)));
1970 /* Destroy the signal. */
1972 gckOS_DestroyUserSignal(Kernel->os,
1973 Interface->u.UserSignal.id));
1977 /* Invalid user signal command. */
1978 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
1983 case gcvHAL_SET_POWER_MANAGEMENT_STATE:
1984 /* Set the power management state. */
1986 gckHARDWARE_SetPowerManagementState(
1988 Interface->u.SetPowerManagement.state));
1991 case gcvHAL_QUERY_POWER_MANAGEMENT_STATE:
1992 /* Chip is not idle. */
1993 Interface->u.QueryPowerManagement.isIdle = gcvFALSE;
1995 /* Query the power management state. */
1996 gcmkONERROR(gckHARDWARE_QueryPowerManagementState(
1998 &Interface->u.QueryPowerManagement.state));
2000 /* Query the idle state. */
2002 gckHARDWARE_QueryIdle(Kernel->hardware,
2003 &Interface->u.QueryPowerManagement.isIdle));
2006 case gcvHAL_READ_REGISTER:
2007 #if gcdREGISTER_ACCESS_FROM_USER
2009 gceCHIPPOWERSTATE power;
2011 gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->hardware->powerMutex, gcvINFINITE));
2012 powerMutexAcquired = gcvTRUE;
2013 gcmkONERROR(gckHARDWARE_QueryPowerManagementState(Kernel->hardware,
2015 if (power == gcvPOWER_ON)
2017 /* Read a register. */
2018 gcmkONERROR(gckOS_ReadRegisterEx(
2021 Interface->u.ReadRegisterData.address,
2022 &Interface->u.ReadRegisterData.data));
2026 /* Chip is in power-state. */
2027 Interface->u.ReadRegisterData.data = 0;
2028 status = gcvSTATUS_CHIP_NOT_READY;
2030 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex));
2031 powerMutexAcquired = gcvFALSE;
2034 /* No access from user land to read registers. */
2035 Interface->u.ReadRegisterData.data = 0;
2036 status = gcvSTATUS_NOT_SUPPORTED;
2041 case gcvHAL_READ_REGISTER_EX:
2042 #if gcdREGISTER_ACCESS_FROM_USER
2044 gceCHIPPOWERSTATE power;
2045 gctUINT32 coreId = 0;
2046 gctUINT32 coreSelect = Interface->u.ReadRegisterDataEx.coreSelect;
2048 gckOS_AcquireMutex(Kernel->os, Kernel->hardware->powerMutex, gcvINFINITE);
2049 powerMutexAcquired = gcvTRUE;
2050 gcmkONERROR(gckHARDWARE_QueryPowerManagementState(Kernel->hardware,
2052 if (power == gcvPOWER_ON)
2054 for (; coreSelect != 0; coreSelect >>= 1, coreId++)
2056 if (coreSelect & 1UL)
2058 /* Read a register. */
2060 gckOS_ReadRegisterByCoreId(
2064 Interface->u.ReadRegisterDataEx.address,
2065 &Interface->u.ReadRegisterDataEx.data[coreId]));
2071 for (coreId = 0; coreId < gcdMULTI_GPU; coreId++)
2073 /* Chip is in power-state. */
2074 Interface->u.ReadRegisterDataEx.data[coreId] = 0;
2076 status = gcvSTATUS_CHIP_NOT_READY;
2078 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex));
2079 powerMutexAcquired = gcvFALSE;
2084 /* No access from user land to read registers. */
2085 for (coreId = 0; coreId < gcdMULTI_GPU; coreId++)
2087 Interface->u.ReadRegisterDataEx.data[coreId] = 0;
2090 status = gcvSTATUS_NOT_SUPPORTED;
2094 case gcvHAL_WRITE_REGISTER_EX:
2095 #if gcdREGISTER_ACCESS_FROM_USER
2097 gceCHIPPOWERSTATE power;
2098 gctUINT32 coreId = 0;
2099 gctUINT32 coreSelect = Interface->u.WriteRegisterDataEx.coreSelect;
2101 gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->hardware->powerMutex, gcvINFINITE));
2102 powerMutexAcquired = gcvTRUE;
2103 gcmkONERROR(gckHARDWARE_QueryPowerManagementState(Kernel->hardware,
2105 if (power == gcvPOWER_ON)
2107 for (; coreSelect != 0; coreSelect >>= 1, coreId++)
2109 if (coreSelect & 1UL)
2111 /* Write a register. */
2113 gckOS_WriteRegisterByCoreId(
2117 Interface->u.WriteRegisterDataEx.address,
2118 Interface->u.WriteRegisterDataEx.data[coreId]));
2124 /* Chip is in power-state. */
2125 for (coreId = 0; coreId < gcdMULTI_GPU; coreId++)
2127 Interface->u.WriteRegisterDataEx.data[coreId] = 0;
2129 status = gcvSTATUS_CHIP_NOT_READY;
2131 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex));
2132 powerMutexAcquired = gcvFALSE;
2135 status = gcvSTATUS_NOT_SUPPORTED;
2140 case gcvHAL_WRITE_REGISTER:
2141 #if gcdREGISTER_ACCESS_FROM_USER
2143 gceCHIPPOWERSTATE power;
2145 gckOS_AcquireMutex(Kernel->os, Kernel->hardware->powerMutex, gcvINFINITE);
2146 gcmkONERROR(gckHARDWARE_QueryPowerManagementState(Kernel->hardware,
2148 if (power == gcvPOWER_ON)
2150 /* Write a register. */
2152 gckOS_WriteRegisterEx(Kernel->os,
2154 Interface->u.WriteRegisterData.address,
2155 Interface->u.WriteRegisterData.data));
2159 /* Chip is in power-state. */
2160 Interface->u.WriteRegisterData.data = 0;
2161 status = gcvSTATUS_CHIP_NOT_READY;
2163 gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex));
2166 /* No access from user land to write registers. */
2167 status = gcvSTATUS_NOT_SUPPORTED;
2171 case gcvHAL_READ_ALL_PROFILE_REGISTERS:
2172 #if VIVANTE_PROFILER && VIVANTE_PROFILER_CONTEXT
2173 /* Read profile data according to the context. */
2175 gckHARDWARE_QueryContextProfile(
2177 Kernel->profileCleanRegister,
2178 gcmNAME_TO_PTR(Interface->u.RegisterProfileData.context),
2179 &Interface->u.RegisterProfileData.counters));
2180 #elif VIVANTE_PROFILER
2181 /* Read all 3D profile registers. */
2183 gckHARDWARE_QueryProfileRegisters(
2185 Kernel->profileCleanRegister,
2186 &Interface->u.RegisterProfileData.counters));
2188 status = gcvSTATUS_OK;
2192 case gcvHAL_PROFILE_REGISTERS_2D:
2193 #if VIVANTE_PROFILER
2194 /* Read all 2D profile registers. */
2196 gckHARDWARE_ProfileEngine2D(
2198 gcmUINT64_TO_PTR(Interface->u.RegisterProfileData2D.hwProfile2D)));
2200 status = gcvSTATUS_OK;
2204 case gcvHAL_GET_PROFILE_SETTING:
2205 #if VIVANTE_PROFILER
2206 /* Get profile setting */
2207 Interface->u.GetProfileSetting.enable = Kernel->profileEnable;
2210 status = gcvSTATUS_OK;
2213 case gcvHAL_SET_PROFILE_SETTING:
2214 #if VIVANTE_PROFILER
2215 /* Set profile setting */
2216 if(Kernel->hardware->gpuProfiler)
2218 Kernel->profileEnable = Interface->u.SetProfileSetting.enable;
2219 #if VIVANTE_PROFILER_NEW
2220 if (Kernel->profileEnable)
2221 gckHARDWARE_InitProfiler(Kernel->hardware);
2226 status = gcvSTATUS_NOT_SUPPORTED;
2231 status = gcvSTATUS_OK;
2234 #if VIVANTE_PROFILER_PERDRAW
2235 case gcvHAL_READ_PROFILER_REGISTER_SETTING:
2236 #if VIVANTE_PROFILER
2237 Kernel->profileCleanRegister = Interface->u.SetProfilerRegisterClear.bclear;
2239 status = gcvSTATUS_OK;
2243 case gcvHAL_QUERY_KERNEL_SETTINGS:
2244 /* Get kernel settings. */
2246 gckKERNEL_QuerySettings(Kernel,
2247 &Interface->u.QueryKernelSettings.settings));
2251 /* Reset the hardware. */
2253 gckHARDWARE_Reset(Kernel->hardware));
2257 /* Set debug level and zones. */
2258 if (Interface->u.Debug.set)
2260 gckOS_SetDebugLevel(Interface->u.Debug.level);
2261 gckOS_SetDebugZones(Interface->u.Debug.zones,
2262 Interface->u.Debug.enable);
2265 if (Interface->u.Debug.message[0] != '\0')
2267 /* Print a message to the debugger. */
2268 if (Interface->u.Debug.type == gcvMESSAGE_TEXT)
2270 gckOS_CopyPrint(Interface->u.Debug.message);
2274 gckOS_DumpBuffer(Kernel->os,
2275 Interface->u.Debug.message,
2276 Interface->u.Debug.messageSize,
2277 gceDUMP_BUFFER_FROM_USER,
2281 status = gcvSTATUS_OK;
2284 case gcvHAL_DUMP_GPU_STATE:
2286 gceCHIPPOWERSTATE power;
2288 _DumpDriverConfigure(Kernel);
2290 gcmkONERROR(gckHARDWARE_QueryPowerManagementState(
2295 if (power == gcvPOWER_ON)
2297 Interface->u.ReadRegisterData.data = 1;
2303 Interface->u.ReadRegisterData.data = 0;
2304 status = gcvSTATUS_CHIP_NOT_READY;
2306 gcmkPRINT("[galcore]: Can't dump state if GPU isn't POWER ON.");
2311 case gcvHAL_DUMP_EVENT:
2316 logical = gcmUINT64_TO_PTR(Interface->u.Cache.logical);
2318 if (Interface->u.Cache.node)
2320 gcmkONERROR(gckVIDMEM_HANDLE_Lookup(
2323 Interface->u.Cache.node,
2326 if (nodeObject->node->VidMem.memory->object.type == gcvOBJ_VIDMEM
2327 || nodeObject->node->Virtual.contiguous
2330 /* If memory is contiguous, get physical address. */
2331 gcmkONERROR(gckOS_GetPhysicalAddress(
2332 Kernel->os, logical, (gctUINT32*)&paddr));
2336 bytes = (gctSIZE_T) Interface->u.Cache.bytes;
2337 switch(Interface->u.Cache.operation)
2339 case gcvCACHE_FLUSH:
2340 /* Clean and invalidate the cache. */
2341 status = gckOS_CacheFlush(Kernel->os,
2348 case gcvCACHE_CLEAN:
2349 /* Clean the cache. */
2350 status = gckOS_CacheClean(Kernel->os,
2357 case gcvCACHE_INVALIDATE:
2358 /* Invalidate the cache. */
2359 status = gckOS_CacheInvalidate(Kernel->os,
2367 case gcvCACHE_MEMORY_BARRIER:
2368 status = gckOS_MemoryBarrier(Kernel->os,
2372 status = gcvSTATUS_INVALID_ARGUMENT;
2377 case gcvHAL_TIMESTAMP:
2378 /* Check for invalid timer. */
2379 if ((Interface->u.TimeStamp.timer >= gcmCOUNTOF(Kernel->timers))
2380 || (Interface->u.TimeStamp.request != 2))
2382 Interface->u.TimeStamp.timeDelta = 0;
2383 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
2386 /* Return timer results and reset timer. */
2388 gcsTIMER_PTR timer = &(Kernel->timers[Interface->u.TimeStamp.timer]);
2389 gctUINT64 timeDelta = 0;
2391 if (timer->stopTime < timer->startTime )
2393 Interface->u.TimeStamp.timeDelta = 0;
2394 gcmkONERROR(gcvSTATUS_TIMER_OVERFLOW);
2397 timeDelta = timer->stopTime - timer->startTime;
2399 /* Check truncation overflow. */
2400 Interface->u.TimeStamp.timeDelta = (gctINT32) timeDelta;
2401 /*bit0~bit30 is available*/
2404 Interface->u.TimeStamp.timeDelta = 0;
2405 gcmkONERROR(gcvSTATUS_TIMER_OVERFLOW);
2408 status = gcvSTATUS_OK;
2412 case gcvHAL_DATABASE:
2413 gcmkONERROR(gckKERNEL_QueryDatabase(Kernel, processID, Interface));
2416 case gcvHAL_VERSION:
2417 Interface->u.Version.major = gcvVERSION_MAJOR;
2418 Interface->u.Version.minor = gcvVERSION_MINOR;
2419 Interface->u.Version.patch = gcvVERSION_PATCH;
2420 Interface->u.Version.build = gcvVERSION_BUILD;
2421 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
2422 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
2423 "KERNEL version %d.%d.%d build %u %s %s",
2424 gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH,
2425 gcvVERSION_BUILD, gcvVERSION_DATE, gcvVERSION_TIME);
2429 case gcvHAL_CHIP_INFO:
2430 /* Only if not support multi-core */
2431 Interface->u.ChipInfo.count = 1;
2432 Interface->u.ChipInfo.types[0] = Kernel->hardware->type;
2435 #if (gcdENABLE_3D || gcdENABLE_2D)
2437 /* Attach user process. */
2439 gckCOMMAND_Attach(Kernel->command,
2444 Interface->u.Attach.stateCount = bytes;
2445 Interface->u.Attach.context = gcmPTR_TO_NAME(context);
2447 if (Interface->u.Attach.map == gcvTRUE)
2450 gckCONTEXT_MapBuffer(context,
2451 Interface->u.Attach.physicals,
2452 Interface->u.Attach.logicals,
2453 &Interface->u.Attach.bytes));
2457 gckKERNEL_AddProcessDB(Kernel,
2458 processID, gcvDB_CONTEXT,
2459 gcmINT2PTR(Interface->u.Attach.context),
2467 gckKERNEL_RemoveProcessDB(Kernel,
2468 processID, gcvDB_CONTEXT,
2469 gcmINT2PTR(Interface->u.Detach.context)));
2471 /* Detach user process. */
2473 gckCOMMAND_Detach(Kernel->command,
2474 gcmNAME_TO_PTR(Interface->u.Detach.context)));
2476 gcmRELEASE_NAME(Interface->u.Detach.context);
2479 case gcvHAL_COMPOSE:
2480 Interface->u.Compose.physical = gcmPTR_TO_UINT64(gcmNAME_TO_PTR(Interface->u.Compose.physical));
2481 /* Start composition. */
2483 gckEVENT_Compose(Kernel->eventObj,
2484 &Interface->u.Compose));
2487 case gcvHAL_SET_TIMEOUT:
2488 /* set timeOut value from user */
2489 gckKERNEL_SetTimeOut(Kernel, Interface->u.SetTimeOut.timeOut);
2492 case gcvHAL_GET_FRAME_INFO:
2493 gcmkONERROR(gckHARDWARE_GetFrameInfo(
2495 gcmUINT64_TO_PTR(Interface->u.GetFrameInfo.frameInfo)));
2498 case gcvHAL_SET_FSCALE_VALUE:
2499 #if gcdENABLE_FSCALE_VAL_ADJUST
2500 status = gckHARDWARE_SetFscaleValue(Kernel->hardware,
2501 Interface->u.SetFscaleValue.value);
2503 status = gcvSTATUS_NOT_SUPPORTED;
2506 case gcvHAL_GET_FSCALE_VALUE:
2507 #if gcdENABLE_FSCALE_VAL_ADJUST
2508 status = gckHARDWARE_GetFscaleValue(Kernel->hardware,
2509 &Interface->u.GetFscaleValue.value,
2510 &Interface->u.GetFscaleValue.minValue,
2511 &Interface->u.GetFscaleValue.maxValue);
2513 status = gcvSTATUS_NOT_SUPPORTED;
2517 case gcvHAL_NAME_VIDEO_MEMORY:
2518 gcmkONERROR(gckVIDMEM_NODE_Name(Kernel,
2519 Interface->u.NameVideoMemory.handle,
2520 &Interface->u.NameVideoMemory.name));
2523 case gcvHAL_IMPORT_VIDEO_MEMORY:
2524 gcmkONERROR(gckVIDMEM_NODE_Import(Kernel,
2525 Interface->u.ImportVideoMemory.name,
2526 &Interface->u.ImportVideoMemory.handle));
2529 gckKERNEL_AddProcessDB(Kernel,
2530 processID, gcvDB_VIDEO_MEMORY,
2531 gcmINT2PTR(Interface->u.ImportVideoMemory.handle),
2536 case gcvHAL_GET_VIDEO_MEMORY_FD:
2537 gcmkONERROR(gckVIDMEM_NODE_GetFd(
2539 Interface->u.GetVideoMemoryFd.handle,
2540 &Interface->u.GetVideoMemoryFd.fd
2543 /* No need to add it to processDB because OS will release all fds when
2548 case gcvHAL_QUERY_RESET_TIME_STAMP:
2549 Interface->u.QueryResetTimeStamp.timeStamp = Kernel->resetTimeStamp;
2552 case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
2553 buffer = (gckVIRTUAL_COMMAND_BUFFER_PTR)gcmNAME_TO_PTR(Interface->u.FreeVirtualCommandBuffer.physical);
2555 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
2558 gcvDB_COMMAND_BUFFER,
2559 gcmUINT64_TO_PTR(Interface->u.FreeVirtualCommandBuffer.logical)));
2561 gcmkONERROR(gckOS_DestroyUserVirtualMapping(
2564 (gctSIZE_T)Interface->u.FreeVirtualCommandBuffer.bytes,
2565 gcmUINT64_TO_PTR(Interface->u.FreeVirtualCommandBuffer.logical)));
2567 gcmkONERROR(gckKERNEL_DestroyVirtualCommandBuffer(
2569 (gctSIZE_T)Interface->u.FreeVirtualCommandBuffer.bytes,
2570 (gctPHYS_ADDR)buffer,
2571 gcmUINT64_TO_PTR(Interface->u.FreeVirtualCommandBuffer.logical)));
2573 gcmRELEASE_NAME(Interface->u.FreeVirtualCommandBuffer.physical);
2576 #if gcdANDROID_NATIVE_FENCE_SYNC
2577 case gcvHAL_SYNC_POINT:
2579 gctSYNC_POINT syncPoint;
2581 switch (Interface->u.SyncPoint.command)
2583 case gcvSYNC_POINT_CREATE:
2584 gcmkONERROR(gckOS_CreateSyncPoint(Kernel->os, &syncPoint));
2586 Interface->u.SyncPoint.syncPoint = gcmPTR_TO_UINT64(syncPoint);
2589 gckKERNEL_AddProcessDB(Kernel,
2590 processID, gcvDB_SYNC_POINT,
2596 case gcvSYNC_POINT_DESTROY:
2597 syncPoint = gcmUINT64_TO_PTR(Interface->u.SyncPoint.syncPoint);
2599 gcmkONERROR(gckOS_DestroySyncPoint(Kernel->os, syncPoint));
2602 gckKERNEL_RemoveProcessDB(Kernel,
2603 processID, gcvDB_SYNC_POINT,
2608 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
2614 case gcvHAL_CREATE_NATIVE_FENCE:
2617 gctSYNC_POINT syncPoint =
2618 gcmUINT64_TO_PTR(Interface->u.CreateNativeFence.syncPoint);
2621 gckOS_CreateNativeFence(Kernel->os,
2626 Interface->u.CreateNativeFence.fenceFD = fenceFD;
2637 switch (Interface->u.ShBuf.command)
2639 case gcvSHBUF_CREATE:
2640 bytes = Interface->u.ShBuf.bytes;
2643 gcmkONERROR(gckKERNEL_CreateShBuffer(Kernel, bytes, &shBuf));
2645 Interface->u.ShBuf.id = gcmPTR_TO_UINT64(shBuf);
2648 gckKERNEL_AddProcessDB(Kernel,
2656 case gcvSHBUF_DESTROY:
2657 shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id);
2659 /* Check db first to avoid illegal destroy in the process. */
2661 gckKERNEL_RemoveProcessDB(Kernel,
2666 gcmkONERROR(gckKERNEL_DestroyShBuffer(Kernel, shBuf));
2670 shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id);
2672 /* Map for current process access. */
2673 gcmkONERROR(gckKERNEL_MapShBuffer(Kernel, shBuf));
2676 gckKERNEL_AddProcessDB(Kernel,
2684 case gcvSHBUF_WRITE:
2685 shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id);
2686 uData = gcmUINT64_TO_PTR(Interface->u.ShBuf.data);
2687 bytes = Interface->u.ShBuf.bytes;
2691 gckKERNEL_WriteShBuffer(Kernel, shBuf, uData, bytes));
2695 shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id);
2696 uData = gcmUINT64_TO_PTR(Interface->u.ShBuf.data);
2697 bytes = Interface->u.ShBuf.bytes;
2701 gckKERNEL_ReadShBuffer(Kernel,
2707 /* Return copied size. */
2708 Interface->u.ShBuf.bytes = bytes;
2712 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
2718 case gcvHAL_CONFIG_POWER_MANAGEMENT:
2719 gcmkONERROR(gckKERNEL_ConfigPowerManagement(Kernel, Interface));
2723 /* Invalid command. */
2724 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
2729 Interface->status = status;
2731 #if QNX_SINGLE_THREADED_DEBUGGING
2732 gckOS_ReleaseMutex(Kernel->os, Kernel->debugMutex);
2735 if (powerMutexAcquired == gcvTRUE)
2737 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex));
2740 /* Return the status. */
2745 /*******************************************************************************
2746 ** gckKERNEL_AttachProcess
2748 ** Attach or detach a process.
2753 ** Pointer to an gckKERNEL object.
2756 ** gcvTRUE if a new process gets attached or gcFALSE when a process
2764 gckKERNEL_AttachProcess(
2765 IN gckKERNEL Kernel,
2770 gctUINT32 processID;
2772 gcmkHEADER_ARG("Kernel=0x%x Attach=%d", Kernel, Attach);
2774 /* Verify the arguments. */
2775 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
2777 /* Get current process ID. */
2778 gcmkONERROR(gckOS_GetProcessID(&processID));
2780 gcmkONERROR(gckKERNEL_AttachProcessEx(Kernel, Attach, processID));
2784 return gcvSTATUS_OK;
2787 /* Return the status. */
2792 /*******************************************************************************
2793 ** gckKERNEL_AttachProcessEx
2795 ** Attach or detach a process with the given PID. Can be paired with gckKERNEL_AttachProcess
2796 ** provided the programmer is aware of the consequences.
2801 ** Pointer to an gckKERNEL object.
2804 ** gcvTRUE if a new process gets attached or gcFALSE when a process
2808 ** PID of the process to attach or detach.
2815 gckKERNEL_AttachProcessEx(
2816 IN gckKERNEL Kernel,
2824 gcmkHEADER_ARG("Kernel=0x%x Attach=%d PID=%d", Kernel, Attach, PID);
2826 /* Verify the arguments. */
2827 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
2831 /* Increment the number of clients attached. */
2833 gckOS_AtomIncrement(Kernel->os, Kernel->atomClients, &old));
2838 if (Kernel->vg == gcvNULL)
2841 gcmkONERROR(gckOS_Broadcast(Kernel->os,
2843 gcvBROADCAST_FIRST_PROCESS));
2847 if (Kernel->dbCreated)
2849 /* Create the process database. */
2850 gcmkONERROR(gckKERNEL_CreateProcessDB(Kernel, PID));
2853 #if gcdPROCESS_ADDRESS_SPACE
2854 /* Map kernel command buffer in the process's own MMU. */
2855 gcmkONERROR(_MapCommandBuffer(Kernel));
2860 if (Kernel->dbCreated)
2862 /* Clean up the process database. */
2863 gcmkONERROR(gckKERNEL_DestroyProcessDB(Kernel, PID));
2865 /* Save the last know process ID. */
2866 Kernel->db->lastProcessID = PID;
2870 if (Kernel->vg == gcvNULL)
2874 status = gckEVENT_Submit(Kernel->eventObj, gcvTRUE, gcvFALSE, gcvCORE_3D_ALL_MASK);
2876 status = gckEVENT_Submit(Kernel->eventObj, gcvTRUE, gcvFALSE);
2879 if (status == gcvSTATUS_INTERRUPTED && Kernel->eventObj->submitTimer)
2881 gcmkONERROR(gckOS_StartTimer(Kernel->os,
2882 Kernel->eventObj->submitTimer,
2887 gcmkONERROR(status);
2891 /* Decrement the number of clients attached. */
2893 gckOS_AtomDecrement(Kernel->os, Kernel->atomClients, &old));
2898 if (Kernel->vg == gcvNULL)
2901 /* Last client detached, switch to SUSPEND power state. */
2902 gcmkONERROR(gckOS_Broadcast(Kernel->os,
2904 gcvBROADCAST_LAST_PROCESS));
2907 /* Flush the debug cache. */
2908 gcmkDEBUGFLUSH(~0U);
2914 return gcvSTATUS_OK;
2917 /* Return the status. */
2924 gckKERNEL_MapLogicalToPhysical(
2925 IN gckKERNEL Kernel,
2926 IN gcskSECURE_CACHE_PTR Cache,
2927 IN OUT gctPOINTER * Data
2931 static gctBOOL baseAddressValid = gcvFALSE;
2932 static gctUINT32 baseAddress;
2934 gcskLOGICAL_CACHE_PTR slot;
2936 gcmkHEADER_ARG("Kernel=0x%x Cache=0x%x *Data=0x%x",
2937 Kernel, Cache, gcmOPT_POINTER(Data));
2939 /* Verify the arguments. */
2940 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
2942 if (!baseAddressValid)
2944 /* Get base address. */
2945 gcmkONERROR(gckHARDWARE_GetBaseAddress(Kernel->hardware, &baseAddress));
2947 baseAddressValid = gcvTRUE;
2950 /* Does this state load need a base address? */
2951 gcmkONERROR(gckHARDWARE_NeedBaseAddress(Kernel->hardware,
2952 ((gctUINT32_PTR) Data)[-1],
2955 #if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LRU
2957 gcskLOGICAL_CACHE_PTR next;
2960 /* Walk all used cache slots. */
2961 for (i = 1, slot = Cache->cache[0].next, next = gcvNULL;
2962 (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL);
2963 ++i, slot = slot->next
2966 if (slot->logical == *Data)
2974 /* See if we had a miss. */
2975 if (next == gcvNULL)
2977 /* Use the tail of the cache. */
2978 slot = Cache->cache[0].prev;
2980 /* Initialize the cache line. */
2981 slot->logical = *Data;
2983 /* Map the logical address to a DMA address. */
2985 gckOS_GetPhysicalAddress(Kernel->os, *Data, &slot->dma));
2988 /* Move slot to head of list. */
2989 if (slot != Cache->cache[0].next)
2992 slot->prev->next = slot->next;
2993 slot->next->prev = slot->prev;
2995 /* Move to head of chain. */
2996 slot->prev = &Cache->cache[0];
2997 slot->next = Cache->cache[0].next;
2998 slot->prev->next = slot;
2999 slot->next->prev = slot;
3002 #elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LINEAR
3005 gcskLOGICAL_CACHE_PTR next = gcvNULL;
3006 gcskLOGICAL_CACHE_PTR oldestSlot = gcvNULL;
3009 if (Cache->cacheIndex != gcvNULL)
3011 /* Walk the cache forwards. */
3012 for (i = 1, slot = Cache->cacheIndex;
3013 (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL);
3014 ++i, slot = slot->next)
3016 if (slot->logical == *Data)
3023 /* Determine age of this slot. */
3024 if ((oldestSlot == gcvNULL)
3025 || (oldestSlot->stamp > slot->stamp)
3032 if (next == gcvNULL)
3034 /* Walk the cache backwards. */
3035 for (slot = Cache->cacheIndex->prev;
3036 (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL);
3037 ++i, slot = slot->prev)
3039 if (slot->logical == *Data)
3046 /* Determine age of this slot. */
3047 if ((oldestSlot == gcvNULL)
3048 || (oldestSlot->stamp > slot->stamp)
3057 /* See if we had a miss. */
3058 if (next == gcvNULL)
3060 if (Cache->cacheFree != 0)
3062 slot = &Cache->cache[Cache->cacheFree];
3063 gcmkASSERT(slot->logical == gcvNULL);
3065 ++ Cache->cacheFree;
3066 if (Cache->cacheFree >= gcmCOUNTOF(Cache->cache))
3068 Cache->cacheFree = 0;
3073 /* Use the oldest cache slot. */
3074 gcmkASSERT(oldestSlot != gcvNULL);
3077 /* Unlink from the chain. */
3078 slot->prev->next = slot->next;
3079 slot->next->prev = slot->prev;
3081 /* Append to the end. */
3082 slot->prev = Cache->cache[0].prev;
3083 slot->next = &Cache->cache[0];
3084 slot->prev->next = slot;
3085 slot->next->prev = slot;
3088 /* Initialize the cache line. */
3089 slot->logical = *Data;
3091 /* Map the logical address to a DMA address. */
3093 gckOS_GetPhysicalAddress(Kernel->os, *Data, &slot->dma));
3096 /* Save time stamp. */
3097 slot->stamp = ++ Cache->cacheStamp;
3099 /* Save current slot for next lookup. */
3100 Cache->cacheIndex = slot;
3102 #elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
3105 gctUINT32 data = gcmPTR2INT32(*Data);
3106 gctUINT32 key, index;
3107 gcskLOGICAL_CACHE_PTR hash;
3109 /* Generate a hash key. */
3110 key = (data >> 24) + (data >> 16) + (data >> 8) + data;
3111 index = key % gcmCOUNTOF(Cache->hash);
3113 /* Get the hash entry. */
3114 hash = &Cache->hash[index];
3116 for (slot = hash->nextHash, i = 0;
3117 (slot != gcvNULL) && (i < gcdSECURE_CACHE_SLOTS);
3118 slot = slot->nextHash, ++i
3121 if (slot->logical == (*Data))
3127 if (slot == gcvNULL)
3129 /* Grab from the tail of the cache. */
3130 slot = Cache->cache[0].prev;
3132 /* Unlink slot from any hash table it is part of. */
3133 if (slot->prevHash != gcvNULL)
3135 slot->prevHash->nextHash = slot->nextHash;
3137 if (slot->nextHash != gcvNULL)
3139 slot->nextHash->prevHash = slot->prevHash;
3142 /* Initialize the cache line. */
3143 slot->logical = *Data;
3145 /* Map the logical address to a DMA address. */
3147 gckOS_GetPhysicalAddress(Kernel->os, *Data, &slot->dma));
3149 if (hash->nextHash != gcvNULL)
3151 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
3152 "Hash Collision: logical=0x%x key=0x%08x",
3156 /* Insert the slot at the head of the hash list. */
3157 slot->nextHash = hash->nextHash;
3158 if (slot->nextHash != gcvNULL)
3160 slot->nextHash->prevHash = slot;
3162 slot->prevHash = hash;
3163 hash->nextHash = slot;
3166 /* Move slot to head of list. */
3167 if (slot != Cache->cache[0].next)
3170 slot->prev->next = slot->next;
3171 slot->next->prev = slot->prev;
3173 /* Move to head of chain. */
3174 slot->prev = &Cache->cache[0];
3175 slot->next = Cache->cache[0].next;
3176 slot->prev->next = slot;
3177 slot->next->prev = slot;
3180 #elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_TABLE
3182 gctUINT32 index = (gcmPTR2INT32(*Data) % gcdSECURE_CACHE_SLOTS) + 1;
3184 /* Get cache slot. */
3185 slot = &Cache->cache[index];
3187 /* Check for cache miss. */
3188 if (slot->logical != *Data)
3190 /* Initialize the cache line. */
3191 slot->logical = *Data;
3193 /* Map the logical address to a DMA address. */
3195 gckOS_GetPhysicalAddress(Kernel->os, *Data, &slot->dma));
3200 /* Return DMA address. */
3201 *Data = gcmINT2PTR(slot->dma + (needBase ? baseAddress : 0));
3204 gcmkFOOTER_ARG("*Data=0x%08x", *Data);
3205 return gcvSTATUS_OK;
3208 /* Return the status. */
3214 gckKERNEL_FlushTranslationCache(
3215 IN gckKERNEL Kernel,
3216 IN gcskSECURE_CACHE_PTR Cache,
3217 IN gctPOINTER Logical,
3222 gcskLOGICAL_CACHE_PTR slot;
3225 gcmkHEADER_ARG("Kernel=0x%x Cache=0x%x Logical=0x%x Bytes=%lu",
3226 Kernel, Cache, Logical, Bytes);
3228 /* Do we need to flush the entire cache? */
3229 if (Logical == gcvNULL)
3231 /* Clear all cache slots. */
3232 for (i = 1; i <= gcdSECURE_CACHE_SLOTS; ++i)
3234 Cache->cache[i].logical = gcvNULL;
3236 #if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
3237 Cache->cache[i].nextHash = gcvNULL;
3238 Cache->cache[i].prevHash = gcvNULL;
3242 #if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
3243 /* Zero the hash table. */
3244 for (i = 0; i < gcmCOUNTOF(Cache->hash); ++i)
3246 Cache->hash[i].nextHash = gcvNULL;
3250 /* Reset the cache functionality. */
3251 Cache->cacheIndex = gcvNULL;
3252 Cache->cacheFree = 1;
3253 Cache->cacheStamp = 0;
3258 gctUINT8_PTR low = (gctUINT8_PTR) Logical;
3259 gctUINT8_PTR high = low + Bytes;
3261 #if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LRU
3262 gcskLOGICAL_CACHE_PTR next;
3264 /* Walk all used cache slots. */
3265 for (i = 1, slot = Cache->cache[0].next;
3266 (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL);
3270 /* Save pointer to next slot. */
3273 /* Test if this slot falls within the range to flush. */
3274 ptr = (gctUINT8_PTR) slot->logical;
3275 if ((ptr >= low) && (ptr < high))
3278 slot->prev->next = slot->next;
3279 slot->next->prev = slot->prev;
3281 /* Append slot to tail of cache. */
3282 slot->prev = Cache->cache[0].prev;
3283 slot->next = &Cache->cache[0];
3284 slot->prev->next = slot;
3285 slot->next->prev = slot;
3287 /* Mark slot as empty. */
3288 slot->logical = gcvNULL;
3292 #elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LINEAR
3293 gcskLOGICAL_CACHE_PTR next;
3295 for (i = 1, slot = Cache->cache[0].next;
3296 (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL);
3299 /* Save pointer to next slot. */
3302 /* Test if this slot falls within the range to flush. */
3303 ptr = (gctUINT8_PTR) slot->logical;
3304 if ((ptr >= low) && (ptr < high))
3306 /* Test if this slot is the current slot. */
3307 if (slot == Cache->cacheIndex)
3309 /* Move to next or previous slot. */
3310 Cache->cacheIndex = (slot->next->logical != gcvNULL)
3312 : (slot->prev->logical != gcvNULL)
3317 /* Unlink slot from cache. */
3318 slot->prev->next = slot->next;
3319 slot->next->prev = slot->prev;
3321 /* Insert slot to head of cache. */
3322 slot->prev = &Cache->cache[0];
3323 slot->next = Cache->cache[0].next;
3324 slot->prev->next = slot;
3325 slot->next->prev = slot;
3327 /* Mark slot as empty. */
3328 slot->logical = gcvNULL;
3333 #elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
3335 gcskLOGICAL_CACHE_PTR hash, next;
3337 /* Walk all hash tables. */
3338 for (i = 0, hash = Cache->hash;
3339 i < gcmCOUNTOF(Cache->hash);
3342 /* Walk all slots in the hash. */
3343 for (j = 0, slot = hash->nextHash;
3344 (j < gcdSECURE_CACHE_SLOTS) && (slot != gcvNULL);
3347 /* Save pointer to next slot. */
3350 /* Test if this slot falls within the range to flush. */
3351 ptr = (gctUINT8_PTR) slot->logical;
3352 if ((ptr >= low) && (ptr < high))
3354 /* Unlink slot from hash table. */
3355 if (slot->prevHash == hash)
3357 hash->nextHash = slot->nextHash;
3361 slot->prevHash->nextHash = slot->nextHash;
3364 if (slot->nextHash != gcvNULL)
3366 slot->nextHash->prevHash = slot->prevHash;
3369 /* Unlink slot from cache. */
3370 slot->prev->next = slot->next;
3371 slot->next->prev = slot->prev;
3373 /* Append slot to tail of cache. */
3374 slot->prev = Cache->cache[0].prev;
3375 slot->next = &Cache->cache[0];
3376 slot->prev->next = slot;
3377 slot->next->prev = slot;
3379 /* Mark slot as empty. */
3380 slot->logical = gcvNULL;
3381 slot->prevHash = gcvNULL;
3382 slot->nextHash = gcvNULL;
3387 #elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_TABLE
3390 /* Loop while inside the range. */
3391 for (i = 1; (low < high) && (i <= gcdSECURE_CACHE_SLOTS); ++i)
3393 /* Get index into cache for this range. */
3394 index = (gcmPTR2INT32(low) % gcdSECURE_CACHE_SLOTS) + 1;
3395 slot = &Cache->cache[index];
3397 /* Test if this slot falls within the range to flush. */
3398 ptr = (gctUINT8_PTR) slot->logical;
3399 if ((ptr >= low) && (ptr < high))
3401 /* Remove entry from cache. */
3402 slot->logical = gcvNULL;
3406 low += gcdSECURE_CACHE_SLOTS;
3413 return gcvSTATUS_OK;
3417 /*******************************************************************************
3419 ** gckKERNEL_Recovery
3421 ** Try to recover the GPU from a fatal error.
3426 ** Pointer to an gckKERNEL object.
3439 gckHARDWARE hardware;
3441 gctUINT32 processID;
3442 gcskSECURE_CACHE_PTR cache;
3447 gctUINT32 i = 0, count = 0;
3448 #if gcdINTERRUPT_STATISTIC
3452 gcmkHEADER_ARG("Kernel=0x%x", Kernel);
3454 /* Validate the arguemnts. */
3455 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
3457 /* Grab gckEVENT object. */
3458 eventObj = Kernel->eventObj;
3459 gcmkVERIFY_OBJECT(eventObj, gcvOBJ_EVENT);
3461 /* Grab gckHARDWARE object. */
3462 hardware = Kernel->hardware;
3463 gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
3465 /* Grab gckCOMMAND object. */
3466 command = Kernel->command;
3467 gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND);
3470 /* Flush the secure mapping cache. */
3471 gcmkONERROR(gckOS_GetProcessID(&processID));
3472 gcmkONERROR(gckKERNEL_GetProcessDBCache(Kernel, processID, &cache));
3473 gcmkONERROR(gckKERNEL_FlushTranslationCache(Kernel, cache, gcvNULL, 0));
3476 if (Kernel->stuckDump == gcdSTUCK_DUMP_MINIMAL)
3478 gcmkPRINT("[galcore]: GPU[%d] hang, automatic recovery.", Kernel->core);
3482 _DumpDriverConfigure(Kernel);
3486 if (Kernel->recovery == gcvFALSE)
3488 gcmkPRINT("[galcore]: Stop driver to keep scene.");
3492 gckOS_Delay(Kernel->os, 10000);
3499 status = gckENTRYQUEUE_Dequeue(&command->queue, &data);
3501 while (status == gcvSTATUS_OK);
3503 /* Issuing a soft reset for the GPU. */
3504 gcmkONERROR(gckHARDWARE_Reset(hardware));
3506 mask = Kernel->restoreMask;
3508 for (i = 0; i < 32; i++)
3510 if (mask & (1 << i))
3516 /* Handle all outstanding events now. */
3519 if (Kernel->core == gcvCORE_MAJOR)
3521 for (i = 0; i < gcdMULTI_GPU; i++)
3523 gcmkONERROR(gckOS_AtomSet(Kernel->os, eventObj->pending3D[i], mask));
3528 gcmkONERROR(gckOS_AtomSet(Kernel->os, eventObj->pending, mask));
3531 gcmkONERROR(gckOS_AtomSet(Kernel->os, eventObj->pending, mask));
3535 if (Kernel->core == gcvCORE_MAJOR)
3537 for (i = 0; i < gcdMULTI_GPU; i++)
3539 eventObj->pending3D[i] = mask;
3544 eventObj->pending = mask;
3547 eventObj->pending = mask;
3551 #if gcdINTERRUPT_STATISTIC
3554 gcmkONERROR(gckOS_AtomDecrement(
3556 eventObj->interruptCount,
3561 gckOS_AtomClearMask(Kernel->hardware->pendingEvent, mask);
3564 gcmkONERROR(gckEVENT_Notify(eventObj, 1));
3566 gcmkVERIFY_OK(gckOS_GetTime(&Kernel->resetTimeStamp));
3570 return gcvSTATUS_OK;
3573 /* Return the status. */
3578 /*******************************************************************************
3580 ** gckKERNEL_OpenUserData
3582 ** Get access to the user data.
3587 ** Pointer to an gckKERNEL object.
3590 ** The flag indicating whether or not the data should be copied.
3592 ** gctPOINTER StaticStorage
3593 ** Pointer to the kernel storage where the data is to be copied if
3594 ** NeedCopy is gcvTRUE.
3596 ** gctPOINTER UserPointer
3597 ** User pointer to the data.
3600 ** Size of the data.
3604 ** gctPOINTER * KernelPointer
3605 ** Pointer to the kernel pointer that will be pointing to the data.
3608 gckKERNEL_OpenUserData(
3609 IN gckKERNEL Kernel,
3610 IN gctBOOL NeedCopy,
3611 IN gctPOINTER StaticStorage,
3612 IN gctPOINTER UserPointer,
3614 OUT gctPOINTER * KernelPointer
3620 "Kernel=0x%08X NeedCopy=%d StaticStorage=0x%08X "
3621 "UserPointer=0x%08X Size=%lu KernelPointer=0x%08X",
3622 Kernel, NeedCopy, StaticStorage, UserPointer, Size, KernelPointer
3625 /* Validate the arguemnts. */
3626 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
3627 gcmkVERIFY_ARGUMENT(!NeedCopy || (StaticStorage != gcvNULL));
3628 gcmkVERIFY_ARGUMENT(UserPointer != gcvNULL);
3629 gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
3630 gcmkVERIFY_ARGUMENT(Size > 0);
3634 /* Copy the user data to the static storage. */
3635 gcmkONERROR(gckOS_CopyFromUserData(
3636 Kernel->os, StaticStorage, UserPointer, Size
3639 /* Set the kernel pointer. */
3640 * KernelPointer = StaticStorage;
3644 gctPOINTER pointer = gcvNULL;
3646 /* Map the user pointer. */
3647 gcmkONERROR(gckOS_MapUserPointer(
3648 Kernel->os, UserPointer, Size, &pointer
3651 /* Set the kernel pointer. */
3652 * KernelPointer = pointer;
3656 /* Return the status. */
3661 /*******************************************************************************
3663 ** gckKERNEL_CloseUserData
3665 ** Release resources associated with the user data connection opened by
3666 ** gckKERNEL_OpenUserData.
3671 ** Pointer to an gckKERNEL object.
3674 ** The flag indicating whether or not the data should be copied.
3676 ** gctBOOL FlushData
3677 ** If gcvTRUE, the data is written back to the user.
3679 ** gctPOINTER UserPointer
3680 ** User pointer to the data.
3683 ** Size of the data.
3687 ** gctPOINTER * KernelPointer
3688 ** Kernel pointer to the data.
3691 gckKERNEL_CloseUserData(
3692 IN gckKERNEL Kernel,
3693 IN gctBOOL NeedCopy,
3694 IN gctBOOL FlushData,
3695 IN gctPOINTER UserPointer,
3697 OUT gctPOINTER * KernelPointer
3700 gceSTATUS status = gcvSTATUS_OK;
3704 "Kernel=0x%08X NeedCopy=%d FlushData=%d "
3705 "UserPointer=0x%08X Size=%lu KernelPointer=0x%08X",
3706 Kernel, NeedCopy, FlushData, UserPointer, Size, KernelPointer
3709 /* Validate the arguemnts. */
3710 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
3711 gcmkVERIFY_ARGUMENT(UserPointer != gcvNULL);
3712 gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
3713 gcmkVERIFY_ARGUMENT(Size > 0);
3715 /* Get a shortcut to the kernel pointer. */
3716 pointer = * KernelPointer;
3718 if (pointer != gcvNULL)
3724 gcmkONERROR(gckOS_CopyToUserData(
3725 Kernel->os, * KernelPointer, UserPointer, Size
3731 /* Unmap record from kernel memory. */
3732 gcmkONERROR(gckOS_UnmapUserPointer(
3740 /* Reset the kernel pointer. */
3741 * KernelPointer = gcvNULL;
3745 /* Return the status. */
3751 gckKERNEL_SetTimeOut(
3752 IN gckKERNEL Kernel,
3753 IN gctUINT32 timeOut
3756 gcmkHEADER_ARG("Kernel=0x%x timeOut=%d", Kernel, timeOut);
3758 Kernel->timeOut = timeOut;
3764 gckKERNEL_AllocateVirtualCommandBuffer(
3765 IN gckKERNEL Kernel,
3766 IN gctBOOL InUserSpace,
3767 IN OUT gctSIZE_T * Bytes,
3768 OUT gctPHYS_ADDR * Physical,
3769 OUT gctPOINTER * Logical
3772 gckOS os = Kernel->os;
3774 gctPOINTER logical = gcvNULL;
3775 gctSIZE_T pageCount;
3776 gctSIZE_T bytes = *Bytes;
3777 gckVIRTUAL_COMMAND_BUFFER_PTR buffer = gcvNULL;
3779 gctUINT32 flag = gcvALLOC_FLAG_NON_CONTIGUOUS;
3781 gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu",
3782 os, InUserSpace, gcmOPT_VALUE(Bytes));
3784 /* Verify the arguments. */
3785 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
3786 gcmkVERIFY_ARGUMENT(Bytes != gcvNULL);
3787 gcmkVERIFY_ARGUMENT(*Bytes > 0);
3788 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
3789 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
3791 gcmkONERROR(gckOS_Allocate(os,
3792 sizeof(gckVIRTUAL_COMMAND_BUFFER),
3793 (gctPOINTER)&buffer));
3795 gcmkONERROR(gckOS_ZeroMemory(buffer, sizeof(gckVIRTUAL_COMMAND_BUFFER)));
3797 buffer->bytes = bytes;
3799 gcmkONERROR(gckOS_AllocatePagedMemoryEx(os,
3803 &buffer->physical));
3807 gcmkONERROR(gckOS_CreateUserVirtualMapping(os,
3814 buffer->userLogical = logical;
3818 gcmkONERROR(gckOS_CreateKernelVirtualMapping(os,
3825 buffer->kernelLogical = logical;
3828 buffer->pageCount = pageCount;
3829 buffer->kernel = Kernel;
3831 gcmkONERROR(gckOS_GetProcessID(&buffer->pid));
3833 #if gcdPROCESS_ADDRESS_SPACE
3834 gcmkONERROR(gckKERNEL_GetProcessMMU(Kernel, &mmu));
3840 gcmkONERROR(gckMMU_AllocatePages(mmu,
3843 &buffer->gpuAddress));
3846 gcmkONERROR(gckOS_MapPagesEx(os,
3851 buffer->pageTable));
3853 gcmkONERROR(gckMMU_Flush(mmu, gcvSURF_INDEX));
3857 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
3858 "gpuAddress = %x pageCount = %d kernelLogical = %x userLogical=%x",
3859 buffer->gpuAddress, buffer->pageCount,
3860 buffer->kernelLogical, buffer->userLogical);
3862 gcmkVERIFY_OK(gckOS_AcquireMutex(os, Kernel->virtualBufferLock, gcvINFINITE));
3864 if (Kernel->virtualBufferHead == gcvNULL)
3866 Kernel->virtualBufferHead =
3867 Kernel->virtualBufferTail = buffer;
3871 buffer->prev = Kernel->virtualBufferTail;
3872 Kernel->virtualBufferTail->next = buffer;
3873 Kernel->virtualBufferTail = buffer;
3876 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Kernel->virtualBufferLock));
3879 return gcvSTATUS_OK;
3882 if (buffer->gpuAddress)
3884 #if gcdPROCESS_ADDRESS_SPACE
3886 gckMMU_FreePages(mmu, buffer->pageTable, buffer->pageCount));
3889 gckMMU_FreePages(Kernel->mmu, buffer->pageTable, buffer->pageCount));
3893 if (buffer->userLogical)
3896 gckOS_DestroyUserVirtualMapping(os,
3899 buffer->userLogical));
3902 if (buffer->kernelLogical)
3905 gckOS_DestroyKernelVirtualMapping(os,
3908 buffer->kernelLogical));
3911 if (buffer->physical)
3913 gcmkVERIFY_OK(gckOS_FreePagedMemory(os, buffer->physical, bytes));
3916 gcmkVERIFY_OK(gckOS_Free(os, buffer));
3918 /* Return the status. */
3924 gckKERNEL_DestroyVirtualCommandBuffer(
3925 IN gckKERNEL Kernel,
3927 IN gctPHYS_ADDR Physical,
3928 IN gctPOINTER Logical
3933 gckVIRTUAL_COMMAND_BUFFER_PTR buffer = (gckVIRTUAL_COMMAND_BUFFER_PTR)Physical;
3936 gcmkVERIFY_ARGUMENT(buffer != gcvNULL);
3938 kernel = buffer->kernel;
3941 if (!buffer->userLogical)
3943 gcmkVERIFY_OK(gckOS_DestroyKernelVirtualMapping(os,
3949 #if !gcdPROCESS_ADDRESS_SPACE
3951 gckMMU_FreePages(kernel->mmu, buffer->pageTable, buffer->pageCount));
3954 gcmkVERIFY_OK(gckOS_UnmapPages(os, buffer->pageCount, buffer->gpuAddress));
3956 gcmkVERIFY_OK(gckOS_FreePagedMemory(os, buffer->physical, Bytes));
3958 gcmkVERIFY_OK(gckOS_AcquireMutex(os, kernel->virtualBufferLock, gcvINFINITE));
3960 if (buffer == kernel->virtualBufferHead)
3962 if ((kernel->virtualBufferHead = buffer->next) == gcvNULL)
3964 kernel->virtualBufferTail = gcvNULL;
3969 buffer->prev->next = buffer->next;
3971 if (buffer == kernel->virtualBufferTail)
3973 kernel->virtualBufferTail = buffer->prev;
3977 buffer->next->prev = buffer->prev;
3981 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, kernel->virtualBufferLock));
3983 gcmkVERIFY_OK(gckOS_Free(os, buffer));
3986 return gcvSTATUS_OK;
3990 gckKERNEL_GetGPUAddress(
3991 IN gckKERNEL Kernel,
3992 IN gctPOINTER Logical,
3993 IN gctBOOL InUserSpace,
3994 OUT gctUINT32 * Address
3998 gckVIRTUAL_COMMAND_BUFFER_PTR buffer;
4002 gcmkHEADER_ARG("Logical = %x InUserSpace=%d.", Logical, InUserSpace);
4004 gcmkVERIFY_OK(gckOS_GetProcessID(&pid));
4006 status = gcvSTATUS_INVALID_ADDRESS;
4008 gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, Kernel->virtualBufferLock, gcvINFINITE));
4010 /* Walk all command buffer. */
4011 for (buffer = Kernel->virtualBufferHead; buffer != gcvNULL; buffer = buffer->next)
4015 start = buffer->userLogical;
4019 start = buffer->kernelLogical;
4022 if (start == gcvNULL)
4027 if (Logical >= start
4028 && (Logical < (gctPOINTER)((gctUINT8_PTR)start + buffer->pageCount * 4096))
4029 && pid == buffer->pid
4032 * Address = buffer->gpuAddress + (gctUINT32)((gctUINT8_PTR)Logical - (gctUINT8_PTR)start);
4033 status = gcvSTATUS_OK;
4038 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->virtualBufferLock));
4045 gckKERNEL_QueryGPUAddress(
4046 IN gckKERNEL Kernel,
4047 IN gctUINT32 GpuAddress,
4048 OUT gckVIRTUAL_COMMAND_BUFFER_PTR * Buffer
4051 gckVIRTUAL_COMMAND_BUFFER_PTR buffer;
4053 gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
4055 gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, Kernel->virtualBufferLock, gcvINFINITE));
4057 /* Walk all command buffers. */
4058 for (buffer = Kernel->virtualBufferHead; buffer != gcvNULL; buffer = buffer->next)
4060 start = (gctUINT32)buffer->gpuAddress;
4062 if (GpuAddress >= start && GpuAddress < (start + buffer->pageCount * 4096))
4064 /* Find a range matched. */
4066 status = gcvSTATUS_OK;
4071 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->virtualBufferLock));
4076 #if gcdLINK_QUEUE_SIZE
4078 gckLINKQUEUE_Dequeue(
4079 IN gckLINKQUEUE LinkQueue
4082 gcmkASSERT(LinkQueue->count == gcdLINK_QUEUE_SIZE);
4085 LinkQueue->front = (LinkQueue->front + 1) % gcdLINK_QUEUE_SIZE;
4089 gckLINKQUEUE_Enqueue(
4090 IN gckLINKQUEUE LinkQueue,
4095 if (LinkQueue->count == gcdLINK_QUEUE_SIZE)
4097 gckLINKQUEUE_Dequeue(LinkQueue);
4100 gcmkASSERT(LinkQueue->count < gcdLINK_QUEUE_SIZE);
4104 LinkQueue->data[LinkQueue->rear].start = start;
4105 LinkQueue->data[LinkQueue->rear].end = end;
4108 gckOS_GetProcessID(&LinkQueue->data[LinkQueue->rear].pid));
4110 LinkQueue->rear = (LinkQueue->rear + 1) % gcdLINK_QUEUE_SIZE;
4114 gckLINKQUEUE_GetData(
4115 IN gckLINKQUEUE LinkQueue,
4117 OUT gckLINKDATA * Data
4120 gcmkASSERT(Index >= 0 && Index < gcdLINK_QUEUE_SIZE);
4122 *Data = &LinkQueue->data[(Index + LinkQueue->front) % gcdLINK_QUEUE_SIZE];
4127 * gckENTRYQUEUE_Enqueue is called with Command->mutexQueue acquired.
4130 gckENTRYQUEUE_Enqueue(
4131 IN gckKERNEL Kernel,
4132 IN gckENTRYQUEUE Queue,
4133 IN gctUINT32 physical,
4137 gctUINT32 next = (Queue->rear + 1) % gcdENTRY_QUEUE_SIZE;
4139 if (next == Queue->front)
4141 /* Queue is full. */
4142 return gcvSTATUS_INVALID_REQUEST;
4146 Queue->data[Queue->rear].physical = physical;
4147 Queue->data[Queue->rear].bytes = bytes;
4149 gcmkVERIFY_OK(gckOS_MemoryBarrier(Kernel->os, &Queue->rear));
4154 return gcvSTATUS_OK;
4158 gckENTRYQUEUE_Dequeue(
4159 IN gckENTRYQUEUE Queue,
4160 OUT gckENTRYDATA * Data
4163 if (Queue->front == Queue->rear)
4165 /* Queue is empty. */
4166 return gcvSTATUS_INVALID_REQUEST;
4170 *Data = &Queue->data[Queue->front];
4173 Queue->front = (Queue->front + 1) % gcdENTRY_QUEUE_SIZE;
4175 return gcvSTATUS_OK;
4178 /******************************************************************************\
4179 *************************** Pointer - ID translation ***************************
4180 \******************************************************************************/
4181 #define gcdID_TABLE_LENGTH 1024
4182 typedef struct _gcsINTEGERDB * gckINTEGERDB;
4183 typedef struct _gcsINTEGERDB
4189 gctUINT32 currentID;
4195 gckKERNEL_CreateIntegerDatabase(
4196 IN gckKERNEL Kernel,
4197 OUT gctPOINTER * Database
4201 gckINTEGERDB database = gcvNULL;
4203 gcmkHEADER_ARG("Kernel=0x%08X Datbase=0x%08X", Kernel, Database);
4205 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
4206 gcmkVERIFY_ARGUMENT(Database != gcvNULL);
4208 /* Allocate a database. */
4209 gcmkONERROR(gckOS_Allocate(
4210 Kernel->os, gcmSIZEOF(gcsINTEGERDB), (gctPOINTER *)&database));
4212 gcmkONERROR(gckOS_ZeroMemory(database, gcmSIZEOF(gcsINTEGERDB)));
4214 /* Allocate a pointer table. */
4215 gcmkONERROR(gckOS_Allocate(
4216 Kernel->os, gcmSIZEOF(gctPOINTER) * gcdID_TABLE_LENGTH, (gctPOINTER *)&database->table));
4218 gcmkONERROR(gckOS_ZeroMemory(database->table, gcmSIZEOF(gctPOINTER) * gcdID_TABLE_LENGTH));
4220 /* Allocate a database mutex. */
4221 gcmkONERROR(gckOS_CreateMutex(Kernel->os, &database->mutex));
4224 database->currentID = 0;
4225 database->unused = gcdID_TABLE_LENGTH;
4226 database->os = Kernel->os;
4227 database->tableLen = gcdID_TABLE_LENGTH;
4229 *Database = database;
4231 gcmkFOOTER_ARG("*Database=0x%08X", *Database);
4232 return gcvSTATUS_OK;
4238 if (database->table)
4240 gcmkOS_SAFE_FREE(Kernel->os, database->table);
4243 gcmkOS_SAFE_FREE(Kernel->os, database);
4251 gckKERNEL_DestroyIntegerDatabase(
4252 IN gckKERNEL Kernel,
4253 IN gctPOINTER Database
4256 gckINTEGERDB database = Database;
4258 gcmkHEADER_ARG("Kernel=0x%08X Datbase=0x%08X", Kernel, Database);
4260 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
4261 gcmkVERIFY_ARGUMENT(Database != gcvNULL);
4263 /* Destroy pointer table. */
4264 gcmkOS_SAFE_FREE(Kernel->os, database->table);
4266 /* Destroy database mutex. */
4267 gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, database->mutex));
4269 /* Destroy database. */
4270 gcmkOS_SAFE_FREE(Kernel->os, database);
4273 return gcvSTATUS_OK;
4277 gckKERNEL_AllocateIntegerId(
4278 IN gctPOINTER Database,
4279 IN gctPOINTER Pointer,
4284 gckINTEGERDB database = Database;
4285 gctUINT32 i, unused, currentID, tableLen;
4287 gckOS os = database->os;
4288 gctBOOL acquired = gcvFALSE;
4290 gcmkHEADER_ARG("Database=0x%08X Pointer=0x%08X", Database, Pointer);
4292 gcmkVERIFY_ARGUMENT(Id != gcvNULL);
4294 gcmkVERIFY_OK(gckOS_AcquireMutex(os, database->mutex, gcvINFINITE));
4297 if (database->unused < 1)
4302 gcmSIZEOF(gctPOINTER) * (database->tableLen + gcdID_TABLE_LENGTH),
4303 (gctPOINTER *)&table));
4305 gcmkONERROR(gckOS_ZeroMemory(table + database->tableLen,
4306 gcmSIZEOF(gctPOINTER) * gcdID_TABLE_LENGTH));
4308 /* Copy data from old table. */
4309 gckOS_MemCopy(table,
4311 database->tableLen * gcmSIZEOF(gctPOINTER));
4313 gcmkOS_SAFE_FREE(os, database->table);
4315 /* Update databse with new allocated table. */
4316 database->table = table;
4317 database->currentID = database->tableLen;
4318 database->tableLen += gcdID_TABLE_LENGTH;
4319 database->unused += gcdID_TABLE_LENGTH;
4322 table = database->table;
4323 currentID = database->currentID;
4324 tableLen = database->tableLen;
4325 unused = database->unused;
4327 /* Connect id with pointer. */
4328 table[currentID] = Pointer;
4330 *Id = currentID + 1;
4332 /* Update the currentID. */
4335 for (i = 0; i < tableLen; i++)
4337 if (++currentID >= tableLen)
4339 /* Wrap to the begin. */
4343 if (table[currentID] == gcvNULL)
4350 database->table = table;
4351 database->currentID = currentID;
4352 database->tableLen = tableLen;
4353 database->unused = unused;
4355 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
4356 acquired = gcvFALSE;
4358 gcmkFOOTER_ARG("*Id=%d", *Id);
4359 return gcvSTATUS_OK;
4364 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
4372 gckKERNEL_FreeIntegerId(
4373 IN gctPOINTER Database,
4378 gckINTEGERDB database = Database;
4379 gckOS os = database->os;
4380 gctBOOL acquired = gcvFALSE;
4382 gcmkHEADER_ARG("Database=0x%08X Id=%d", Database, Id);
4384 gcmkVERIFY_OK(gckOS_AcquireMutex(os, database->mutex, gcvINFINITE));
4387 if (!(Id > 0 && Id <= database->tableLen))
4389 gcmkONERROR(gcvSTATUS_NOT_FOUND);
4394 database->table[Id] = gcvNULL;
4396 if (database->unused++ == 0)
4398 database->currentID = Id;
4401 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
4402 acquired = gcvFALSE;
4405 return gcvSTATUS_OK;
4410 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
4418 gckKERNEL_QueryIntegerId(
4419 IN gctPOINTER Database,
4421 OUT gctPOINTER * Pointer
4425 gckINTEGERDB database = Database;
4427 gckOS os = database->os;
4428 gctBOOL acquired = gcvFALSE;
4430 gcmkHEADER_ARG("Database=0x%08X Id=%d", Database, Id);
4431 gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
4433 gcmkVERIFY_OK(gckOS_AcquireMutex(os, database->mutex, gcvINFINITE));
4436 if (!(Id > 0 && Id <= database->tableLen))
4438 gcmkONERROR(gcvSTATUS_NOT_FOUND);
4443 pointer = database->table[Id];
4445 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
4446 acquired = gcvFALSE;
4454 gcmkONERROR(gcvSTATUS_NOT_FOUND);
4457 gcmkFOOTER_ARG("*Pointer=0x%08X", *Pointer);
4458 return gcvSTATUS_OK;
4463 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
4472 gckKERNEL_AllocateNameFromPointer(
4473 IN gckKERNEL Kernel,
4474 IN gctPOINTER Pointer
4479 gctPOINTER database = Kernel->db->pointerDatabase;
4481 gcmkHEADER_ARG("Kernel=0x%X Pointer=0x%X", Kernel, Pointer);
4484 gckKERNEL_AllocateIntegerId(database, Pointer, &name));
4486 gcmkFOOTER_ARG("name=%d", name);
4495 gckKERNEL_QueryPointerFromName(
4496 IN gckKERNEL Kernel,
4501 gctPOINTER pointer = gcvNULL;
4502 gctPOINTER database = Kernel->db->pointerDatabase;
4504 gcmkHEADER_ARG("Kernel=0x%X Name=%d", Kernel, Name);
4506 /* Lookup in database to get pointer. */
4507 gcmkONERROR(gckKERNEL_QueryIntegerId(database, Name, &pointer));
4509 gcmkFOOTER_ARG("pointer=0x%X", pointer);
4518 gckKERNEL_DeleteName(
4519 IN gckKERNEL Kernel,
4523 gctPOINTER database = Kernel->db->pointerDatabase;
4525 gcmkHEADER_ARG("Kernel=0x%X Name=0x%X", Kernel, Name);
4527 /* Free name if exists. */
4528 gcmkVERIFY_OK(gckKERNEL_FreeIntegerId(database, Name));
4531 return gcvSTATUS_OK;
4535 gckKERNEL_SetRecovery(
4536 IN gckKERNEL Kernel,
4537 IN gctBOOL Recovery,
4538 IN gctUINT32 StuckDump
4541 Kernel->recovery = Recovery;
4543 if (Recovery == gcvFALSE)
4545 /* Dump stuck information if Recovery is disabled. */
4546 Kernel->stuckDump = gcmMAX(StuckDump, gcdSTUCK_DUMP_MIDDLE);
4549 return gcvSTATUS_OK;
4553 /*******************************************************************************
4554 ***** Shared Buffer ************************************************************
4555 *******************************************************************************/
4557 /*******************************************************************************
4559 ** gckKERNEL_CreateShBuffer
4561 ** Create shared buffer.
4562 ** The shared buffer can be used across processes. Other process needs call
4563 ** gckKERNEL_MapShBuffer before use it.
4568 ** Pointer to an gckKERNEL object.
4571 ** Specify the shared buffer size.
4576 ** Pointer to hold return shared buffer handle.
4579 gckKERNEL_CreateShBuffer(
4580 IN gckKERNEL Kernel,
4582 OUT gctSHBUF * ShBuf
4586 gcsSHBUF_PTR shBuf = gcvNULL;
4588 gcmkHEADER_ARG("Kernel=0x%X, Size=%u", Kernel, Size);
4590 /* Verify the arguments. */
4591 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
4596 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
4598 else if (Size > 1024)
4600 /* Limite shared buffer size. */
4601 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
4604 /* Create a shared buffer structure. */
4606 gckOS_Allocate(Kernel->os,
4608 (gctPOINTER *)&shBuf));
4610 /* Initialize shared buffer. */
4612 shBuf->reference = gcvNULL;
4614 shBuf->data = gcvNULL;
4616 /* Allocate integer id for this shared buffer. */
4618 gckKERNEL_AllocateIntegerId(Kernel->db->pointerDatabase,
4622 /* Allocate atom. */
4623 gcmkONERROR(gckOS_AtomConstruct(Kernel->os, &shBuf->reference));
4625 /* Set default reference count to 1. */
4626 gcmkVERIFY_OK(gckOS_AtomSet(Kernel->os, shBuf->reference, 1));
4628 /* Return integer id. */
4629 *ShBuf = (gctSHBUF)(gctUINTPTR_T)shBuf->id;
4631 gcmkFOOTER_ARG("*ShBuf=%u", shBuf->id);
4632 return gcvSTATUS_OK;
4635 /* Error roll back. */
4636 if (shBuf != gcvNULL)
4641 gckKERNEL_FreeIntegerId(Kernel->db->pointerDatabase,
4645 gcmkOS_SAFE_FREE(Kernel->os, shBuf);
4652 /*******************************************************************************
4654 ** gckKERNEL_DestroyShBuffer
4656 ** Destroy shared buffer.
4657 ** This will decrease reference of specified shared buffer and do actual
4658 ** destroy when no reference on it.
4663 ** Pointer to an gckKERNEL object.
4666 ** Specify the shared buffer to be destroyed.
4673 gckKERNEL_DestroyShBuffer(
4674 IN gckKERNEL Kernel,
4680 gctINT32 oldValue = 0;
4681 gctBOOL acquired = gcvFALSE;
4683 gcmkHEADER_ARG("Kernel=0x%X ShBuf=%u",
4684 Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf);
4686 /* Verify the arguments. */
4687 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
4688 gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL);
4690 /* Acquire mutex. */
4692 gckOS_AcquireMutex(Kernel->os,
4693 Kernel->db->pointerDatabaseMutex,
4697 /* Find shared buffer structure. */
4699 gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase,
4700 (gctUINT32)(gctUINTPTR_T)ShBuf,
4701 (gctPOINTER)&shBuf));
4703 gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf);
4705 /* Decrease the reference count. */
4706 gckOS_AtomDecrement(Kernel->os, shBuf->reference, &oldValue);
4710 /* Free integer id. */
4712 gckKERNEL_FreeIntegerId(Kernel->db->pointerDatabase,
4716 gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, shBuf->reference));
4720 gcmkOS_SAFE_FREE(Kernel->os, shBuf->data);
4721 shBuf->data = gcvNULL;
4724 /* Free the shared buffer. */
4725 gcmkOS_SAFE_FREE(Kernel->os, shBuf);
4728 /* Release the mutex. */
4730 gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
4731 acquired = gcvFALSE;
4734 return gcvSTATUS_OK;
4739 /* Release the mutex. */
4741 gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
4748 /*******************************************************************************
4750 ** gckKERNEL_MapShBuffer
4752 ** Map shared buffer into this process so that it can be used in this process.
4753 ** This will increase reference count on the specified shared buffer.
4754 ** Call gckKERNEL_DestroyShBuffer to dereference.
4759 ** Pointer to an gckKERNEL object.
4762 ** Specify the shared buffer to be mapped.
4769 gckKERNEL_MapShBuffer(
4770 IN gckKERNEL Kernel,
4776 gctINT32 oldValue = 0;
4777 gctBOOL acquired = gcvFALSE;
4779 gcmkHEADER_ARG("Kernel=0x%X ShBuf=%u",
4780 Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf);
4782 /* Verify the arguments. */
4783 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
4784 gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL);
4786 /* Acquire mutex. */
4788 gckOS_AcquireMutex(Kernel->os,
4789 Kernel->db->pointerDatabaseMutex,
4793 /* Find shared buffer structure. */
4795 gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase,
4796 (gctUINT32)(gctUINTPTR_T)ShBuf,
4797 (gctPOINTER)&shBuf));
4799 gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf);
4801 /* Increase the reference count. */
4802 gckOS_AtomIncrement(Kernel->os, shBuf->reference, &oldValue);
4804 /* Release the mutex. */
4806 gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
4807 acquired = gcvFALSE;
4810 return gcvSTATUS_OK;
4815 /* Release the mutex. */
4817 gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
4824 /*******************************************************************************
4826 ** gckKERNEL_WriteShBuffer
4828 ** Write user data into shared buffer.
4833 ** Pointer to an gckKERNEL object.
4836 ** Specify the shared buffer to be written to.
4838 ** gctPOINTER UserData
4839 ** User mode pointer to hold the source data.
4841 ** gctUINT32 ByteCount
4842 ** Specify number of bytes to write. If this is larger than
4843 ** shared buffer size, gcvSTATUS_INVALID_ARGUMENT is returned.
4850 gckKERNEL_WriteShBuffer(
4851 IN gckKERNEL Kernel,
4853 IN gctPOINTER UserData,
4854 IN gctUINT32 ByteCount
4859 gctBOOL acquired = gcvFALSE;
4861 gcmkHEADER_ARG("Kernel=0x%X ShBuf=%u UserData=0x%X ByteCount=%u",
4862 Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf, UserData, ByteCount);
4864 /* Verify the arguments. */
4865 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
4866 gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL);
4868 /* Acquire mutex. */
4870 gckOS_AcquireMutex(Kernel->os,
4871 Kernel->db->pointerDatabaseMutex,
4875 /* Find shared buffer structure. */
4877 gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase,
4878 (gctUINT32)(gctUINTPTR_T)ShBuf,
4879 (gctPOINTER)&shBuf));
4881 gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf);
4883 if ((ByteCount > shBuf->size) ||
4885 (UserData == gcvNULL))
4887 /* Exceeds buffer max size or invalid. */
4888 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
4891 if (shBuf->data == gcvNULL)
4893 /* Allocate buffer data when first time write. */
4894 gcmkONERROR(gckOS_Allocate(Kernel->os, ByteCount, &shBuf->data));
4897 /* Copy data from user. */
4899 gckOS_CopyFromUserData(Kernel->os,
4904 /* Release the mutex. */
4906 gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
4907 acquired = gcvFALSE;
4910 return gcvSTATUS_OK;
4915 /* Release the mutex. */
4917 gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
4924 /*******************************************************************************
4926 ** gckKERNEL_ReadShBuffer
4928 ** Read data from shared buffer and copy to user pointer.
4933 ** Pointer to an gckKERNEL object.
4936 ** Specify the shared buffer to be read from.
4938 ** gctPOINTER UserData
4939 ** User mode pointer to save output data.
4941 ** gctUINT32 ByteCount
4942 ** Specify number of bytes to read.
4943 ** If this is larger than shared buffer size, only avaiable bytes are
4944 ** copied. If smaller, copy requested size.
4948 ** gctUINT32 * BytesRead
4949 ** Pointer to hold how many bytes actually read from shared buffer.
4952 gckKERNEL_ReadShBuffer(
4953 IN gckKERNEL Kernel,
4955 IN gctPOINTER UserData,
4956 IN gctUINT32 ByteCount,
4957 OUT gctUINT32 * BytesRead
4963 gctBOOL acquired = gcvFALSE;
4965 gcmkHEADER_ARG("Kernel=0x%X ShBuf=%u UserData=0x%X ByteCount=%u",
4966 Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf, UserData, ByteCount);
4968 /* Verify the arguments. */
4969 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
4970 gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL);
4972 /* Acquire mutex. */
4974 gckOS_AcquireMutex(Kernel->os,
4975 Kernel->db->pointerDatabaseMutex,
4979 /* Find shared buffer structure. */
4981 gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase,
4982 (gctUINT32)(gctUINTPTR_T)ShBuf,
4983 (gctPOINTER)&shBuf));
4985 gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf);
4987 if (shBuf->data == gcvNULL)
4991 /* No data in shared buffer, skip copy. */
4992 status = gcvSTATUS_SKIP;
4995 else if (ByteCount == 0)
4997 /* Invalid size to read. */
4998 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
5001 /* Determine bytes to copy. */
5002 bytes = (ByteCount < shBuf->size) ? ByteCount : shBuf->size;
5004 /* Copy data to user. */
5006 gckOS_CopyToUserData(Kernel->os,
5011 /* Return copied size. */
5014 /* Release the mutex. */
5016 gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
5017 acquired = gcvFALSE;
5019 gcmkFOOTER_ARG("*BytesRead=%u", bytes);
5020 return gcvSTATUS_OK;
5025 /* Release the mutex. */
5027 gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
5035 /*******************************************************************************
5036 ***** Test Code ****************************************************************
5037 *******************************************************************************/