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 gctUINT32 process, thread;
205 gctBOOL powerLocked = gcvFALSE;
206 gckHARDWARE hardware;
209 gcmkHEADER_ARG("Event=0x%x", Event);
211 /* Verify the arguments. */
212 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
214 /* Grab gckHARDWARE object. */
215 hardware = Event->kernel->hardware;
216 gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
219 /* Check whether the event queue is empty. */
220 gcmkONERROR(gckEVENT_IsEmpty(Event, &empty));
224 status = gckOS_AcquireMutex(hardware->os, hardware->powerMutex, 0);
225 if (status == gcvSTATUS_TIMEOUT)
227 gcmkONERROR(gckOS_GetProcessID(&process));
228 gcmkONERROR(gckOS_GetThreadID(&thread));
230 /* Just return to prevent deadlock. */
231 if ((hardware->powerProcess != process)
232 || (hardware->powerThread != thread))
240 powerLocked = gcvTRUE;
243 /* Query whether the hardware is idle. */
244 gcmkONERROR(gckHARDWARE_QueryIdle(Event->kernel->hardware, &idle));
248 gcmkONERROR(gckOS_ReleaseMutex(hardware->os, hardware->powerMutex));
249 powerLocked = gcvFALSE;
254 /* Inform the system of idle GPU. */
255 gcmkONERROR(gckOS_Broadcast(Event->os,
256 Event->kernel->hardware,
257 gcvBROADCAST_GPU_IDLE));
268 gcmkONERROR(gckOS_ReleaseMutex(hardware->os, hardware->powerMutex));
269 powerLocked = gcvFALSE;
277 __RemoveRecordFromProcessDB(
279 IN gcsEVENT_PTR Record
282 gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
283 gcmkVERIFY_ARGUMENT(Record != gcvNULL);
285 while (Record != gcvNULL)
287 if (Record->info.command == gcvHAL_SIGNAL)
289 /* TODO: Find a better place to bind signal to hardware.*/
290 gcmkVERIFY_OK(gckOS_SignalSetHardware(Event->os,
291 gcmUINT64_TO_PTR(Record->info.u.Signal.signal),
292 Event->kernel->hardware));
295 if (Record->fromKernel)
297 /* No need to check db if event is from kernel. */
298 Record = Record->next;
302 switch (Record->info.command)
304 case gcvHAL_FREE_NON_PAGED_MEMORY:
305 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
309 gcmUINT64_TO_PTR(Record->info.u.FreeNonPagedMemory.logical)));
312 case gcvHAL_FREE_CONTIGUOUS_MEMORY:
313 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
317 gcmUINT64_TO_PTR(Record->info.u.FreeContiguousMemory.logical)));
320 case gcvHAL_FREE_VIDEO_MEMORY:
321 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
325 gcmUINT64_TO_PTR(Record->info.u.FreeVideoMemory.node)));
328 case gcvHAL_UNLOCK_VIDEO_MEMORY:
329 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
332 gcvDB_VIDEO_MEMORY_LOCKED,
333 gcmUINT64_TO_PTR(Record->info.u.UnlockVideoMemory.node)));
336 case gcvHAL_UNMAP_USER_MEMORY:
337 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
340 gcvDB_MAP_USER_MEMORY,
341 gcmINT2PTR(Record->info.u.UnmapUserMemory.info)));
344 case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
345 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
348 gcvDB_COMMAND_BUFFER,
349 gcmUINT64_TO_PTR(Record->info.u.FreeVirtualCommandBuffer.logical)));
356 Record = Record->next;
363 _SubmitTimerFunction(
367 gckEVENT event = (gckEVENT)Data;
368 gcmkVERIFY_OK(gckEVENT_Submit(event, gcvTRUE, gcvFALSE));
371 /******************************************************************************\
372 ******************************* gckEVENT API Code *******************************
373 \******************************************************************************/
375 /*******************************************************************************
377 ** gckEVENT_Construct
379 ** Construct a new gckEVENT object.
384 ** Pointer to an gckKERNEL object.
389 ** Pointer to a variable that receives the gckEVENT object pointer.
399 gckEVENT eventObj = gcvNULL;
402 gctPOINTER pointer = gcvNULL;
404 gcmkHEADER_ARG("Kernel=0x%x", Kernel);
406 /* Verify the arguments. */
407 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
408 gcmkVERIFY_ARGUMENT(Event != gcvNULL);
410 /* Extract the pointer to the gckOS object. */
412 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
414 /* Allocate the gckEVENT object. */
415 gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckEVENT), &pointer));
419 /* Reset the object. */
420 gcmkVERIFY_OK(gckOS_ZeroMemory(eventObj, gcmSIZEOF(struct _gckEVENT)));
422 /* Initialize the gckEVENT object. */
423 eventObj->object.type = gcvOBJ_EVENT;
424 eventObj->kernel = Kernel;
427 /* Create the mutexes. */
428 gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventQueueMutex));
429 gcmkONERROR(gckOS_CreateMutex(os, &eventObj->freeEventMutex));
430 gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventListMutex));
432 /* Create a bunch of event reccords. */
433 for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1)
435 /* Allocate an event record. */
436 gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsEVENT), &pointer));
440 /* Push it on the free list. */
441 record->next = eventObj->freeEventList;
442 eventObj->freeEventList = record;
443 eventObj->freeEventCount += 1;
446 /* Initialize the free list of event queues. */
447 for (i = 0; i < gcdREPO_LIST_COUNT; i += 1)
449 eventObj->repoList[i].next = eventObj->freeList;
450 eventObj->freeList = &eventObj->repoList[i];
453 /* Construct the atom. */
454 gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->freeAtom));
455 gcmkONERROR(gckOS_AtomSet(os,
457 gcmCOUNTOF(eventObj->queues)));
460 gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->pending));
463 gcmkVERIFY_OK(gckOS_CreateTimer(os,
464 _SubmitTimerFunction,
465 (gctPOINTER)eventObj,
466 &eventObj->submitTimer));
468 /* Return pointer to the gckEVENT object. */
472 gcmkFOOTER_ARG("*Event=0x%x", *Event);
477 if (eventObj != gcvNULL)
479 if (eventObj->eventQueueMutex != gcvNULL)
481 gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventQueueMutex));
484 if (eventObj->freeEventMutex != gcvNULL)
486 gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->freeEventMutex));
489 if (eventObj->eventListMutex != gcvNULL)
491 gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventListMutex));
494 while (eventObj->freeEventList != gcvNULL)
496 record = eventObj->freeEventList;
497 eventObj->freeEventList = record->next;
499 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, record));
502 if (eventObj->freeAtom != gcvNULL)
504 gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->freeAtom));
508 if (eventObj->pending != gcvNULL)
510 gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->pending));
513 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, eventObj));
516 /* Return the status. */
521 /*******************************************************************************
525 ** Destroy an gckEVENT object.
530 ** Pointer to an gckEVENT object.
542 gcsEVENT_QUEUE_PTR queue;
544 gcmkHEADER_ARG("Event=0x%x", Event);
546 /* Verify the arguments. */
547 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
549 if (Event->submitTimer != gcvNULL)
551 gcmkVERIFY_OK(gckOS_StopTimer(Event->os, Event->submitTimer));
552 gcmkVERIFY_OK(gckOS_DestroyTimer(Event->os, Event->submitTimer));
555 /* Delete the queue mutex. */
556 gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventQueueMutex));
558 /* Free all free events. */
559 while (Event->freeEventList != gcvNULL)
561 record = Event->freeEventList;
562 Event->freeEventList = record->next;
564 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record));
567 /* Delete the free mutex. */
568 gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->freeEventMutex));
570 /* Free all pending queues. */
571 while (Event->queueHead != gcvNULL)
573 /* Get the current queue. */
574 queue = Event->queueHead;
576 /* Free all pending events. */
577 while (queue->head != gcvNULL)
579 record = queue->head;
580 queue->head = record->next;
583 gcvLEVEL_WARNING, gcvZONE_EVENT,
584 gcmSIZEOF(record) + gcmSIZEOF(queue->source),
585 "Event record 0x%x is still pending for %d.",
586 record, queue->source
589 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record));
592 /* Remove the top queue from the list. */
593 if (Event->queueHead == Event->queueTail)
596 Event->queueTail = gcvNULL;
600 Event->queueHead = Event->queueHead->next;
603 /* Free the queue. */
604 gcmkVERIFY_OK(gckEVENT_FreeQueue(Event, queue));
607 /* Delete the list mutex. */
608 gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventListMutex));
610 /* Delete the atom. */
611 gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->freeAtom));
614 gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->pending));
617 /* Mark the gckEVENT object as unknown. */
618 Event->object.type = gcvOBJ_UNKNOWN;
620 /* Free the gckEVENT object. */
621 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, Event));
628 /*******************************************************************************
632 ** Reserve the next available hardware event.
637 ** Pointer to an gckEVENT object.
640 ** Set to gcvTRUE to force the function to wait if no events are
641 ** immediately available.
643 ** gceKERNEL_WHERE Source
644 ** Source of the event.
648 ** gctUINT8 * EventID
649 ** Reserved event ID.
655 OUT gctUINT8 * EventID,
656 IN gceKERNEL_WHERE Source
661 gctBOOL acquired = gcvFALSE;
668 gcmkHEADER_ARG("Event=0x%x Source=%d", Event, Source);
672 /* Grab the queue mutex. */
673 gcmkONERROR(gckOS_AcquireMutex(Event->os,
674 Event->eventQueueMutex,
678 /* Walk through all events. */
680 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
682 gctINT nextID = gckMATH_ModuloInt((id + 1),
683 gcmCOUNTOF(Event->queues));
685 if (Event->queues[id].head == gcvNULL)
687 *EventID = (gctUINT8) id;
689 Event->lastID = (gctUINT8) nextID;
691 /* Save time stamp of event. */
692 Event->queues[id].stamp = ++(Event->stamp);
693 Event->queues[id].source = Source;
695 gcmkONERROR(gckOS_AtomDecrement(Event->os,
699 if (free <= gcdDYNAMIC_EVENT_THRESHOLD)
701 gcmkONERROR(gckOS_BroadcastHurry(
703 Event->kernel->hardware,
704 gcdDYNAMIC_EVENT_THRESHOLD - free));
708 /* Release the queue mutex. */
709 gcmkONERROR(gckOS_ReleaseMutex(Event->os,
710 Event->eventQueueMutex));
714 gcvLEVEL_INFO, gcvZONE_EVENT,
720 gcmkFOOTER_ARG("*EventID=%u", *EventID);
728 /* No free events, speed up the GPU right now! */
729 gcmkONERROR(gckOS_BroadcastHurry(Event->os,
730 Event->kernel->hardware,
731 gcdDYNAMIC_EVENT_THRESHOLD));
734 /* Release the queue mutex. */
735 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
738 /* Fail if wait is not requested. */
741 /* Out of resources. */
742 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
746 gcmkONERROR(gckOS_Delay(Event->os, 1));
749 /* Increment the wait timer. */
752 if (timer == gcdGPU_TIMEOUT)
754 /* Try to call any outstanding events. */
755 gcmkONERROR(gckHARDWARE_Interrupt(Event->kernel->hardware,
758 else if (timer > gcdGPU_TIMEOUT)
762 gcmSIZEOF(gctCONST_STRING) + gcmSIZEOF(gctINT),
763 "%s(%d): no available events\n",
764 __FUNCTION__, __LINE__
768 gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING);
776 /* Release the queue mutex. */
777 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
780 /* Return the status. */
785 /*******************************************************************************
787 ** gckEVENT_AllocateRecord
789 ** Allocate a record for the new event.
794 ** Pointer to an gckEVENT object.
796 ** gctBOOL AllocateAllowed
797 ** State for allocation if out of free events.
801 ** gcsEVENT_PTR * Record
802 ** Allocated event record.
805 gckEVENT_AllocateRecord(
807 IN gctBOOL AllocateAllowed,
808 OUT gcsEVENT_PTR * Record
812 gctBOOL acquired = gcvFALSE;
815 gctPOINTER pointer = gcvNULL;
817 gcmkHEADER_ARG("Event=0x%x AllocateAllowed=%d", Event, AllocateAllowed);
819 /* Verify the arguments. */
820 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
821 gcmkVERIFY_ARGUMENT(Record != gcvNULL);
823 /* Acquire the mutex. */
824 gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->freeEventMutex, gcvINFINITE));
827 /* Test if we are below the allocation threshold. */
828 if ( (AllocateAllowed && (Event->freeEventCount < gcdEVENT_MIN_THRESHOLD)) ||
829 (Event->freeEventCount == 0) )
831 /* Allocate a bunch of records. */
832 for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1)
834 /* Allocate an event record. */
835 gcmkONERROR(gckOS_Allocate(Event->os,
841 /* Push it on the free list. */
842 record->next = Event->freeEventList;
843 Event->freeEventList = record;
844 Event->freeEventCount += 1;
848 *Record = Event->freeEventList;
849 Event->freeEventList = Event->freeEventList->next;
850 Event->freeEventCount -= 1;
852 /* Release the mutex. */
853 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
857 gcmkFOOTER_ARG("*Record=0x%x", gcmOPT_POINTER(Record));
864 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
867 /* Return the status. */
872 /*******************************************************************************
876 ** Add a new event to the list of events.
881 ** Pointer to an gckEVENT object.
883 ** gcsHAL_INTERFACE_PTR Interface
884 ** Pointer to the interface for the event to be added.
886 ** gceKERNEL_WHERE FromWhere
887 ** Place in the pipe where the event needs to be generated.
889 ** gctBOOL AllocateAllowed
890 ** State for allocation if out of free events.
899 IN gcsHAL_INTERFACE_PTR Interface,
900 IN gceKERNEL_WHERE FromWhere,
901 IN gctBOOL AllocateAllowed,
902 IN gctBOOL FromKernel
906 gctBOOL acquired = gcvFALSE;
907 gcsEVENT_PTR record = gcvNULL;
908 gcsEVENT_QUEUE_PTR queue;
909 gckKERNEL kernel = Event->kernel;
911 gcmkHEADER_ARG("Event=0x%x Interface=0x%x",
914 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, _GC_OBJ_ZONE,
915 "FromWhere=%d AllocateAllowed=%d",
916 FromWhere, AllocateAllowed);
918 /* Verify the arguments. */
919 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
920 gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
922 /* Verify the event command. */
924 ( (Interface->command == gcvHAL_FREE_NON_PAGED_MEMORY)
925 || (Interface->command == gcvHAL_FREE_CONTIGUOUS_MEMORY)
926 || (Interface->command == gcvHAL_FREE_VIDEO_MEMORY)
927 || (Interface->command == gcvHAL_WRITE_DATA)
928 || (Interface->command == gcvHAL_UNLOCK_VIDEO_MEMORY)
929 || (Interface->command == gcvHAL_SIGNAL)
930 || (Interface->command == gcvHAL_UNMAP_USER_MEMORY)
931 || (Interface->command == gcvHAL_TIMESTAMP)
932 || (Interface->command == gcvHAL_COMMIT_DONE)
933 || (Interface->command == gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER)
936 /* Validate the source. */
937 if ((FromWhere != gcvKERNEL_COMMAND) && (FromWhere != gcvKERNEL_PIXEL))
939 /* Invalid argument. */
940 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
943 /* Allocate a free record. */
944 gcmkONERROR(gckEVENT_AllocateRecord(Event, AllocateAllowed, &record));
946 /* Termninate the record. */
947 record->next = gcvNULL;
949 /* Record the committer. */
950 record->fromKernel = FromKernel;
952 /* Copy the event interface into the record. */
953 gckOS_MemCopy(&record->info, Interface, gcmSIZEOF(record->info));
955 /* Get process ID. */
956 gcmkONERROR(gckOS_GetProcessID(&record->processID));
959 record->kernel = Event->kernel;
962 gcmkONERROR(__RemoveRecordFromProcessDB(Event, record));
964 /* Acquire the mutex. */
965 gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->eventListMutex, gcvINFINITE));
968 /* Do we need to allocate a new queue? */
969 if ((Event->queueTail == gcvNULL) || (Event->queueTail->source < FromWhere))
971 /* Allocate a new queue. */
972 gcmkONERROR(gckEVENT_AllocateQueue(Event, &queue));
974 /* Initialize the queue. */
975 queue->source = FromWhere;
976 queue->head = gcvNULL;
977 queue->next = gcvNULL;
979 /* Attach it to the list of allocated queues. */
980 if (Event->queueTail == gcvNULL)
983 Event->queueTail = queue;
987 Event->queueTail->next = queue;
988 Event->queueTail = queue;
993 queue = Event->queueTail;
996 /* Attach the record to the queue. */
997 if (queue->head == gcvNULL)
999 queue->head = record;
1000 queue->tail = record;
1004 queue->tail->next = record;
1005 queue->tail = record;
1008 /* Unmap user space logical address.
1009 * Linux kernel does not support unmap the memory of other process any more since 3.5.
1010 * Let's unmap memory of self process before submit the event to gpu.
1012 switch(Interface->command)
1014 case gcvHAL_FREE_NON_PAGED_MEMORY:
1015 gcmkONERROR(gckOS_UnmapUserLogical(
1017 gcmNAME_TO_PTR(Interface->u.FreeNonPagedMemory.physical),
1018 (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes,
1019 gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical)));
1021 case gcvHAL_FREE_CONTIGUOUS_MEMORY:
1022 gcmkONERROR(gckOS_UnmapUserLogical(
1024 gcmNAME_TO_PTR(Interface->u.FreeContiguousMemory.physical),
1025 (gctSIZE_T) Interface->u.FreeContiguousMemory.bytes,
1026 gcmUINT64_TO_PTR(Interface->u.FreeContiguousMemory.logical)));
1033 /* Release the mutex. */
1034 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1038 return gcvSTATUS_OK;
1044 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1047 if (record != gcvNULL)
1049 gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record));
1052 /* Return the status. */
1057 /*******************************************************************************
1061 ** Schedule an event to unlock virtual memory.
1066 ** Pointer to an gckEVENT object.
1068 ** gceKERNEL_WHERE FromWhere
1069 ** Place in the pipe where the event needs to be generated.
1071 ** gcuVIDMEM_NODE_PTR Node
1072 ** Pointer to a gcuVIDMEM_NODE union that specifies the virtual memory
1075 ** gceSURF_TYPE Type
1076 ** Type of surface to unlock.
1085 IN gceKERNEL_WHERE FromWhere,
1086 IN gcuVIDMEM_NODE_PTR Node,
1087 IN gceSURF_TYPE Type
1091 gcsHAL_INTERFACE iface;
1093 gcmkHEADER_ARG("Event=0x%x FromWhere=%d Node=0x%x Type=%d",
1094 Event, FromWhere, Node, Type);
1096 /* Verify the arguments. */
1097 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1098 gcmkVERIFY_ARGUMENT(Node != gcvNULL);
1100 /* Mark the event as an unlock. */
1101 iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY;
1102 iface.u.UnlockVideoMemory.node = gcmPTR_TO_UINT64(Node);
1103 iface.u.UnlockVideoMemory.type = Type;
1104 iface.u.UnlockVideoMemory.asynchroneous = 0;
1106 /* Append it to the queue. */
1107 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1111 return gcvSTATUS_OK;
1114 /* Return the status. */
1119 /*******************************************************************************
1121 ** gckEVENT_FreeVideoMemory
1123 ** Schedule an event to free video memory.
1128 ** Pointer to an gckEVENT object.
1130 ** gcuVIDMEM_NODE_PTR VideoMemory
1131 ** Pointer to a gcuVIDMEM_NODE object to free.
1133 ** gceKERNEL_WHERE FromWhere
1134 ** Place in the pipe where the event needs to be generated.
1141 gckEVENT_FreeVideoMemory(
1143 IN gcuVIDMEM_NODE_PTR VideoMemory,
1144 IN gceKERNEL_WHERE FromWhere
1148 gcsHAL_INTERFACE iface;
1150 gcmkHEADER_ARG("Event=0x%x VideoMemory=0x%x FromWhere=%d",
1151 Event, VideoMemory, FromWhere);
1153 /* Verify the arguments. */
1154 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1155 gcmkVERIFY_ARGUMENT(VideoMemory != gcvNULL);
1157 /* Create an event. */
1158 iface.command = gcvHAL_FREE_VIDEO_MEMORY;
1159 iface.u.FreeVideoMemory.node = gcmPTR_TO_UINT64(VideoMemory);
1161 /* Append it to the queue. */
1162 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1166 return gcvSTATUS_OK;
1169 /* Return the status. */
1174 /*******************************************************************************
1176 ** gckEVENT_FreeNonPagedMemory
1178 ** Schedule an event to free non-paged memory.
1183 ** Pointer to an gckEVENT object.
1186 ** Number of bytes of non-paged memory to free.
1188 ** gctPHYS_ADDR Physical
1189 ** Physical address of non-paged memory to free.
1191 ** gctPOINTER Logical
1192 ** Logical address of non-paged memory to free.
1194 ** gceKERNEL_WHERE FromWhere
1195 ** Place in the pipe where the event needs to be generated.
1198 gckEVENT_FreeNonPagedMemory(
1201 IN gctPHYS_ADDR Physical,
1202 IN gctPOINTER Logical,
1203 IN gceKERNEL_WHERE FromWhere
1207 gcsHAL_INTERFACE iface;
1208 gckKERNEL kernel = Event->kernel;
1210 gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
1212 Event, Bytes, Physical, Logical, FromWhere);
1214 /* Verify the arguments. */
1215 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1216 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
1217 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1218 gcmkVERIFY_ARGUMENT(Bytes > 0);
1220 /* Create an event. */
1221 iface.command = gcvHAL_FREE_NON_PAGED_MEMORY;
1222 iface.u.FreeNonPagedMemory.bytes = Bytes;
1223 iface.u.FreeNonPagedMemory.physical = gcmPTR_TO_NAME(Physical);
1224 iface.u.FreeNonPagedMemory.logical = gcmPTR_TO_UINT64(Logical);
1226 /* Append it to the queue. */
1227 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1231 return gcvSTATUS_OK;
1234 /* Return the status. */
1240 gckEVENT_DestroyVirtualCommandBuffer(
1243 IN gctPHYS_ADDR Physical,
1244 IN gctPOINTER Logical,
1245 IN gceKERNEL_WHERE FromWhere
1249 gcsHAL_INTERFACE iface;
1250 gckKERNEL kernel = Event->kernel;
1252 gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
1254 Event, Bytes, Physical, Logical, FromWhere);
1256 /* Verify the arguments. */
1257 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1258 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
1259 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1260 gcmkVERIFY_ARGUMENT(Bytes > 0);
1262 /* Create an event. */
1263 iface.command = gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER;
1264 iface.u.FreeVirtualCommandBuffer.bytes = Bytes;
1265 iface.u.FreeVirtualCommandBuffer.physical = gcmPTR_TO_NAME(Physical);
1266 iface.u.FreeVirtualCommandBuffer.logical = gcmPTR_TO_UINT64(Logical);
1268 /* Append it to the queue. */
1269 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1273 return gcvSTATUS_OK;
1276 /* Return the status. */
1281 /*******************************************************************************
1283 ** gckEVENT_FreeContigiuousMemory
1285 ** Schedule an event to free contiguous memory.
1290 ** Pointer to an gckEVENT object.
1293 ** Number of bytes of contiguous memory to free.
1295 ** gctPHYS_ADDR Physical
1296 ** Physical address of contiguous memory to free.
1298 ** gctPOINTER Logical
1299 ** Logical address of contiguous memory to free.
1301 ** gceKERNEL_WHERE FromWhere
1302 ** Place in the pipe where the event needs to be generated.
1305 gckEVENT_FreeContiguousMemory(
1308 IN gctPHYS_ADDR Physical,
1309 IN gctPOINTER Logical,
1310 IN gceKERNEL_WHERE FromWhere
1314 gcsHAL_INTERFACE iface;
1315 gckKERNEL kernel = Event->kernel;
1317 gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
1319 Event, Bytes, Physical, Logical, FromWhere);
1321 /* Verify the arguments. */
1322 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1323 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
1324 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1325 gcmkVERIFY_ARGUMENT(Bytes > 0);
1327 /* Create an event. */
1328 iface.command = gcvHAL_FREE_CONTIGUOUS_MEMORY;
1329 iface.u.FreeContiguousMemory.bytes = Bytes;
1330 iface.u.FreeContiguousMemory.physical = gcmPTR_TO_NAME(Physical);
1331 iface.u.FreeContiguousMemory.logical = gcmPTR_TO_UINT64(Logical);
1333 /* Append it to the queue. */
1334 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1338 return gcvSTATUS_OK;
1341 /* Return the status. */
1346 /*******************************************************************************
1350 ** Schedule an event to trigger a signal.
1355 ** Pointer to an gckEVENT object.
1358 ** Pointer to the signal to trigger.
1360 ** gceKERNEL_WHERE FromWhere
1361 ** Place in the pipe where the event needs to be generated.
1370 IN gctSIGNAL Signal,
1371 IN gceKERNEL_WHERE FromWhere
1375 gcsHAL_INTERFACE iface;
1377 gcmkHEADER_ARG("Event=0x%x Signal=0x%x FromWhere=%d",
1378 Event, Signal, FromWhere);
1380 /* Verify the arguments. */
1381 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1382 gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
1384 /* Mark the event as a signal. */
1385 iface.command = gcvHAL_SIGNAL;
1386 iface.u.Signal.signal = gcmPTR_TO_UINT64(Signal);
1388 iface.u.Signal.coid = 0;
1389 iface.u.Signal.rcvid = 0;
1391 iface.u.Signal.auxSignal = 0;
1392 iface.u.Signal.process = 0;
1394 /* Append it to the queue. */
1395 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1399 return gcvSTATUS_OK;
1402 /* Return the status. */
1407 /*******************************************************************************
1409 ** gckEVENT_CommitDone
1411 ** Schedule an event to wake up work thread when commit is done by GPU.
1416 ** Pointer to an gckEVENT object.
1418 ** gceKERNEL_WHERE FromWhere
1419 ** Place in the pipe where the event needs to be generated.
1426 gckEVENT_CommitDone(
1428 IN gceKERNEL_WHERE FromWhere
1432 gcsHAL_INTERFACE iface;
1434 gcmkHEADER_ARG("Event=0x%x FromWhere=%d", Event, FromWhere);
1436 /* Verify the arguments. */
1437 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1439 iface.command = gcvHAL_COMMIT_DONE;
1441 /* Append it to the queue. */
1442 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1446 return gcvSTATUS_OK;
1449 /* Return the status. */
1453 /*******************************************************************************
1457 ** Submit the current event queue to the GPU.
1462 ** Pointer to an gckEVENT object.
1465 ** Submit requires one vacant event; if Wait is set to not zero,
1466 ** and there are no vacant events at this time, the function will
1467 ** wait until an event becomes vacant so that submission of the
1468 ** queue is successful.
1470 ** gctBOOL FromPower
1471 ** Determines whether the call originates from inside the power
1472 ** management or not.
1482 IN gctBOOL FromPower
1487 gcsEVENT_QUEUE_PTR queue;
1488 gctBOOL acquired = gcvFALSE;
1489 gckCOMMAND command = gcvNULL;
1490 gctBOOL commitEntered = gcvFALSE;
1496 gcmkHEADER_ARG("Event=0x%x Wait=%d", Event, Wait);
1498 /* Get gckCOMMAND object. */
1499 command = Event->kernel->command;
1501 /* Are there event queues? */
1502 if (Event->queueHead != gcvNULL)
1504 /* Acquire the command queue. */
1505 gcmkONERROR(gckCOMMAND_EnterCommit(command, FromPower));
1506 commitEntered = gcvTRUE;
1508 /* Process all queues. */
1509 while (Event->queueHead != gcvNULL)
1511 /* Acquire the list mutex. */
1512 gcmkONERROR(gckOS_AcquireMutex(Event->os,
1513 Event->eventListMutex,
1517 /* Get the current queue. */
1518 queue = Event->queueHead;
1520 /* Allocate an event ID. */
1521 gcmkONERROR(gckEVENT_GetEvent(Event, Wait, &id, queue->source));
1523 /* Copy event list to event ID queue. */
1524 Event->queues[id].head = queue->head;
1526 /* Remove the top queue from the list. */
1527 if (Event->queueHead == Event->queueTail)
1529 Event->queueHead = gcvNULL;
1530 Event->queueTail = gcvNULL;
1534 Event->queueHead = Event->queueHead->next;
1537 /* Free the queue. */
1538 gcmkONERROR(gckEVENT_FreeQueue(Event, queue));
1540 /* Release the list mutex. */
1541 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1542 acquired = gcvFALSE;
1545 /* Notify immediately on infinite hardware. */
1546 gcmkONERROR(gckEVENT_Interrupt(Event, 1 << id));
1548 gcmkONERROR(gckEVENT_Notify(Event, 0));
1550 /* Get the size of the hardware event. */
1551 gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware,
1554 Event->queues[id].source,
1557 /* Reserve space in the command queue. */
1558 gcmkONERROR(gckCOMMAND_Reserve(command,
1563 /* Set the hardware event in the command queue. */
1564 gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware,
1567 Event->queues[id].source,
1570 /* Execute the hardware event. */
1571 gcmkONERROR(gckCOMMAND_Execute(command, bytes));
1575 /* Release the command queue. */
1576 gcmkONERROR(gckCOMMAND_ExitCommit(command, FromPower));
1577 commitEntered = gcvFALSE;
1580 gcmkVERIFY_OK(_TryToIdleGPU(Event));
1586 return gcvSTATUS_OK;
1591 /* Release the command queue mutex. */
1592 gcmkVERIFY_OK(gckCOMMAND_ExitCommit(command, FromPower));
1597 /* Need to unroll the mutex acquire. */
1598 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1603 /* Need to unroll the event allocation. */
1604 Event->queues[id].head = gcvNULL;
1607 if (status == gcvSTATUS_GPU_NOT_RESPONDING)
1609 /* Broadcast GPU stuck. */
1610 status = gckOS_Broadcast(Event->os,
1611 Event->kernel->hardware,
1612 gcvBROADCAST_GPU_STUCK);
1615 /* Return the status. */
1620 /*******************************************************************************
1624 ** Commit an event queue from the user.
1629 ** Pointer to an gckEVENT object.
1631 ** gcsQUEUE_PTR Queue
1632 ** User event queue.
1641 IN gcsQUEUE_PTR Queue
1645 gcsQUEUE_PTR record = gcvNULL, next;
1646 gctUINT32 processID;
1647 gctBOOL needCopy = gcvFALSE;
1649 gcmkHEADER_ARG("Event=0x%x Queue=0x%x", Event, Queue);
1651 /* Verify the arguments. */
1652 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1654 /* Get the current process ID. */
1655 gcmkONERROR(gckOS_GetProcessID(&processID));
1657 /* Query if we need to copy the client data. */
1658 gcmkONERROR(gckOS_QueryNeedCopy(Event->os, processID, &needCopy));
1660 /* Loop while there are records in the queue. */
1661 while (Queue != gcvNULL)
1667 /* Point to stack record. */
1670 /* Copy the data from the client. */
1671 gcmkONERROR(gckOS_CopyFromUserData(Event->os,
1674 gcmSIZEOF(gcsQUEUE)));
1678 gctPOINTER pointer = gcvNULL;
1680 /* Map record into kernel memory. */
1681 gcmkONERROR(gckOS_MapUserPointer(Event->os,
1683 gcmSIZEOF(gcsQUEUE),
1689 /* Append event record to event queue. */
1691 gckEVENT_AddList(Event, &record->iface, gcvKERNEL_PIXEL, gcvTRUE, gcvFALSE));
1693 /* Next record in the queue. */
1694 next = gcmUINT64_TO_PTR(record->next);
1698 /* Unmap record from kernel memory. */
1700 gckOS_UnmapUserPointer(Event->os,
1702 gcmSIZEOF(gcsQUEUE),
1703 (gctPOINTER *) record));
1710 /* Submit the event list. */
1711 gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE));
1715 return gcvSTATUS_OK;
1718 if ((record != gcvNULL) && !needCopy)
1721 gcmkVERIFY_OK(gckOS_UnmapUserPointer(Event->os,
1723 gcmSIZEOF(gcsQUEUE),
1724 (gctPOINTER *) record));
1727 /* Return the status. */
1732 /*******************************************************************************
1736 ** Schedule a composition event and start a composition.
1741 ** Pointer to an gckEVENT object.
1743 ** gcsHAL_COMPOSE_PTR Info
1744 ** Pointer to the composition structure.
1753 IN gcsHAL_COMPOSE_PTR Info
1757 gcsEVENT_PTR headRecord;
1758 gcsEVENT_PTR tailRecord;
1759 gcsEVENT_PTR tempRecord;
1761 gctUINT32 processID;
1763 gcmkHEADER_ARG("Event=0x%x Info=0x%x", Event, Info);
1765 /* Verify the arguments. */
1766 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1767 gcmkVERIFY_ARGUMENT(Info != gcvNULL);
1769 /* Allocate an event ID. */
1770 gcmkONERROR(gckEVENT_GetEvent(Event, gcvTRUE, &id, gcvKERNEL_PIXEL));
1772 /* Get process ID. */
1773 gcmkONERROR(gckOS_GetProcessID(&processID));
1775 /* Allocate a record. */
1776 gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord));
1777 headRecord = tailRecord = tempRecord;
1779 /* Initialize the record. */
1780 tempRecord->info.command = gcvHAL_SIGNAL;
1781 tempRecord->info.u.Signal.process = Info->process;
1783 tempRecord->info.u.Signal.coid = Info->coid;
1784 tempRecord->info.u.Signal.rcvid = Info->rcvid;
1786 tempRecord->info.u.Signal.signal = Info->signal;
1787 tempRecord->info.u.Signal.auxSignal = 0;
1788 tempRecord->next = gcvNULL;
1789 tempRecord->processID = processID;
1791 /* Allocate another record for user signal #1. */
1792 if (gcmUINT64_TO_PTR(Info->userSignal1) != gcvNULL)
1794 /* Allocate a record. */
1795 gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord));
1796 tailRecord->next = tempRecord;
1797 tailRecord = tempRecord;
1799 /* Initialize the record. */
1800 tempRecord->info.command = gcvHAL_SIGNAL;
1801 tempRecord->info.u.Signal.process = Info->userProcess;
1803 tempRecord->info.u.Signal.coid = Info->coid;
1804 tempRecord->info.u.Signal.rcvid = Info->rcvid;
1806 tempRecord->info.u.Signal.signal = Info->userSignal1;
1807 tempRecord->info.u.Signal.auxSignal = 0;
1808 tempRecord->next = gcvNULL;
1809 tempRecord->processID = processID;
1812 /* Allocate another record for user signal #2. */
1813 if (gcmUINT64_TO_PTR(Info->userSignal2) != gcvNULL)
1815 /* Allocate a record. */
1816 gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord));
1817 tailRecord->next = tempRecord;
1818 tailRecord = tempRecord;
1820 /* Initialize the record. */
1821 tempRecord->info.command = gcvHAL_SIGNAL;
1822 tempRecord->info.u.Signal.process = Info->userProcess;
1824 tempRecord->info.u.Signal.coid = Info->coid;
1825 tempRecord->info.u.Signal.rcvid = Info->rcvid;
1827 tempRecord->info.u.Signal.signal = Info->userSignal2;
1828 tempRecord->info.u.Signal.auxSignal = 0;
1829 tempRecord->next = gcvNULL;
1830 tempRecord->processID = processID;
1833 /* Set the event list. */
1834 Event->queues[id].head = headRecord;
1836 /* Start composition. */
1837 gcmkONERROR(gckHARDWARE_Compose(
1838 Event->kernel->hardware, processID,
1839 gcmUINT64_TO_PTR(Info->physical), gcmUINT64_TO_PTR(Info->logical), Info->offset, Info->size, id
1844 return gcvSTATUS_OK;
1847 /* Return the status. */
1852 /*******************************************************************************
1854 ** gckEVENT_Interrupt
1856 ** Called by the interrupt service routine to store the triggered interrupt
1857 ** mask to be later processed by gckEVENT_Notify.
1862 ** Pointer to an gckEVENT object.
1865 ** Mask for the 32 interrupts.
1877 gcmkHEADER_ARG("Event=0x%x Data=0x%x", Event, Data);
1879 /* Verify the arguments. */
1880 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1882 /* Combine current interrupt status with pending flags. */
1884 gckOS_AtomSetMask(Event->pending, Data);
1885 #elif defined(__QNXNTO__)
1886 atomic_set(&Event->pending, Data);
1888 Event->pending |= Data;
1893 return gcvSTATUS_OK;
1896 /*******************************************************************************
1900 ** Process all triggered interrupts.
1905 ** Pointer to an gckEVENT object.
1917 gceSTATUS status = gcvSTATUS_OK;
1919 gcsEVENT_QUEUE * queue;
1921 gctBOOL acquired = gcvFALSE;
1922 gcuVIDMEM_NODE_PTR node;
1926 gckKERNEL kernel = Event->kernel;
1928 gctBOOL suspended = gcvFALSE;
1930 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
1931 gctINT eventNumber = 0;
1935 gcskSECURE_CACHE_PTR cache;
1938 gcmkHEADER_ARG("Event=0x%x IDs=0x%x", Event, IDs);
1940 /* Verify the arguments. */
1941 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1946 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
1948 if (Event->queues[i].head != gcvNULL)
1950 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
1951 "Queue(%d): stamp=%llu source=%d",
1953 Event->queues[i].stamp,
1954 Event->queues[i].source);
1962 gcsEVENT_PTR record;
1965 /* Get current interrupts. */
1966 gckOS_AtomGet(Event->os, Event->pending, (gctINT32_PTR)&pending);
1968 /* Suspend interrupts. */
1969 gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core));
1970 suspended = gcvTRUE;
1972 /* Get current interrupts. */
1973 pending = Event->pending;
1975 /* Resume interrupts. */
1976 gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
1977 suspended = gcvFALSE;
1982 /* No more pending interrupts - done. */
1986 if (pending & 0x80000000)
1988 gckOS_Print("!!!!!!!!!!!!! AXI BUS ERROR !!!!!!!!!!!!!\n");
1989 gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_EVENT, "AXI BUS ERROR");
1990 pending &= 0x7FFFFFFF;
1993 if (pending & 0x40000000)
1995 gckHARDWARE_DumpMMUException(Event->kernel->hardware);
1997 pending &= 0xBFFFFFFF;
2001 gcvLEVEL_INFO, gcvZONE_EVENT,
2003 "Pending interrupts 0x%x",
2012 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
2014 if (Event->queues[i].head != gcvNULL)
2016 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2017 "Queue(%d): stamp=%llu source=%d",
2019 Event->queues[i].stamp,
2020 Event->queues[i].source);
2026 /* Find the oldest pending interrupt. */
2027 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
2029 if ((Event->queues[i].head != gcvNULL)
2030 && (pending & (1 << i))
2033 if ((queue == gcvNULL)
2034 || (Event->queues[i].stamp < queue->stamp)
2037 queue = &Event->queues[i];
2039 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
2046 if (queue == gcvNULL)
2049 gcvLEVEL_ERROR, gcvZONE_EVENT,
2051 "Interrupts 0x%x are not pending.",
2056 /* Mark pending interrupts as handled. */
2057 gckOS_AtomClearMask(Event->pending, pending);
2058 #elif defined(__QNXNTO__)
2059 /* Mark pending interrupts as handled. */
2060 atomic_clr((gctUINT32_PTR)&Event->pending, pending);
2062 /* Suspend interrupts. */
2063 gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core));
2064 suspended = gcvTRUE;
2066 /* Mark pending interrupts as handled. */
2067 Event->pending &= ~pending;
2069 /* Resume interrupts. */
2070 gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
2071 suspended = gcvFALSE;
2076 /* Check whether there is a missed interrupt. */
2077 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
2079 if ((Event->queues[i].head != gcvNULL)
2080 && (Event->queues[i].stamp < queue->stamp)
2081 && (Event->queues[i].source <= queue->source)
2086 gcmSIZEOF(i) + gcmSIZEOF(Event->queues[i].stamp),
2087 "Event %d lost (stamp %llu)",
2088 i, Event->queues[i].stamp
2091 /* Use this event instead. */
2092 queue = &Event->queues[i];
2099 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
2101 gcvLEVEL_INFO, gcvZONE_EVENT,
2102 gcmSIZEOF(eventNumber),
2103 "Processing interrupt %d",
2110 /* Mark pending interrupt as handled. */
2111 gckOS_AtomClearMask(Event->pending, mask);
2112 #elif defined(__QNXNTO__)
2113 /* Mark pending interrupt as handled. */
2114 atomic_clr(&Event->pending, mask);
2116 /* Suspend interrupts. */
2117 gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core));
2118 suspended = gcvTRUE;
2120 /* Mark pending interrupt as handled. */
2121 Event->pending &= ~mask;
2123 /* Resume interrupts. */
2124 gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
2125 suspended = gcvFALSE;
2128 /* Grab the mutex queue. */
2129 gcmkONERROR(gckOS_AcquireMutex(Event->os,
2130 Event->eventQueueMutex,
2134 /* Grab the event head. */
2135 record = queue->head;
2137 /* Now quickly clear its event list. */
2138 queue->head = gcvNULL;
2140 /* Release the mutex queue. */
2141 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2142 acquired = gcvFALSE;
2144 /* Increase the number of free events. */
2145 gcmkONERROR(gckOS_AtomIncrement(Event->os, Event->freeAtom, &free));
2147 /* Walk all events for this interrupt. */
2148 while (record != gcvNULL)
2150 gcsEVENT_PTR recordNext;
2158 /* Grab next record. */
2159 recordNext = record->next;
2162 /* Assign record->processID as the pid for this galcore thread.
2163 * Used in OS calls like gckOS_UnlockMemory() which do not take a pid.
2165 drv_thread_specific_key_assign(record->processID, 0, Event->kernel->core);
2169 /* Get the cache that belongs to this process. */
2170 gcmkONERROR(gckKERNEL_GetProcessDBCache(Event->kernel,
2176 gcvLEVEL_INFO, gcvZONE_EVENT,
2177 gcmSIZEOF(record->info.command),
2178 "Processing event type: %d",
2179 record->info.command
2182 switch (record->info.command)
2184 case gcvHAL_FREE_NON_PAGED_MEMORY:
2185 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2186 "gcvHAL_FREE_NON_PAGED_MEMORY: 0x%x",
2187 gcmNAME_TO_PTR(record->info.u.FreeNonPagedMemory.physical));
2189 /* Free non-paged memory. */
2190 status = gckOS_FreeNonPagedMemory(
2192 (gctSIZE_T) record->info.u.FreeNonPagedMemory.bytes,
2193 gcmNAME_TO_PTR(record->info.u.FreeNonPagedMemory.physical),
2194 gcmUINT64_TO_PTR(record->info.u.FreeNonPagedMemory.logical));
2196 if (gcmIS_SUCCESS(status))
2199 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2202 gcmUINT64_TO_PTR(record->record.u.FreeNonPagedMemory.logical),
2203 (gctSIZE_T) record->record.u.FreeNonPagedMemory.bytes));
2206 gcmRELEASE_NAME(record->info.u.FreeNonPagedMemory.physical);
2209 case gcvHAL_FREE_CONTIGUOUS_MEMORY:
2211 gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2212 "gcvHAL_FREE_CONTIGUOUS_MEMORY: 0x%x",
2213 gcmNAME_TO_PTR(record->info.u.FreeContiguousMemory.physical));
2215 /* Unmap the user memory. */
2216 status = gckOS_FreeContiguous(
2218 gcmNAME_TO_PTR(record->info.u.FreeContiguousMemory.physical),
2219 gcmUINT64_TO_PTR(record->info.u.FreeContiguousMemory.logical),
2220 (gctSIZE_T) record->info.u.FreeContiguousMemory.bytes);
2222 if (gcmIS_SUCCESS(status))
2225 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2228 gcmUINT64_TO_PTR(record->record.u.FreeContiguousMemory.logical),
2229 (gctSIZE_T) record->record.u.FreeContiguousMemory.bytes));
2232 gcmRELEASE_NAME(record->info.u.FreeContiguousMemory.physical);
2235 case gcvHAL_FREE_VIDEO_MEMORY:
2236 node = gcmUINT64_TO_PTR(record->info.u.FreeVideoMemory.node);
2237 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2238 "gcvHAL_FREE_VIDEO_MEMORY: 0x%x",
2241 #if gcdUSE_VIDMEM_PER_PID
2242 /* Check if the VidMem object still exists. */
2243 if (gckKERNEL_GetVideoMemoryPoolPid(record->kernel,
2246 gcvNULL) == gcvSTATUS_NOT_FOUND)
2248 /*printf("Vidmem not found for process:%d\n", queue->processID);*/
2249 status = gcvSTATUS_OK;
2253 if ((node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
2254 && (node->VidMem.logical != gcvNULL)
2258 gckKERNEL_UnmapVideoMemory(record->kernel,
2259 node->VidMem.logical,
2261 node->VidMem.bytes));
2262 node->VidMem.logical = gcvNULL;
2267 /* Free video memory. */
2269 gckVIDMEM_Free(node);
2273 case gcvHAL_WRITE_DATA:
2275 /* Convert physical into logical address. */
2277 gckOS_MapPhysical(Event->os,
2278 record->info.u.WriteData.address,
2279 gcmSIZEOF(gctUINT32),
2284 gckOS_WriteMemory(Event->os,
2286 record->info.u.WriteData.data));
2288 /* Unmap the physical memory. */
2290 gckOS_UnmapPhysical(Event->os,
2292 gcmSIZEOF(gctUINT32)));
2296 gckOS_WriteMemory(Event->os,
2298 record->info.u.WriteData.address,
2299 record->info.u.WriteData.data));
2303 case gcvHAL_UNLOCK_VIDEO_MEMORY:
2304 node = gcmUINT64_TO_PTR(record->info.u.UnlockVideoMemory.node);
2306 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2307 "gcvHAL_UNLOCK_VIDEO_MEMORY: 0x%x",
2310 /* Save node information before it disappears. */
2312 if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
2319 logical = node->Virtual.logical;
2320 bytes = node->Virtual.bytes;
2325 status = gckVIDMEM_Unlock(
2328 record->info.u.UnlockVideoMemory.type,
2332 if (gcmIS_SUCCESS(status) && (logical != gcvNULL))
2334 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2344 signal = gcmUINT64_TO_PTR(record->info.u.Signal.signal);
2345 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2346 "gcvHAL_SIGNAL: 0x%x",
2350 if ((record->info.u.Signal.coid == 0)
2351 && (record->info.u.Signal.rcvid == 0)
2354 /* Kernel signal. */
2356 gckOS_Signal(Event->os,
2364 gckOS_UserSignal(Event->os,
2366 record->info.u.Signal.rcvid,
2367 record->info.u.Signal.coid));
2371 if (gcmUINT64_TO_PTR(record->info.u.Signal.process) == gcvNULL)
2373 /* Kernel signal. */
2375 gckOS_Signal(Event->os,
2383 gckOS_UserSignal(Event->os,
2385 gcmUINT64_TO_PTR(record->info.u.Signal.process)));
2388 gcmkASSERT(record->info.u.Signal.auxSignal == 0);
2392 case gcvHAL_UNMAP_USER_MEMORY:
2393 info = gcmNAME_TO_PTR(record->info.u.UnmapUserMemory.info);
2394 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2395 "gcvHAL_UNMAP_USER_MEMORY: 0x%x",
2398 /* Unmap the user memory. */
2399 status = gckOS_UnmapUserMemory(
2401 Event->kernel->core,
2402 gcmUINT64_TO_PTR(record->info.u.UnmapUserMemory.memory),
2403 (gctSIZE_T) record->info.u.UnmapUserMemory.size,
2405 record->info.u.UnmapUserMemory.address);
2408 if (gcmIS_SUCCESS(status))
2410 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2413 gcmUINT64_TO_PTR(record->info.u.UnmapUserMemory.memory),
2414 (gctSIZE_T) record->info.u.UnmapUserMemory.size));
2417 gcmRELEASE_NAME(record->info.u.UnmapUserMemory.info);
2420 case gcvHAL_TIMESTAMP:
2421 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2422 "gcvHAL_TIMESTAMP: %d %d",
2423 record->info.u.TimeStamp.timer,
2424 record->info.u.TimeStamp.request);
2426 /* Process the timestamp. */
2427 switch (record->info.u.TimeStamp.request)
2430 status = gckOS_GetTime(&Event->kernel->timers[
2431 record->info.u.TimeStamp.timer].
2436 status = gckOS_GetTime(&Event->kernel->timers[
2437 record->info.u.TimeStamp.timer].
2443 gcvLEVEL_ERROR, gcvZONE_EVENT,
2444 gcmSIZEOF(record->info.u.TimeStamp.request),
2445 "Invalid timestamp request: %d",
2446 record->info.u.TimeStamp.request
2449 status = gcvSTATUS_INVALID_ARGUMENT;
2454 #if gcdVIRTUAL_COMMAND_BUFFER
2455 case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
2457 gckKERNEL_DestroyVirtualCommandBuffer(Event->kernel,
2458 (gctSIZE_T) record->info.u.FreeVirtualCommandBuffer.bytes,
2459 gcmNAME_TO_PTR(record->info.u.FreeVirtualCommandBuffer.physical),
2460 gcmUINT64_TO_PTR(record->info.u.FreeVirtualCommandBuffer.logical)
2462 gcmRELEASE_NAME(record->info.u.FreeVirtualCommandBuffer.physical);
2466 case gcvHAL_COMMIT_DONE:
2470 /* Invalid argument. */
2472 gcvLEVEL_ERROR, gcvZONE_EVENT,
2473 gcmSIZEOF(record->info.command),
2474 "Unknown event type: %d",
2475 record->info.command
2478 status = gcvSTATUS_INVALID_ARGUMENT;
2482 /* Make sure there are no errors generated. */
2483 if (gcmIS_ERROR(status))
2486 gcvLEVEL_WARNING, gcvZONE_EVENT,
2488 "Event produced status: %d(%s)",
2489 status, gckOS_DebugStatus2Name(status));
2492 /* Free the event. */
2493 gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record));
2495 /* Advance to next record. */
2496 record = recordNext;
2499 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2500 "Handled interrupt 0x%x", mask);
2505 gcmkONERROR(_TryToIdleGPU(Event));
2510 return gcvSTATUS_OK;
2515 /* Release mutex. */
2516 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2522 /* Resume interrupts. */
2523 gcmkVERIFY_OK(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
2527 /* Return the status. */
2532 /*******************************************************************************
2533 ** gckEVENT_FreeProcess
2535 ** Free all events owned by a particular process ID.
2540 ** Pointer to an gckEVENT object.
2542 ** gctUINT32 ProcessID
2543 ** Process ID of the process to be freed up.
2550 gckEVENT_FreeProcess(
2552 IN gctUINT32 ProcessID
2556 gctBOOL acquired = gcvFALSE;
2557 gcsEVENT_PTR record, next;
2559 gcsEVENT_PTR deleteHead, deleteTail;
2561 gcmkHEADER_ARG("Event=0x%x ProcessID=%d", Event, ProcessID);
2563 /* Verify the arguments. */
2564 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
2566 /* Walk through all queues. */
2567 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
2569 if (Event->queues[i].head != gcvNULL)
2571 /* Grab the event queue mutex. */
2572 gcmkONERROR(gckOS_AcquireMutex(Event->os,
2573 Event->eventQueueMutex,
2577 /* Grab the mutex head. */
2578 record = Event->queues[i].head;
2579 Event->queues[i].head = gcvNULL;
2580 Event->queues[i].tail = gcvNULL;
2581 deleteHead = gcvNULL;
2582 deleteTail = gcvNULL;
2584 while (record != gcvNULL)
2586 next = record->next;
2587 if (record->processID == ProcessID)
2589 if (deleteHead == gcvNULL)
2591 deleteHead = record;
2595 deleteTail->next = record;
2598 deleteTail = record;
2602 if (Event->queues[i].head == gcvNULL)
2604 Event->queues[i].head = record;
2608 Event->queues[i].tail->next = record;
2611 Event->queues[i].tail = record;
2614 record->next = gcvNULL;
2618 /* Release the mutex queue. */
2619 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2620 acquired = gcvFALSE;
2622 /* Loop through the entire list of events. */
2623 for (record = deleteHead; record != gcvNULL; record = next)
2625 /* Get the next event record. */
2626 next = record->next;
2628 /* Free the event record. */
2629 gcmkONERROR(gckEVENT_FreeRecord(Event, record));
2634 gcmkONERROR(_TryToIdleGPU(Event));
2638 return gcvSTATUS_OK;
2641 /* Release the event queue mutex. */
2644 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2647 /* Return the status. */
2652 /*******************************************************************************
2655 ** Stop the hardware using the End event mechanism.
2660 ** Pointer to an gckEVENT object.
2662 ** gctUINT32 ProcessID
2663 ** Process ID Logical belongs.
2665 ** gctPHYS_ADDR Handle
2666 ** Physical address handle. If gcvNULL it is video memory.
2668 ** gctPOINTER Logical
2669 ** Logical address to flush.
2672 ** Pointer to the signal to trigger.
2681 IN gctUINT32 ProcessID,
2682 IN gctPHYS_ADDR Handle,
2683 IN gctPOINTER Logical,
2684 IN gctSIGNAL Signal,
2685 IN OUT gctSIZE_T * waitSize
2689 /* gctSIZE_T waitSize;*/
2690 gcsEVENT_PTR record;
2693 gcmkHEADER_ARG("Event=0x%x ProcessID=%u Handle=0x%x Logical=0x%x "
2695 Event, ProcessID, Handle, Logical, Signal);
2697 /* Verify the arguments. */
2698 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
2700 /* Submit the current event queue. */
2701 gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE));
2703 gcmkONERROR(gckEVENT_GetEvent(Event, gcvTRUE, &id, gcvKERNEL_PIXEL));
2705 /* Allocate a record. */
2706 gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &record));
2708 /* Initialize the record. */
2709 record->next = gcvNULL;
2710 record->processID = ProcessID;
2711 record->info.command = gcvHAL_SIGNAL;
2712 record->info.u.Signal.signal = gcmPTR_TO_UINT64(Signal);
2714 record->info.u.Signal.coid = 0;
2715 record->info.u.Signal.rcvid = 0;
2717 record->info.u.Signal.auxSignal = 0;
2718 record->info.u.Signal.process = 0;
2720 /* Append the record. */
2721 Event->queues[id].head = record;
2723 /* Replace last WAIT with END. */
2724 gcmkONERROR(gckHARDWARE_End(
2725 Event->kernel->hardware, Logical, waitSize
2728 #if gcdNONPAGED_MEMORY_CACHEABLE
2729 /* Flush the cache for the END. */
2730 gcmkONERROR(gckOS_CacheClean(
2740 /* Wait for the signal. */
2741 gcmkONERROR(gckOS_WaitSignal(Event->os, Signal, gcvINFINITE));
2745 return gcvSTATUS_OK;
2749 /* Return the status. */
2759 switch (record->info.command)
2761 case gcvHAL_FREE_NON_PAGED_MEMORY:
2762 gcmkPRINT(" gcvHAL_FREE_NON_PAGED_MEMORY");
2765 case gcvHAL_FREE_CONTIGUOUS_MEMORY:
2766 gcmkPRINT(" gcvHAL_FREE_CONTIGUOUS_MEMORY");
2769 case gcvHAL_FREE_VIDEO_MEMORY:
2770 gcmkPRINT(" gcvHAL_FREE_VIDEO_MEMORY");
2773 case gcvHAL_WRITE_DATA:
2774 gcmkPRINT(" gcvHAL_WRITE_DATA");
2777 case gcvHAL_UNLOCK_VIDEO_MEMORY:
2778 gcmkPRINT(" gcvHAL_UNLOCK_VIDEO_MEMORY");
2782 gcmkPRINT(" gcvHAL_SIGNAL process=%d signal=0x%x",
2783 record->info.u.Signal.process,
2784 record->info.u.Signal.signal);
2787 case gcvHAL_UNMAP_USER_MEMORY:
2788 gcmkPRINT(" gcvHAL_UNMAP_USER_MEMORY");
2791 case gcvHAL_TIMESTAMP:
2792 gcmkPRINT(" gcvHAL_TIMESTAMP");
2795 case gcvHAL_COMMIT_DONE:
2796 gcmkPRINT(" gcvHAL_COMMIT_DONE");
2799 case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
2800 gcmkPRINT(" gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER logical=0x%08x",
2801 record->info.u.FreeVirtualCommandBuffer.logical);
2805 gcmkPRINT(" Illegal Event %d", record->info.command);
2810 /*******************************************************************************
2813 ** Dump record in event queue when stuck happens.
2814 ** No protection for the event queue.
2821 gcsEVENT_QUEUE_PTR queueHead = Event->queueHead;
2822 gcsEVENT_QUEUE_PTR queue;
2823 gcsEVENT_PTR record = gcvNULL;
2826 gcmkHEADER_ARG("Event=0x%x", Event);
2828 gcmkPRINT("**************************\n");
2829 gcmkPRINT("*** EVENT STATE DUMP ***\n");
2830 gcmkPRINT("**************************\n");
2833 gcmkPRINT(" Unsumbitted Event:");
2837 record = queueHead->head;
2839 gcmkPRINT(" [%x]:", queue);
2842 _PrintRecord(record);
2843 record = record->next;
2846 if (queueHead == Event->queueTail)
2848 queueHead = gcvNULL;
2852 queueHead = queueHead->next;
2856 gcmkPRINT(" Untriggered Event:");
2857 for (i = 0; i < 30; i++)
2859 queue = &Event->queues[i];
2860 record = queue->head;
2862 gcmkPRINT(" [%d]:", i);
2865 _PrintRecord(record);
2866 record = record->next;
2871 return gcvSTATUS_OK;