1 /****************************************************************************
3 * Copyright (C) 2005 - 2013 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"
23 #include "gc_hal_kernel_buffer.h"
27 #include "gc_hal_kernel_qnx.h"
30 #define _GC_OBJ_ZONE gcvZONE_EVENT
32 #define gcdEVENT_ALLOCATION_COUNT (4096 / gcmSIZEOF(gcsHAL_INTERFACE))
33 #define gcdEVENT_MIN_THRESHOLD 4
35 /******************************************************************************\
36 ********************************* Support Code *********************************
37 \******************************************************************************/
40 gckEVENT_AllocateQueue(
42 OUT gcsEVENT_QUEUE_PTR * Queue
47 gcmkHEADER_ARG("Event=0x%x", Event);
49 /* Verify the arguments. */
50 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
51 gcmkVERIFY_ARGUMENT(Queue != gcvNULL);
53 /* Do we have free queues? */
54 if (Event->freeList == gcvNULL)
56 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
59 /* Move one free queue from the free list. */
60 * Queue = Event->freeList;
61 Event->freeList = Event->freeList->next;
64 gcmkFOOTER_ARG("*Queue=0x%x", gcmOPT_POINTER(Queue));
68 /* Return the status. */
76 OUT gcsEVENT_QUEUE_PTR Queue
79 gceSTATUS status = gcvSTATUS_OK;
81 gcmkHEADER_ARG("Event=0x%x", Event);
83 /* Verify the arguments. */
84 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
85 gcmkVERIFY_ARGUMENT(Queue != gcvNULL);
87 /* Move one free queue from the free list. */
88 Queue->next = Event->freeList;
89 Event->freeList = Queue;
99 IN gcsEVENT_PTR Record
103 gctBOOL acquired = gcvFALSE;
105 gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
107 /* Verify the arguments. */
108 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
109 gcmkVERIFY_ARGUMENT(Record != gcvNULL);
111 /* Acquire the mutex. */
112 gcmkONERROR(gckOS_AcquireMutex(Event->os,
113 Event->freeEventMutex,
117 /* Push the record on the free list. */
118 Record->next = Event->freeEventList;
119 Event->freeEventList = Record;
120 Event->freeEventCount += 1;
122 /* Release the mutex. */
123 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
133 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
136 /* Return the status. */
144 OUT gctBOOL_PTR IsEmpty
150 gcmkHEADER_ARG("Event=0x%x", Event);
152 /* Verify the arguments. */
153 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
154 gcmkVERIFY_ARGUMENT(IsEmpty != gcvNULL);
156 /* Assume the event queue is empty. */
159 /* Walk the event queue. */
160 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
162 /* Check whether this event is in use. */
163 if (Event->queues[i].head != gcvNULL)
165 /* The event is in use, hence the queue is not empty. */
171 /* Try acquiring the mutex. */
172 status = gckOS_AcquireMutex(Event->os, Event->eventQueueMutex, 0);
173 if (status == gcvSTATUS_TIMEOUT)
175 /* Timeout - queue is no longer empty. */
180 /* Bail out on error. */
183 /* Release the mutex. */
184 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
188 gcmkFOOTER_ARG("*IsEmpty=%d", gcmOPT_VALUE(IsEmpty));
192 /* Return the status. */
203 gctBOOL empty = gcvFALSE, idle = gcvFALSE;
204 gctBOOL powerLocked = gcvFALSE;
205 gckHARDWARE hardware;
207 gcmkHEADER_ARG("Event=0x%x", Event);
209 /* Verify the arguments. */
210 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
212 /* Grab gckHARDWARE object. */
213 hardware = Event->kernel->hardware;
214 gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
216 /* Check whether the event queue is empty. */
217 gcmkONERROR(gckEVENT_IsEmpty(Event, &empty));
221 status = gckOS_AcquireMutex(hardware->os, hardware->powerMutex, 0);
222 if (status == gcvSTATUS_TIMEOUT)
228 powerLocked = gcvTRUE;
230 /* Query whether the hardware is idle. */
231 gcmkONERROR(gckHARDWARE_QueryIdle(Event->kernel->hardware, &idle));
233 gcmkONERROR(gckOS_ReleaseMutex(hardware->os, hardware->powerMutex));
234 powerLocked = gcvFALSE;
238 /* Inform the system of idle GPU. */
239 gcmkONERROR(gckOS_Broadcast(Event->os,
240 Event->kernel->hardware,
241 gcvBROADCAST_GPU_IDLE));
251 gcmkONERROR(gckOS_ReleaseMutex(hardware->os, hardware->powerMutex));
252 powerLocked = gcvFALSE;
260 __RemoveRecordFromProcessDB(
262 IN gcsEVENT_PTR Record
265 gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
266 gcmkVERIFY_ARGUMENT(Record != gcvNULL);
268 while (Record != gcvNULL)
270 if (Record->info.command == gcvHAL_SIGNAL)
272 /* TODO: Find a better place to bind signal to hardware.*/
273 gcmkVERIFY_OK(gckOS_SignalSetHardware(Event->os,
274 gcmUINT64_TO_PTR(Record->info.u.Signal.signal),
275 Event->kernel->hardware));
278 if (Record->fromKernel)
280 /* No need to check db if event is from kernel. */
281 Record = Record->next;
285 switch (Record->info.command)
287 case gcvHAL_FREE_NON_PAGED_MEMORY:
288 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
292 gcmUINT64_TO_PTR(Record->info.u.FreeNonPagedMemory.logical)));
295 case gcvHAL_FREE_CONTIGUOUS_MEMORY:
296 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
300 gcmUINT64_TO_PTR(Record->info.u.FreeContiguousMemory.logical)));
303 case gcvHAL_FREE_VIDEO_MEMORY:
304 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
308 gcmUINT64_TO_PTR(Record->info.u.FreeVideoMemory.node)));
311 gcuVIDMEM_NODE_PTR node = (gcuVIDMEM_NODE_PTR)(gcmUINT64_TO_PTR(Record->info.u.FreeVideoMemory.node));
313 if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
315 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(Event->kernel,
317 gcvDB_VIDEO_MEMORY_RESERVED,
320 else if(node->Virtual.contiguous)
322 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(Event->kernel,
324 gcvDB_VIDEO_MEMORY_CONTIGUOUS,
329 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(Event->kernel,
331 gcvDB_VIDEO_MEMORY_VIRTUAL,
338 case gcvHAL_UNLOCK_VIDEO_MEMORY:
339 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
342 gcvDB_VIDEO_MEMORY_LOCKED,
343 gcmUINT64_TO_PTR(Record->info.u.UnlockVideoMemory.node)));
346 case gcvHAL_UNMAP_USER_MEMORY:
347 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
350 gcvDB_MAP_USER_MEMORY,
351 gcmINT2PTR(Record->info.u.UnmapUserMemory.info)));
354 case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
355 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
358 gcvDB_COMMAND_BUFFER,
359 gcmUINT64_TO_PTR(Record->info.u.FreeVirtualCommandBuffer.logical)));
366 Record = Record->next;
373 _SubmitTimerFunction(
377 gckEVENT event = (gckEVENT)Data;
378 gcmkVERIFY_OK(gckEVENT_Submit(event, gcvTRUE, gcvFALSE));
381 /******************************************************************************\
382 ******************************* gckEVENT API Code *******************************
383 \******************************************************************************/
385 /*******************************************************************************
387 ** gckEVENT_Construct
389 ** Construct a new gckEVENT object.
394 ** Pointer to an gckKERNEL object.
399 ** Pointer to a variable that receives the gckEVENT object pointer.
409 gckEVENT eventObj = gcvNULL;
412 gctPOINTER pointer = gcvNULL;
414 gcmkHEADER_ARG("Kernel=0x%x", Kernel);
416 /* Verify the arguments. */
417 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
418 gcmkVERIFY_ARGUMENT(Event != gcvNULL);
420 /* Extract the pointer to the gckOS object. */
422 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
424 /* Allocate the gckEVENT object. */
425 gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckEVENT), &pointer));
429 /* Reset the object. */
430 gcmkVERIFY_OK(gckOS_ZeroMemory(eventObj, gcmSIZEOF(struct _gckEVENT)));
432 /* Initialize the gckEVENT object. */
433 eventObj->object.type = gcvOBJ_EVENT;
434 eventObj->kernel = Kernel;
437 /* Create the mutexes. */
438 gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventQueueMutex));
439 gcmkONERROR(gckOS_CreateMutex(os, &eventObj->freeEventMutex));
440 gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventListMutex));
442 /* Create a bunch of event reccords. */
443 for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1)
445 /* Allocate an event record. */
446 gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsEVENT), &pointer));
450 /* Push it on the free list. */
451 record->next = eventObj->freeEventList;
452 eventObj->freeEventList = record;
453 eventObj->freeEventCount += 1;
456 /* Initialize the free list of event queues. */
457 for (i = 0; i < gcdREPO_LIST_COUNT; i += 1)
459 eventObj->repoList[i].next = eventObj->freeList;
460 eventObj->freeList = &eventObj->repoList[i];
463 /* Construct the atom. */
464 gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->freeAtom));
465 gcmkONERROR(gckOS_AtomSet(os,
467 gcmCOUNTOF(eventObj->queues)));
470 gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->pending));
473 gcmkVERIFY_OK(gckOS_CreateTimer(os,
474 _SubmitTimerFunction,
475 (gctPOINTER)eventObj,
476 &eventObj->submitTimer));
478 /* Return pointer to the gckEVENT object. */
482 gcmkFOOTER_ARG("*Event=0x%x", *Event);
487 if (eventObj != gcvNULL)
489 if (eventObj->eventQueueMutex != gcvNULL)
491 gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventQueueMutex));
494 if (eventObj->freeEventMutex != gcvNULL)
496 gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->freeEventMutex));
499 if (eventObj->eventListMutex != gcvNULL)
501 gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventListMutex));
504 while (eventObj->freeEventList != gcvNULL)
506 record = eventObj->freeEventList;
507 eventObj->freeEventList = record->next;
509 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, record));
512 if (eventObj->freeAtom != gcvNULL)
514 gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->freeAtom));
518 if (eventObj->pending != gcvNULL)
520 gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->pending));
523 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, eventObj));
526 /* Return the status. */
531 /*******************************************************************************
535 ** Destroy an gckEVENT object.
540 ** Pointer to an gckEVENT object.
552 gcsEVENT_QUEUE_PTR queue;
554 gcmkHEADER_ARG("Event=0x%x", Event);
556 /* Verify the arguments. */
557 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
559 if (Event->submitTimer != gcvNULL)
561 gcmkVERIFY_OK(gckOS_StopTimer(Event->os, Event->submitTimer));
562 gcmkVERIFY_OK(gckOS_DestroyTimer(Event->os, Event->submitTimer));
565 /* Delete the queue mutex. */
566 gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventQueueMutex));
568 /* Free all free events. */
569 while (Event->freeEventList != gcvNULL)
571 record = Event->freeEventList;
572 Event->freeEventList = record->next;
574 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record));
577 /* Delete the free mutex. */
578 gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->freeEventMutex));
580 /* Free all pending queues. */
581 while (Event->queueHead != gcvNULL)
583 /* Get the current queue. */
584 queue = Event->queueHead;
586 /* Free all pending events. */
587 while (queue->head != gcvNULL)
589 record = queue->head;
590 queue->head = record->next;
593 gcvLEVEL_WARNING, gcvZONE_EVENT,
594 gcmSIZEOF(record) + gcmSIZEOF(queue->source),
595 "Event record 0x%x is still pending for %d.",
596 record, queue->source
599 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record));
602 /* Remove the top queue from the list. */
603 if (Event->queueHead == Event->queueTail)
606 Event->queueTail = gcvNULL;
610 Event->queueHead = Event->queueHead->next;
613 /* Free the queue. */
614 gcmkVERIFY_OK(gckEVENT_FreeQueue(Event, queue));
617 /* Delete the list mutex. */
618 gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventListMutex));
620 /* Delete the atom. */
621 gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->freeAtom));
624 gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->pending));
627 /* Mark the gckEVENT object as unknown. */
628 Event->object.type = gcvOBJ_UNKNOWN;
630 /* Free the gckEVENT object. */
631 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, Event));
638 /*******************************************************************************
642 ** Reserve the next available hardware event.
647 ** Pointer to an gckEVENT object.
650 ** Set to gcvTRUE to force the function to wait if no events are
651 ** immediately available.
653 ** gceKERNEL_WHERE Source
654 ** Source of the event.
658 ** gctUINT8 * EventID
659 ** Reserved event ID.
665 OUT gctUINT8 * EventID,
666 IN gceKERNEL_WHERE Source
671 gctBOOL acquired = gcvFALSE;
678 gcmkHEADER_ARG("Event=0x%x Source=%d", Event, Source);
682 /* Grab the queue mutex. */
683 gcmkONERROR(gckOS_AcquireMutex(Event->os,
684 Event->eventQueueMutex,
688 /* Walk through all events. */
690 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
692 gctINT nextID = gckMATH_ModuloInt((id + 1),
693 gcmCOUNTOF(Event->queues));
695 if (Event->queues[id].head == gcvNULL)
697 *EventID = (gctUINT8) id;
699 Event->lastID = (gctUINT8) nextID;
701 /* Save time stamp of event. */
702 Event->queues[id].stamp = ++(Event->stamp);
703 Event->queues[id].source = Source;
705 gcmkONERROR(gckOS_AtomDecrement(Event->os,
709 if (free <= gcdDYNAMIC_EVENT_THRESHOLD)
711 gcmkONERROR(gckOS_BroadcastHurry(
713 Event->kernel->hardware,
714 gcdDYNAMIC_EVENT_THRESHOLD - free));
718 /* Release the queue mutex. */
719 gcmkONERROR(gckOS_ReleaseMutex(Event->os,
720 Event->eventQueueMutex));
724 gcvLEVEL_INFO, gcvZONE_EVENT,
730 gcmkFOOTER_ARG("*EventID=%u", *EventID);
738 /* No free events, speed up the GPU right now! */
739 gcmkONERROR(gckOS_BroadcastHurry(Event->os,
740 Event->kernel->hardware,
741 gcdDYNAMIC_EVENT_THRESHOLD));
744 /* Release the queue mutex. */
745 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
748 /* Fail if wait is not requested. */
751 /* Out of resources. */
752 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
756 gcmkONERROR(gckOS_Delay(Event->os, 1));
759 /* Increment the wait timer. */
762 if (timer == Event->kernel->timeOut)
764 /* Try to call any outstanding events. */
765 gcmkONERROR(gckHARDWARE_Interrupt(Event->kernel->hardware,
768 else if (timer > Event->kernel->timeOut)
772 gcmSIZEOF(gctCONST_STRING) + gcmSIZEOF(gctINT),
773 "%s(%d): no available events\n",
774 __FUNCTION__, __LINE__
778 gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING);
786 /* Release the queue mutex. */
787 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
790 /* Return the status. */
795 /*******************************************************************************
797 ** gckEVENT_AllocateRecord
799 ** Allocate a record for the new event.
804 ** Pointer to an gckEVENT object.
806 ** gctBOOL AllocateAllowed
807 ** State for allocation if out of free events.
811 ** gcsEVENT_PTR * Record
812 ** Allocated event record.
815 gckEVENT_AllocateRecord(
817 IN gctBOOL AllocateAllowed,
818 OUT gcsEVENT_PTR * Record
822 gctBOOL acquired = gcvFALSE;
825 gctPOINTER pointer = gcvNULL;
827 gcmkHEADER_ARG("Event=0x%x AllocateAllowed=%d", Event, AllocateAllowed);
829 /* Verify the arguments. */
830 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
831 gcmkVERIFY_ARGUMENT(Record != gcvNULL);
833 /* Acquire the mutex. */
834 gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->freeEventMutex, gcvINFINITE));
837 /* Test if we are below the allocation threshold. */
838 if ( (AllocateAllowed && (Event->freeEventCount < gcdEVENT_MIN_THRESHOLD)) ||
839 (Event->freeEventCount == 0) )
841 /* Allocate a bunch of records. */
842 for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1)
844 /* Allocate an event record. */
845 gcmkONERROR(gckOS_Allocate(Event->os,
851 /* Push it on the free list. */
852 record->next = Event->freeEventList;
853 Event->freeEventList = record;
854 Event->freeEventCount += 1;
858 *Record = Event->freeEventList;
859 Event->freeEventList = Event->freeEventList->next;
860 Event->freeEventCount -= 1;
862 /* Release the mutex. */
863 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
867 gcmkFOOTER_ARG("*Record=0x%x", gcmOPT_POINTER(Record));
874 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
877 /* Return the status. */
882 /*******************************************************************************
886 ** Add a new event to the list of events.
891 ** Pointer to an gckEVENT object.
893 ** gcsHAL_INTERFACE_PTR Interface
894 ** Pointer to the interface for the event to be added.
896 ** gceKERNEL_WHERE FromWhere
897 ** Place in the pipe where the event needs to be generated.
899 ** gctBOOL AllocateAllowed
900 ** State for allocation if out of free events.
909 IN gcsHAL_INTERFACE_PTR Interface,
910 IN gceKERNEL_WHERE FromWhere,
911 IN gctBOOL AllocateAllowed,
912 IN gctBOOL FromKernel
916 gctBOOL acquired = gcvFALSE;
917 gcsEVENT_PTR record = gcvNULL;
918 gcsEVENT_QUEUE_PTR queue;
919 gckKERNEL kernel = Event->kernel;
921 gcmkHEADER_ARG("Event=0x%x Interface=0x%x",
924 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, _GC_OBJ_ZONE,
925 "FromWhere=%d AllocateAllowed=%d",
926 FromWhere, AllocateAllowed);
928 /* Verify the arguments. */
929 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
930 gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
932 /* Verify the event command. */
934 ( (Interface->command == gcvHAL_FREE_NON_PAGED_MEMORY)
935 || (Interface->command == gcvHAL_FREE_CONTIGUOUS_MEMORY)
936 || (Interface->command == gcvHAL_FREE_VIDEO_MEMORY)
937 || (Interface->command == gcvHAL_WRITE_DATA)
938 || (Interface->command == gcvHAL_UNLOCK_VIDEO_MEMORY)
939 || (Interface->command == gcvHAL_SIGNAL)
940 || (Interface->command == gcvHAL_UNMAP_USER_MEMORY)
941 || (Interface->command == gcvHAL_TIMESTAMP)
942 || (Interface->command == gcvHAL_COMMIT_DONE)
943 || (Interface->command == gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER)
944 || (Interface->command == gcvHAL_SYNC_POINT)
947 /* Validate the source. */
948 if ((FromWhere != gcvKERNEL_COMMAND) && (FromWhere != gcvKERNEL_PIXEL))
950 /* Invalid argument. */
951 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
954 /* Allocate a free record. */
955 gcmkONERROR(gckEVENT_AllocateRecord(Event, AllocateAllowed, &record));
957 /* Termninate the record. */
958 record->next = gcvNULL;
960 /* Record the committer. */
961 record->fromKernel = FromKernel;
963 /* Copy the event interface into the record. */
964 gckOS_MemCopy(&record->info, Interface, gcmSIZEOF(record->info));
966 /* Get process ID. */
967 gcmkONERROR(gckOS_GetProcessID(&record->processID));
970 record->kernel = Event->kernel;
973 gcmkONERROR(__RemoveRecordFromProcessDB(Event, record));
975 /* Acquire the mutex. */
976 gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->eventListMutex, gcvINFINITE));
979 /* Do we need to allocate a new queue? */
980 if ((Event->queueTail == gcvNULL) || (Event->queueTail->source < FromWhere))
982 /* Allocate a new queue. */
983 gcmkONERROR(gckEVENT_AllocateQueue(Event, &queue));
985 /* Initialize the queue. */
986 queue->source = FromWhere;
987 queue->head = gcvNULL;
988 queue->next = gcvNULL;
990 /* Attach it to the list of allocated queues. */
991 if (Event->queueTail == gcvNULL)
994 Event->queueTail = queue;
998 Event->queueTail->next = queue;
999 Event->queueTail = queue;
1004 queue = Event->queueTail;
1007 /* Attach the record to the queue. */
1008 if (queue->head == gcvNULL)
1010 queue->head = record;
1011 queue->tail = record;
1015 queue->tail->next = record;
1016 queue->tail = record;
1019 /* Unmap user space logical address.
1020 * Linux kernel does not support unmap the memory of other process any more since 3.5.
1021 * Let's unmap memory of self process before submit the event to gpu.
1023 switch(Interface->command)
1025 case gcvHAL_FREE_NON_PAGED_MEMORY:
1026 gcmkONERROR(gckOS_UnmapUserLogical(
1028 gcmNAME_TO_PTR(Interface->u.FreeNonPagedMemory.physical),
1029 (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes,
1030 gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical)));
1032 case gcvHAL_FREE_CONTIGUOUS_MEMORY:
1033 gcmkONERROR(gckOS_UnmapUserLogical(
1035 gcmNAME_TO_PTR(Interface->u.FreeContiguousMemory.physical),
1036 (gctSIZE_T) Interface->u.FreeContiguousMemory.bytes,
1037 gcmUINT64_TO_PTR(Interface->u.FreeContiguousMemory.logical)));
1044 /* Release the mutex. */
1045 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1049 return gcvSTATUS_OK;
1055 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1058 if (record != gcvNULL)
1060 gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record));
1063 /* Return the status. */
1068 /*******************************************************************************
1072 ** Schedule an event to unlock virtual memory.
1077 ** Pointer to an gckEVENT object.
1079 ** gceKERNEL_WHERE FromWhere
1080 ** Place in the pipe where the event needs to be generated.
1082 ** gcuVIDMEM_NODE_PTR Node
1083 ** Pointer to a gcuVIDMEM_NODE union that specifies the virtual memory
1086 ** gceSURF_TYPE Type
1087 ** Type of surface to unlock.
1096 IN gceKERNEL_WHERE FromWhere,
1097 IN gcuVIDMEM_NODE_PTR Node,
1098 IN gceSURF_TYPE Type
1102 gcsHAL_INTERFACE iface;
1104 gcmkHEADER_ARG("Event=0x%x FromWhere=%d Node=0x%x Type=%d",
1105 Event, FromWhere, Node, Type);
1107 /* Verify the arguments. */
1108 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1109 gcmkVERIFY_ARGUMENT(Node != gcvNULL);
1111 /* Mark the event as an unlock. */
1112 iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY;
1113 iface.u.UnlockVideoMemory.node = gcmPTR_TO_UINT64(Node);
1114 iface.u.UnlockVideoMemory.type = Type;
1115 iface.u.UnlockVideoMemory.asynchroneous = 0;
1117 /* Append it to the queue. */
1118 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1122 return gcvSTATUS_OK;
1125 /* Return the status. */
1130 /*******************************************************************************
1132 ** gckEVENT_FreeVideoMemory
1134 ** Schedule an event to free video memory.
1139 ** Pointer to an gckEVENT object.
1141 ** gcuVIDMEM_NODE_PTR VideoMemory
1142 ** Pointer to a gcuVIDMEM_NODE object to free.
1144 ** gceKERNEL_WHERE FromWhere
1145 ** Place in the pipe where the event needs to be generated.
1152 gckEVENT_FreeVideoMemory(
1154 IN gcuVIDMEM_NODE_PTR VideoMemory,
1155 IN gceKERNEL_WHERE FromWhere
1159 gcsHAL_INTERFACE iface;
1161 gcmkHEADER_ARG("Event=0x%x VideoMemory=0x%x FromWhere=%d",
1162 Event, VideoMemory, FromWhere);
1164 /* Verify the arguments. */
1165 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1166 gcmkVERIFY_ARGUMENT(VideoMemory != gcvNULL);
1168 /* Create an event. */
1169 iface.command = gcvHAL_FREE_VIDEO_MEMORY;
1170 iface.u.FreeVideoMemory.node = gcmPTR_TO_UINT64(VideoMemory);
1172 /* Append it to the queue. */
1173 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1177 return gcvSTATUS_OK;
1180 /* Return the status. */
1185 /*******************************************************************************
1187 ** gckEVENT_FreeNonPagedMemory
1189 ** Schedule an event to free non-paged memory.
1194 ** Pointer to an gckEVENT object.
1197 ** Number of bytes of non-paged memory to free.
1199 ** gctPHYS_ADDR Physical
1200 ** Physical address of non-paged memory to free.
1202 ** gctPOINTER Logical
1203 ** Logical address of non-paged memory to free.
1205 ** gceKERNEL_WHERE FromWhere
1206 ** Place in the pipe where the event needs to be generated.
1209 gckEVENT_FreeNonPagedMemory(
1212 IN gctPHYS_ADDR Physical,
1213 IN gctPOINTER Logical,
1214 IN gceKERNEL_WHERE FromWhere
1218 gcsHAL_INTERFACE iface;
1219 gckKERNEL kernel = Event->kernel;
1221 gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
1223 Event, Bytes, Physical, Logical, FromWhere);
1225 /* Verify the arguments. */
1226 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1227 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
1228 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1229 gcmkVERIFY_ARGUMENT(Bytes > 0);
1231 /* Create an event. */
1232 iface.command = gcvHAL_FREE_NON_PAGED_MEMORY;
1233 iface.u.FreeNonPagedMemory.bytes = Bytes;
1234 iface.u.FreeNonPagedMemory.physical = gcmPTR_TO_NAME(Physical);
1235 iface.u.FreeNonPagedMemory.logical = gcmPTR_TO_UINT64(Logical);
1237 /* Append it to the queue. */
1238 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1242 return gcvSTATUS_OK;
1245 /* Return the status. */
1251 gckEVENT_DestroyVirtualCommandBuffer(
1254 IN gctPHYS_ADDR Physical,
1255 IN gctPOINTER Logical,
1256 IN gceKERNEL_WHERE FromWhere
1260 gcsHAL_INTERFACE iface;
1261 gckKERNEL kernel = Event->kernel;
1263 gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
1265 Event, Bytes, Physical, Logical, FromWhere);
1267 /* Verify the arguments. */
1268 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1269 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
1270 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1271 gcmkVERIFY_ARGUMENT(Bytes > 0);
1273 /* Create an event. */
1274 iface.command = gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER;
1275 iface.u.FreeVirtualCommandBuffer.bytes = Bytes;
1276 iface.u.FreeVirtualCommandBuffer.physical = gcmPTR_TO_NAME(Physical);
1277 iface.u.FreeVirtualCommandBuffer.logical = gcmPTR_TO_UINT64(Logical);
1279 /* Append it to the queue. */
1280 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1284 return gcvSTATUS_OK;
1287 /* Return the status. */
1292 /*******************************************************************************
1294 ** gckEVENT_FreeContigiuousMemory
1296 ** Schedule an event to free contiguous memory.
1301 ** Pointer to an gckEVENT object.
1304 ** Number of bytes of contiguous memory to free.
1306 ** gctPHYS_ADDR Physical
1307 ** Physical address of contiguous memory to free.
1309 ** gctPOINTER Logical
1310 ** Logical address of contiguous memory to free.
1312 ** gceKERNEL_WHERE FromWhere
1313 ** Place in the pipe where the event needs to be generated.
1316 gckEVENT_FreeContiguousMemory(
1319 IN gctPHYS_ADDR Physical,
1320 IN gctPOINTER Logical,
1321 IN gceKERNEL_WHERE FromWhere
1325 gcsHAL_INTERFACE iface;
1326 gckKERNEL kernel = Event->kernel;
1328 gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
1330 Event, Bytes, Physical, Logical, FromWhere);
1332 /* Verify the arguments. */
1333 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1334 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
1335 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1336 gcmkVERIFY_ARGUMENT(Bytes > 0);
1338 /* Create an event. */
1339 iface.command = gcvHAL_FREE_CONTIGUOUS_MEMORY;
1340 iface.u.FreeContiguousMemory.bytes = Bytes;
1341 iface.u.FreeContiguousMemory.physical = gcmPTR_TO_NAME(Physical);
1342 iface.u.FreeContiguousMemory.logical = gcmPTR_TO_UINT64(Logical);
1344 /* Append it to the queue. */
1345 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1349 return gcvSTATUS_OK;
1352 /* Return the status. */
1357 /*******************************************************************************
1361 ** Schedule an event to trigger a signal.
1366 ** Pointer to an gckEVENT object.
1369 ** Pointer to the signal to trigger.
1371 ** gceKERNEL_WHERE FromWhere
1372 ** Place in the pipe where the event needs to be generated.
1381 IN gctSIGNAL Signal,
1382 IN gceKERNEL_WHERE FromWhere
1386 gcsHAL_INTERFACE iface;
1388 gcmkHEADER_ARG("Event=0x%x Signal=0x%x FromWhere=%d",
1389 Event, Signal, FromWhere);
1391 /* Verify the arguments. */
1392 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1393 gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
1395 /* Mark the event as a signal. */
1396 iface.command = gcvHAL_SIGNAL;
1397 iface.u.Signal.signal = gcmPTR_TO_UINT64(Signal);
1399 iface.u.Signal.coid = 0;
1400 iface.u.Signal.rcvid = 0;
1402 iface.u.Signal.auxSignal = 0;
1403 iface.u.Signal.process = 0;
1405 /* Append it to the queue. */
1406 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1410 return gcvSTATUS_OK;
1413 /* Return the status. */
1418 /*******************************************************************************
1420 ** gckEVENT_CommitDone
1422 ** Schedule an event to wake up work thread when commit is done by GPU.
1427 ** Pointer to an gckEVENT object.
1429 ** gceKERNEL_WHERE FromWhere
1430 ** Place in the pipe where the event needs to be generated.
1437 gckEVENT_CommitDone(
1439 IN gceKERNEL_WHERE FromWhere
1443 gcsHAL_INTERFACE iface;
1445 gcmkHEADER_ARG("Event=0x%x FromWhere=%d", Event, FromWhere);
1447 /* Verify the arguments. */
1448 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1450 iface.command = gcvHAL_COMMIT_DONE;
1452 /* Append it to the queue. */
1453 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1457 return gcvSTATUS_OK;
1460 /* Return the status. */
1464 /*******************************************************************************
1468 ** Submit the current event queue to the GPU.
1473 ** Pointer to an gckEVENT object.
1476 ** Submit requires one vacant event; if Wait is set to not zero,
1477 ** and there are no vacant events at this time, the function will
1478 ** wait until an event becomes vacant so that submission of the
1479 ** queue is successful.
1481 ** gctBOOL FromPower
1482 ** Determines whether the call originates from inside the power
1483 ** management or not.
1493 IN gctBOOL FromPower
1498 gcsEVENT_QUEUE_PTR queue;
1499 gctBOOL acquired = gcvFALSE;
1500 gckCOMMAND command = gcvNULL;
1501 gctBOOL commitEntered = gcvFALSE;
1507 gcmkHEADER_ARG("Event=0x%x Wait=%d", Event, Wait);
1509 /* Get gckCOMMAND object. */
1510 command = Event->kernel->command;
1512 /* Are there event queues? */
1513 if (Event->queueHead != gcvNULL)
1515 /* Acquire the command queue. */
1516 gcmkONERROR(gckCOMMAND_EnterCommit(command, FromPower));
1517 commitEntered = gcvTRUE;
1519 /* Process all queues. */
1520 while (Event->queueHead != gcvNULL)
1522 /* Acquire the list mutex. */
1523 gcmkONERROR(gckOS_AcquireMutex(Event->os,
1524 Event->eventListMutex,
1528 /* Get the current queue. */
1529 queue = Event->queueHead;
1531 /* Allocate an event ID. */
1532 gcmkONERROR(gckEVENT_GetEvent(Event, Wait, &id, queue->source));
1534 /* Copy event list to event ID queue. */
1535 Event->queues[id].head = queue->head;
1537 /* Remove the top queue from the list. */
1538 if (Event->queueHead == Event->queueTail)
1540 Event->queueHead = gcvNULL;
1541 Event->queueTail = gcvNULL;
1545 Event->queueHead = Event->queueHead->next;
1548 /* Free the queue. */
1549 gcmkONERROR(gckEVENT_FreeQueue(Event, queue));
1551 /* Release the list mutex. */
1552 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1553 acquired = gcvFALSE;
1556 /* Notify immediately on infinite hardware. */
1557 gcmkONERROR(gckEVENT_Interrupt(Event, 1 << id));
1559 gcmkONERROR(gckEVENT_Notify(Event, 0));
1561 /* Get the size of the hardware event. */
1562 gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware,
1565 Event->queues[id].source,
1568 /* Reserve space in the command queue. */
1569 gcmkONERROR(gckCOMMAND_Reserve(command,
1574 /* Set the hardware event in the command queue. */
1575 gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware,
1578 Event->queues[id].source,
1581 /* Execute the hardware event. */
1582 gcmkONERROR(gckCOMMAND_Execute(command, bytes));
1586 /* Release the command queue. */
1587 gcmkONERROR(gckCOMMAND_ExitCommit(command, FromPower));
1588 commitEntered = gcvFALSE;
1591 gcmkVERIFY_OK(_TryToIdleGPU(Event));
1597 return gcvSTATUS_OK;
1602 /* Release the command queue mutex. */
1603 gcmkVERIFY_OK(gckCOMMAND_ExitCommit(command, FromPower));
1608 /* Need to unroll the mutex acquire. */
1609 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1614 /* Need to unroll the event allocation. */
1615 Event->queues[id].head = gcvNULL;
1618 if (status == gcvSTATUS_GPU_NOT_RESPONDING)
1620 /* Broadcast GPU stuck. */
1621 status = gckOS_Broadcast(Event->os,
1622 Event->kernel->hardware,
1623 gcvBROADCAST_GPU_STUCK);
1626 /* Return the status. */
1631 /*******************************************************************************
1635 ** Commit an event queue from the user.
1640 ** Pointer to an gckEVENT object.
1642 ** gcsQUEUE_PTR Queue
1643 ** User event queue.
1652 IN gcsQUEUE_PTR Queue
1656 gcsQUEUE_PTR record = gcvNULL, next;
1657 gctUINT32 processID;
1658 gctBOOL needCopy = gcvFALSE;
1660 gcmkHEADER_ARG("Event=0x%x Queue=0x%x", Event, Queue);
1662 /* Verify the arguments. */
1663 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1665 /* Get the current process ID. */
1666 gcmkONERROR(gckOS_GetProcessID(&processID));
1668 /* Query if we need to copy the client data. */
1669 gcmkONERROR(gckOS_QueryNeedCopy(Event->os, processID, &needCopy));
1671 /* Loop while there are records in the queue. */
1672 while (Queue != gcvNULL)
1678 /* Point to stack record. */
1681 /* Copy the data from the client. */
1682 gcmkONERROR(gckOS_CopyFromUserData(Event->os,
1685 gcmSIZEOF(gcsQUEUE)));
1689 gctPOINTER pointer = gcvNULL;
1691 /* Map record into kernel memory. */
1692 gcmkONERROR(gckOS_MapUserPointer(Event->os,
1694 gcmSIZEOF(gcsQUEUE),
1700 /* Append event record to event queue. */
1702 gckEVENT_AddList(Event, &record->iface, gcvKERNEL_PIXEL, gcvTRUE, gcvFALSE));
1704 /* Next record in the queue. */
1705 next = gcmUINT64_TO_PTR(record->next);
1709 /* Unmap record from kernel memory. */
1711 gckOS_UnmapUserPointer(Event->os,
1713 gcmSIZEOF(gcsQUEUE),
1714 (gctPOINTER *) record));
1721 /* Submit the event list. */
1722 gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE));
1726 return gcvSTATUS_OK;
1729 if ((record != gcvNULL) && !needCopy)
1732 gcmkVERIFY_OK(gckOS_UnmapUserPointer(Event->os,
1734 gcmSIZEOF(gcsQUEUE),
1735 (gctPOINTER *) record));
1738 /* Return the status. */
1743 /*******************************************************************************
1747 ** Schedule a composition event and start a composition.
1752 ** Pointer to an gckEVENT object.
1754 ** gcsHAL_COMPOSE_PTR Info
1755 ** Pointer to the composition structure.
1764 IN gcsHAL_COMPOSE_PTR Info
1768 gcsEVENT_PTR headRecord;
1769 gcsEVENT_PTR tailRecord;
1770 gcsEVENT_PTR tempRecord;
1772 gctUINT32 processID;
1774 gcmkHEADER_ARG("Event=0x%x Info=0x%x", Event, Info);
1776 /* Verify the arguments. */
1777 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1778 gcmkVERIFY_ARGUMENT(Info != gcvNULL);
1780 /* Allocate an event ID. */
1781 gcmkONERROR(gckEVENT_GetEvent(Event, gcvTRUE, &id, gcvKERNEL_PIXEL));
1783 /* Get process ID. */
1784 gcmkONERROR(gckOS_GetProcessID(&processID));
1786 /* Allocate a record. */
1787 gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord));
1788 headRecord = tailRecord = tempRecord;
1790 /* Initialize the record. */
1791 tempRecord->info.command = gcvHAL_SIGNAL;
1792 tempRecord->info.u.Signal.process = Info->process;
1794 tempRecord->info.u.Signal.coid = Info->coid;
1795 tempRecord->info.u.Signal.rcvid = Info->rcvid;
1797 tempRecord->info.u.Signal.signal = Info->signal;
1798 tempRecord->info.u.Signal.auxSignal = 0;
1799 tempRecord->next = gcvNULL;
1800 tempRecord->processID = processID;
1802 /* Allocate another record for user signal #1. */
1803 if (gcmUINT64_TO_PTR(Info->userSignal1) != gcvNULL)
1805 /* Allocate a record. */
1806 gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord));
1807 tailRecord->next = tempRecord;
1808 tailRecord = tempRecord;
1810 /* Initialize the record. */
1811 tempRecord->info.command = gcvHAL_SIGNAL;
1812 tempRecord->info.u.Signal.process = Info->userProcess;
1814 tempRecord->info.u.Signal.coid = Info->coid;
1815 tempRecord->info.u.Signal.rcvid = Info->rcvid;
1817 tempRecord->info.u.Signal.signal = Info->userSignal1;
1818 tempRecord->info.u.Signal.auxSignal = 0;
1819 tempRecord->next = gcvNULL;
1820 tempRecord->processID = processID;
1823 /* Allocate another record for user signal #2. */
1824 if (gcmUINT64_TO_PTR(Info->userSignal2) != gcvNULL)
1826 /* Allocate a record. */
1827 gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord));
1828 tailRecord->next = tempRecord;
1829 tailRecord = tempRecord;
1831 /* Initialize the record. */
1832 tempRecord->info.command = gcvHAL_SIGNAL;
1833 tempRecord->info.u.Signal.process = Info->userProcess;
1835 tempRecord->info.u.Signal.coid = Info->coid;
1836 tempRecord->info.u.Signal.rcvid = Info->rcvid;
1838 tempRecord->info.u.Signal.signal = Info->userSignal2;
1839 tempRecord->info.u.Signal.auxSignal = 0;
1840 tempRecord->next = gcvNULL;
1841 tempRecord->processID = processID;
1844 /* Set the event list. */
1845 Event->queues[id].head = headRecord;
1847 /* Start composition. */
1848 gcmkONERROR(gckHARDWARE_Compose(
1849 Event->kernel->hardware, processID,
1850 gcmUINT64_TO_PTR(Info->physical), gcmUINT64_TO_PTR(Info->logical), Info->offset, Info->size, id
1855 return gcvSTATUS_OK;
1858 /* Return the status. */
1863 /*******************************************************************************
1865 ** gckEVENT_Interrupt
1867 ** Called by the interrupt service routine to store the triggered interrupt
1868 ** mask to be later processed by gckEVENT_Notify.
1873 ** Pointer to an gckEVENT object.
1876 ** Mask for the 32 interrupts.
1888 gcmkHEADER_ARG("Event=0x%x Data=0x%x", Event, Data);
1890 /* Verify the arguments. */
1891 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1893 /* Combine current interrupt status with pending flags. */
1895 gckOS_AtomSetMask(Event->pending, Data);
1896 #elif defined(__QNXNTO__)
1897 atomic_set(&Event->pending, Data);
1899 Event->pending |= Data;
1904 return gcvSTATUS_OK;
1907 /*******************************************************************************
1911 ** Process all triggered interrupts.
1916 ** Pointer to an gckEVENT object.
1928 gceSTATUS status = gcvSTATUS_OK;
1930 gcsEVENT_QUEUE * queue;
1932 gctBOOL acquired = gcvFALSE;
1933 gcuVIDMEM_NODE_PTR node;
1937 gckKERNEL kernel = Event->kernel;
1939 gctBOOL suspended = gcvFALSE;
1941 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
1942 gctINT eventNumber = 0;
1946 gcskSECURE_CACHE_PTR cache;
1949 gcmkHEADER_ARG("Event=0x%x IDs=0x%x", Event, IDs);
1951 /* Verify the arguments. */
1952 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1957 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
1959 if (Event->queues[i].head != gcvNULL)
1961 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
1962 "Queue(%d): stamp=%llu source=%d",
1964 Event->queues[i].stamp,
1965 Event->queues[i].source);
1973 gcsEVENT_PTR record;
1976 /* Get current interrupts. */
1977 gckOS_AtomGet(Event->os, Event->pending, (gctINT32_PTR)&pending);
1979 /* Suspend interrupts. */
1980 gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core));
1981 suspended = gcvTRUE;
1983 /* Get current interrupts. */
1984 pending = Event->pending;
1986 /* Resume interrupts. */
1987 gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
1988 suspended = gcvFALSE;
1993 /* No more pending interrupts - done. */
1997 if (pending & 0x80000000)
1999 gckOS_Print("!!!!!!!!!!!!! AXI BUS ERROR !!!!!!!!!!!!!\n");
2000 gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_EVENT, "AXI BUS ERROR");
2001 pending &= 0x7FFFFFFF;
2004 if (pending & 0x40000000)
2006 gckHARDWARE_DumpMMUException(Event->kernel->hardware);
2008 pending &= 0xBFFFFFFF;
2012 gcvLEVEL_INFO, gcvZONE_EVENT,
2014 "Pending interrupts 0x%x",
2023 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
2025 if (Event->queues[i].head != gcvNULL)
2027 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2028 "Queue(%d): stamp=%llu source=%d",
2030 Event->queues[i].stamp,
2031 Event->queues[i].source);
2037 /* Find the oldest pending interrupt. */
2038 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
2040 if ((Event->queues[i].head != gcvNULL)
2041 && (pending & (1 << i))
2044 if ((queue == gcvNULL)
2045 || (Event->queues[i].stamp < queue->stamp)
2048 queue = &Event->queues[i];
2050 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
2057 if (queue == gcvNULL)
2060 gcvLEVEL_ERROR, gcvZONE_EVENT,
2062 "Interrupts 0x%x are not pending.",
2067 /* Mark pending interrupts as handled. */
2068 gckOS_AtomClearMask(Event->pending, pending);
2069 #elif defined(__QNXNTO__)
2070 /* Mark pending interrupts as handled. */
2071 atomic_clr((gctUINT32_PTR)&Event->pending, pending);
2073 /* Suspend interrupts. */
2074 gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core));
2075 suspended = gcvTRUE;
2077 /* Mark pending interrupts as handled. */
2078 Event->pending &= ~pending;
2080 /* Resume interrupts. */
2081 gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
2082 suspended = gcvFALSE;
2087 /* Check whether there is a missed interrupt. */
2088 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
2090 if ((Event->queues[i].head != gcvNULL)
2091 && (Event->queues[i].stamp < queue->stamp)
2092 && (Event->queues[i].source <= queue->source)
2097 gcmSIZEOF(i) + gcmSIZEOF(Event->queues[i].stamp),
2098 "Event %d lost (stamp %llu)",
2099 i, Event->queues[i].stamp
2102 /* Use this event instead. */
2103 queue = &Event->queues[i];
2110 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
2112 gcvLEVEL_INFO, gcvZONE_EVENT,
2113 gcmSIZEOF(eventNumber),
2114 "Processing interrupt %d",
2121 /* Mark pending interrupt as handled. */
2122 gckOS_AtomClearMask(Event->pending, mask);
2123 #elif defined(__QNXNTO__)
2124 /* Mark pending interrupt as handled. */
2125 atomic_clr(&Event->pending, mask);
2127 /* Suspend interrupts. */
2128 gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core));
2129 suspended = gcvTRUE;
2131 /* Mark pending interrupt as handled. */
2132 Event->pending &= ~mask;
2134 /* Resume interrupts. */
2135 gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
2136 suspended = gcvFALSE;
2139 /* Grab the mutex queue. */
2140 gcmkONERROR(gckOS_AcquireMutex(Event->os,
2141 Event->eventQueueMutex,
2145 /* We are in the notify loop. */
2146 Event->inNotify = gcvTRUE;
2148 /* Grab the event head. */
2149 record = queue->head;
2151 /* Now quickly clear its event list. */
2152 queue->head = gcvNULL;
2154 /* Release the mutex queue. */
2155 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2156 acquired = gcvFALSE;
2158 /* Increase the number of free events. */
2159 gcmkONERROR(gckOS_AtomIncrement(Event->os, Event->freeAtom, &free));
2161 /* Walk all events for this interrupt. */
2162 while (record != gcvNULL)
2164 gcsEVENT_PTR recordNext;
2172 /* Grab next record. */
2173 recordNext = record->next;
2176 /* Assign record->processID as the pid for this galcore thread.
2177 * Used in OS calls like gckOS_UnlockMemory() which do not take a pid.
2179 drv_thread_specific_key_assign(record->processID, 0, Event->kernel->core);
2183 /* Get the cache that belongs to this process. */
2184 gcmkONERROR(gckKERNEL_GetProcessDBCache(Event->kernel,
2190 gcvLEVEL_INFO, gcvZONE_EVENT,
2191 gcmSIZEOF(record->info.command),
2192 "Processing event type: %d",
2193 record->info.command
2196 switch (record->info.command)
2198 case gcvHAL_FREE_NON_PAGED_MEMORY:
2199 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2200 "gcvHAL_FREE_NON_PAGED_MEMORY: 0x%x",
2201 gcmNAME_TO_PTR(record->info.u.FreeNonPagedMemory.physical));
2203 /* Free non-paged memory. */
2204 status = gckOS_FreeNonPagedMemory(
2206 (gctSIZE_T) record->info.u.FreeNonPagedMemory.bytes,
2207 gcmNAME_TO_PTR(record->info.u.FreeNonPagedMemory.physical),
2208 gcmUINT64_TO_PTR(record->info.u.FreeNonPagedMemory.logical));
2210 if (gcmIS_SUCCESS(status))
2213 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2216 gcmUINT64_TO_PTR(record->record.u.FreeNonPagedMemory.logical),
2217 (gctSIZE_T) record->record.u.FreeNonPagedMemory.bytes));
2220 gcmRELEASE_NAME(record->info.u.FreeNonPagedMemory.physical);
2223 case gcvHAL_FREE_CONTIGUOUS_MEMORY:
2225 gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2226 "gcvHAL_FREE_CONTIGUOUS_MEMORY: 0x%x",
2227 gcmNAME_TO_PTR(record->info.u.FreeContiguousMemory.physical));
2229 /* Unmap the user memory. */
2230 status = gckOS_FreeContiguous(
2232 gcmNAME_TO_PTR(record->info.u.FreeContiguousMemory.physical),
2233 gcmUINT64_TO_PTR(record->info.u.FreeContiguousMemory.logical),
2234 (gctSIZE_T) record->info.u.FreeContiguousMemory.bytes);
2236 if (gcmIS_SUCCESS(status))
2239 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2242 gcmUINT64_TO_PTR(record->record.u.FreeContiguousMemory.logical),
2243 (gctSIZE_T) record->record.u.FreeContiguousMemory.bytes));
2246 gcmRELEASE_NAME(record->info.u.FreeContiguousMemory.physical);
2249 case gcvHAL_FREE_VIDEO_MEMORY:
2250 node = gcmUINT64_TO_PTR(record->info.u.FreeVideoMemory.node);
2251 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2252 "gcvHAL_FREE_VIDEO_MEMORY: 0x%x",
2255 #if gcdUSE_VIDMEM_PER_PID
2256 /* Check if the VidMem object still exists. */
2257 if (gckKERNEL_GetVideoMemoryPoolPid(record->kernel,
2260 gcvNULL) == gcvSTATUS_NOT_FOUND)
2262 /*printf("Vidmem not found for process:%d\n", queue->processID);*/
2263 status = gcvSTATUS_OK;
2267 if ((node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
2268 && (node->VidMem.logical != gcvNULL)
2272 gckKERNEL_UnmapVideoMemory(record->kernel,
2273 node->VidMem.logical,
2275 node->VidMem.bytes));
2276 node->VidMem.logical = gcvNULL;
2281 /* Free video memory. */
2283 gckVIDMEM_Free(node);
2287 case gcvHAL_WRITE_DATA:
2289 /* Convert physical into logical address. */
2291 gckOS_MapPhysical(Event->os,
2292 record->info.u.WriteData.address,
2293 gcmSIZEOF(gctUINT32),
2298 gckOS_WriteMemory(Event->os,
2300 record->info.u.WriteData.data));
2302 /* Unmap the physical memory. */
2304 gckOS_UnmapPhysical(Event->os,
2306 gcmSIZEOF(gctUINT32)));
2310 gckOS_WriteMemory(Event->os,
2312 record->info.u.WriteData.address,
2313 record->info.u.WriteData.data));
2317 case gcvHAL_UNLOCK_VIDEO_MEMORY:
2318 node = gcmUINT64_TO_PTR(record->info.u.UnlockVideoMemory.node);
2320 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2321 "gcvHAL_UNLOCK_VIDEO_MEMORY: 0x%x",
2324 /* Save node information before it disappears. */
2326 if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
2333 logical = node->Virtual.logical;
2334 bytes = node->Virtual.bytes;
2339 status = gckVIDMEM_Unlock(
2342 record->info.u.UnlockVideoMemory.type,
2346 if (gcmIS_SUCCESS(status) && (logical != gcvNULL))
2348 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2358 signal = gcmUINT64_TO_PTR(record->info.u.Signal.signal);
2359 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2360 "gcvHAL_SIGNAL: 0x%x",
2364 if ((record->info.u.Signal.coid == 0)
2365 && (record->info.u.Signal.rcvid == 0)
2368 /* Kernel signal. */
2370 gckOS_Signal(Event->os,
2378 gckOS_UserSignal(Event->os,
2380 record->info.u.Signal.rcvid,
2381 record->info.u.Signal.coid));
2385 if (gcmUINT64_TO_PTR(record->info.u.Signal.process) == gcvNULL)
2387 /* Kernel signal. */
2389 gckOS_Signal(Event->os,
2397 gckOS_UserSignal(Event->os,
2399 gcmUINT64_TO_PTR(record->info.u.Signal.process)));
2402 gcmkASSERT(record->info.u.Signal.auxSignal == 0);
2406 case gcvHAL_UNMAP_USER_MEMORY:
2407 info = gcmNAME_TO_PTR(record->info.u.UnmapUserMemory.info);
2408 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2409 "gcvHAL_UNMAP_USER_MEMORY: 0x%x",
2412 /* Unmap the user memory. */
2413 status = gckOS_UnmapUserMemory(
2415 Event->kernel->core,
2416 gcmUINT64_TO_PTR(record->info.u.UnmapUserMemory.memory),
2417 (gctSIZE_T) record->info.u.UnmapUserMemory.size,
2419 record->info.u.UnmapUserMemory.address);
2422 if (gcmIS_SUCCESS(status))
2424 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2427 gcmUINT64_TO_PTR(record->info.u.UnmapUserMemory.memory),
2428 (gctSIZE_T) record->info.u.UnmapUserMemory.size));
2431 gcmRELEASE_NAME(record->info.u.UnmapUserMemory.info);
2434 case gcvHAL_TIMESTAMP:
2435 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2436 "gcvHAL_TIMESTAMP: %d %d",
2437 record->info.u.TimeStamp.timer,
2438 record->info.u.TimeStamp.request);
2440 /* Process the timestamp. */
2441 switch (record->info.u.TimeStamp.request)
2444 status = gckOS_GetTime(&Event->kernel->timers[
2445 record->info.u.TimeStamp.timer].
2450 status = gckOS_GetTime(&Event->kernel->timers[
2451 record->info.u.TimeStamp.timer].
2457 gcvLEVEL_ERROR, gcvZONE_EVENT,
2458 gcmSIZEOF(record->info.u.TimeStamp.request),
2459 "Invalid timestamp request: %d",
2460 record->info.u.TimeStamp.request
2463 status = gcvSTATUS_INVALID_ARGUMENT;
2468 #if gcdVIRTUAL_COMMAND_BUFFER
2469 case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
2471 gckKERNEL_DestroyVirtualCommandBuffer(Event->kernel,
2472 (gctSIZE_T) record->info.u.FreeVirtualCommandBuffer.bytes,
2473 gcmNAME_TO_PTR(record->info.u.FreeVirtualCommandBuffer.physical),
2474 gcmUINT64_TO_PTR(record->info.u.FreeVirtualCommandBuffer.logical)
2476 gcmRELEASE_NAME(record->info.u.FreeVirtualCommandBuffer.physical);
2480 #if gcdANDROID_NATIVE_FENCE_SYNC
2481 case gcvHAL_SYNC_POINT:
2483 gctSYNC_POINT syncPoint;
2485 syncPoint = gcmUINT64_TO_PTR(record->info.u.SyncPoint.syncPoint);
2486 status = gckOS_SignalSyncPoint(Event->os, syncPoint);
2491 case gcvHAL_COMMIT_DONE:
2495 /* Invalid argument. */
2497 gcvLEVEL_ERROR, gcvZONE_EVENT,
2498 gcmSIZEOF(record->info.command),
2499 "Unknown event type: %d",
2500 record->info.command
2503 status = gcvSTATUS_INVALID_ARGUMENT;
2507 /* Make sure there are no errors generated. */
2508 if (gcmIS_ERROR(status))
2511 gcvLEVEL_WARNING, gcvZONE_EVENT,
2513 "Event produced status: %d(%s)",
2514 status, gckOS_DebugStatus2Name(status));
2517 /* Free the event. */
2518 gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record));
2520 /* Advance to next record. */
2521 record = recordNext;
2524 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2525 "Handled interrupt 0x%x", mask);
2530 gcmkONERROR(_TryToIdleGPU(Event));
2533 /* We are out the notify loop. */
2534 Event->inNotify = gcvFALSE;
2538 return gcvSTATUS_OK;
2543 /* Release mutex. */
2544 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2550 /* Resume interrupts. */
2551 gcmkVERIFY_OK(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
2555 /* We are out the notify loop. */
2556 Event->inNotify = gcvFALSE;
2558 /* Return the status. */
2563 /*******************************************************************************
2564 ** gckEVENT_FreeProcess
2566 ** Free all events owned by a particular process ID.
2571 ** Pointer to an gckEVENT object.
2573 ** gctUINT32 ProcessID
2574 ** Process ID of the process to be freed up.
2581 gckEVENT_FreeProcess(
2583 IN gctUINT32 ProcessID
2587 gctBOOL acquired = gcvFALSE;
2588 gcsEVENT_PTR record, next;
2590 gcsEVENT_PTR deleteHead, deleteTail;
2592 gcmkHEADER_ARG("Event=0x%x ProcessID=%d", Event, ProcessID);
2594 /* Verify the arguments. */
2595 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
2597 /* Walk through all queues. */
2598 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
2600 if (Event->queues[i].head != gcvNULL)
2602 /* Grab the event queue mutex. */
2603 gcmkONERROR(gckOS_AcquireMutex(Event->os,
2604 Event->eventQueueMutex,
2608 /* Grab the mutex head. */
2609 record = Event->queues[i].head;
2610 Event->queues[i].head = gcvNULL;
2611 Event->queues[i].tail = gcvNULL;
2612 deleteHead = gcvNULL;
2613 deleteTail = gcvNULL;
2615 while (record != gcvNULL)
2617 next = record->next;
2618 if (record->processID == ProcessID)
2620 if (deleteHead == gcvNULL)
2622 deleteHead = record;
2626 deleteTail->next = record;
2629 deleteTail = record;
2633 if (Event->queues[i].head == gcvNULL)
2635 Event->queues[i].head = record;
2639 Event->queues[i].tail->next = record;
2642 Event->queues[i].tail = record;
2645 record->next = gcvNULL;
2649 /* Release the mutex queue. */
2650 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2651 acquired = gcvFALSE;
2653 /* Loop through the entire list of events. */
2654 for (record = deleteHead; record != gcvNULL; record = next)
2656 /* Get the next event record. */
2657 next = record->next;
2659 /* Free the event record. */
2660 gcmkONERROR(gckEVENT_FreeRecord(Event, record));
2665 gcmkONERROR(_TryToIdleGPU(Event));
2669 return gcvSTATUS_OK;
2672 /* Release the event queue mutex. */
2675 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2678 /* Return the status. */
2683 /*******************************************************************************
2686 ** Stop the hardware using the End event mechanism.
2691 ** Pointer to an gckEVENT object.
2693 ** gctUINT32 ProcessID
2694 ** Process ID Logical belongs.
2696 ** gctPHYS_ADDR Handle
2697 ** Physical address handle. If gcvNULL it is video memory.
2699 ** gctPOINTER Logical
2700 ** Logical address to flush.
2703 ** Pointer to the signal to trigger.
2712 IN gctUINT32 ProcessID,
2713 IN gctPHYS_ADDR Handle,
2714 IN gctPOINTER Logical,
2715 IN gctSIGNAL Signal,
2716 IN OUT gctSIZE_T * waitSize
2720 /* gctSIZE_T waitSize;*/
2721 gcsEVENT_PTR record;
2724 gcmkHEADER_ARG("Event=0x%x ProcessID=%u Handle=0x%x Logical=0x%x "
2726 Event, ProcessID, Handle, Logical, Signal);
2728 /* Verify the arguments. */
2729 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
2731 /* Submit the current event queue. */
2732 gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE));
2734 gcmkONERROR(gckEVENT_GetEvent(Event, gcvTRUE, &id, gcvKERNEL_PIXEL));
2736 /* Allocate a record. */
2737 gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &record));
2739 /* Initialize the record. */
2740 record->next = gcvNULL;
2741 record->processID = ProcessID;
2742 record->info.command = gcvHAL_SIGNAL;
2743 record->info.u.Signal.signal = gcmPTR_TO_UINT64(Signal);
2745 record->info.u.Signal.coid = 0;
2746 record->info.u.Signal.rcvid = 0;
2748 record->info.u.Signal.auxSignal = 0;
2749 record->info.u.Signal.process = 0;
2751 /* Append the record. */
2752 Event->queues[id].head = record;
2754 /* Replace last WAIT with END. */
2755 gcmkONERROR(gckHARDWARE_End(
2756 Event->kernel->hardware, Logical, waitSize
2759 #if gcdNONPAGED_MEMORY_CACHEABLE
2760 /* Flush the cache for the END. */
2761 gcmkONERROR(gckOS_CacheClean(
2771 /* Wait for the signal. */
2772 gcmkONERROR(gckOS_WaitSignal(Event->os, Signal, gcvINFINITE));
2776 return gcvSTATUS_OK;
2780 /* Return the status. */
2790 switch (record->info.command)
2792 case gcvHAL_FREE_NON_PAGED_MEMORY:
2793 gcmkPRINT(" gcvHAL_FREE_NON_PAGED_MEMORY");
2796 case gcvHAL_FREE_CONTIGUOUS_MEMORY:
2797 gcmkPRINT(" gcvHAL_FREE_CONTIGUOUS_MEMORY");
2800 case gcvHAL_FREE_VIDEO_MEMORY:
2801 gcmkPRINT(" gcvHAL_FREE_VIDEO_MEMORY");
2804 case gcvHAL_WRITE_DATA:
2805 gcmkPRINT(" gcvHAL_WRITE_DATA");
2808 case gcvHAL_UNLOCK_VIDEO_MEMORY:
2809 gcmkPRINT(" gcvHAL_UNLOCK_VIDEO_MEMORY");
2813 gcmkPRINT(" gcvHAL_SIGNAL process=%d signal=0x%x",
2814 record->info.u.Signal.process,
2815 record->info.u.Signal.signal);
2818 case gcvHAL_UNMAP_USER_MEMORY:
2819 gcmkPRINT(" gcvHAL_UNMAP_USER_MEMORY");
2822 case gcvHAL_TIMESTAMP:
2823 gcmkPRINT(" gcvHAL_TIMESTAMP");
2826 case gcvHAL_COMMIT_DONE:
2827 gcmkPRINT(" gcvHAL_COMMIT_DONE");
2830 case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
2831 gcmkPRINT(" gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER logical=0x%08x",
2832 record->info.u.FreeVirtualCommandBuffer.logical);
2836 gcmkPRINT(" Illegal Event %d", record->info.command);
2841 /*******************************************************************************
2844 ** Dump record in event queue when stuck happens.
2845 ** No protection for the event queue.
2852 gcsEVENT_QUEUE_PTR queueHead = Event->queueHead;
2853 gcsEVENT_QUEUE_PTR queue;
2854 gcsEVENT_PTR record = gcvNULL;
2857 gcmkHEADER_ARG("Event=0x%x", Event);
2859 gcmkPRINT("**************************\n");
2860 gcmkPRINT("*** EVENT STATE DUMP ***\n");
2861 gcmkPRINT("**************************\n");
2864 gcmkPRINT(" Unsumbitted Event:");
2868 record = queueHead->head;
2870 gcmkPRINT(" [%x]:", queue);
2873 _PrintRecord(record);
2874 record = record->next;
2877 if (queueHead == Event->queueTail)
2879 queueHead = gcvNULL;
2883 queueHead = queueHead->next;
2887 gcmkPRINT(" Untriggered Event:");
2888 for (i = 0; i < 30; i++)
2890 queue = &Event->queues[i];
2891 record = queue->head;
2893 gcmkPRINT(" [%d]:", i);
2896 _PrintRecord(record);
2897 record = record->next;
2902 return gcvSTATUS_OK;
2905 gceSTATUS gckEVENT_WaitEmpty(gckEVENT Event)
2909 while (Event->inNotify || (gcmIS_SUCCESS(gckEVENT_IsEmpty(Event, &isEmpty)) && !isEmpty)) ;
2911 return gcvSTATUS_OK;