ENGR00156850 gpu-viv: add gpu-viv driver source
[wandboard.git] / drivers / mxc / gpu-viv / hal / kernel / gc_hal_kernel_event.c
blobe9050f1ad7f650f2da3f7413815cb53c5d485236
1 /****************************************************************************
3 * Copyright (C) 2005 - 2011 by Vivante Corp.
4 * Copyright (C) 2011 Freescale Semiconductor, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the license, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *****************************************************************************/
25 #include "gc_hal_kernel_precomp.h"
26 #include "gc_hal_kernel_buffer.h"
28 #ifdef __QNXNTO__
29 #include <atomic.h>
30 #include "gc_hal_kernel_qnx.h"
31 #endif
33 #ifdef LINUX
34 #include <asm/atomic.h>
35 #endif
37 #define _GC_OBJ_ZONE gcvZONE_EVENT
39 #define gcdEVENT_ALLOCATION_COUNT (4096 / gcmSIZEOF(gcsHAL_INTERFACE))
40 #define gcdEVENT_MIN_THRESHOLD 4
42 /******************************************************************************\
43 ********************************* Support Code *********************************
44 \******************************************************************************/
46 static gceSTATUS
47 gckEVENT_AllocateQueue(
48 IN gckEVENT Event,
49 OUT gcsEVENT_QUEUE_PTR * Queue
52 gceSTATUS status;
54 gcmkHEADER_ARG("Event=0x%x", Event);
56 /* Verify the arguments. */
57 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
58 gcmkVERIFY_ARGUMENT(Queue != gcvNULL);
60 /* Do we have free queues? */
61 if (Event->freeList == gcvNULL)
63 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
66 /* Move one free queue from the free list. */
67 * Queue = Event->freeList;
68 Event->freeList = Event->freeList->next;
70 /* Success. */
71 gcmkFOOTER_ARG("*Queue=0x%x", gcmOPT_POINTER(Queue));
72 return gcvSTATUS_OK;
74 OnError:
75 /* Return the status. */
76 gcmkFOOTER();
77 return status;
80 static gceSTATUS
81 gckEVENT_FreeQueue(
82 IN gckEVENT Event,
83 OUT gcsEVENT_QUEUE_PTR Queue
86 gceSTATUS status = gcvSTATUS_OK;
88 gcmkHEADER_ARG("Event=0x%x", Event);
90 /* Verify the arguments. */
91 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
92 gcmkVERIFY_ARGUMENT(Queue != gcvNULL);
94 /* Move one free queue from the free list. */
95 Queue->next = Event->freeList;
96 Event->freeList = Queue;
98 /* Success. */
99 gcmkFOOTER();
100 return status;
103 static gceSTATUS
104 gckEVENT_FreeRecord(
105 IN gckEVENT Event,
106 IN gcsEVENT_PTR Record
109 gceSTATUS status;
110 gctBOOL acquired = gcvFALSE;
112 gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
114 /* Verify the arguments. */
115 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
116 gcmkVERIFY_ARGUMENT(Record != gcvNULL);
118 /* Acquire the mutex. */
119 gcmkONERROR(gckOS_AcquireMutex(Event->os,
120 Event->freeEventMutex,
121 gcvINFINITE));
122 acquired = gcvTRUE;
124 /* Push the record on the free list. */
125 Record->next = Event->freeEventList;
126 Event->freeEventList = Record;
127 Event->freeEventCount += 1;
129 /* Release the mutex. */
130 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
132 /* Success. */
133 gcmkFOOTER_NO();
134 return gcvSTATUS_OK;
136 OnError:
137 /* Roll back. */
138 if (acquired)
140 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
143 /* Return the status. */
144 gcmkFOOTER();
145 return gcvSTATUS_OK;
148 #ifndef __QNXNTO__
150 static gceSTATUS
151 gckEVENT_IsEmpty(
152 IN gckEVENT Event,
153 OUT gctBOOL_PTR IsEmpty
156 gceSTATUS status;
157 gctSIZE_T i;
159 gcmkHEADER_ARG("Event=0x%x", Event);
161 /* Verify the arguments. */
162 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
163 gcmkVERIFY_ARGUMENT(IsEmpty != gcvNULL);
165 /* Assume the event queue is empty. */
166 *IsEmpty = gcvTRUE;
168 /* Walk the event queue. */
169 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
171 /* Check whether this event is in use. */
172 if (Event->queues[i].head != gcvNULL)
174 /* The event is in use, hence the queue is not empty. */
175 *IsEmpty = gcvFALSE;
176 break;
180 /* Try acquiring the mutex. */
181 status = gckOS_AcquireMutex(Event->os, Event->eventQueueMutex, 0);
182 if (status == gcvSTATUS_TIMEOUT)
184 /* Timeout - queue is no longer empty. */
185 *IsEmpty = gcvFALSE;
187 else
189 /* Bail out on error. */
190 gcmkONERROR(status);
192 /* Release the mutex. */
193 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
196 /* Success. */
197 gcmkFOOTER_ARG("*IsEmpty=%d", gcmOPT_VALUE(IsEmpty));
198 return gcvSTATUS_OK;
200 OnError:
201 /* Return the status. */
202 gcmkFOOTER();
203 return status;
206 #endif
208 static gceSTATUS
209 __RemoveRecordFromProcessDB(
210 IN gckEVENT Event,
211 IN gcsEVENT_PTR Record
214 gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
215 gcmkVERIFY_ARGUMENT(Record != gcvNULL);
217 while (Record != gcvNULL)
219 switch (Record->info.command)
221 case gcvHAL_FREE_NON_PAGED_MEMORY:
222 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
223 Event->kernel,
224 Record->processID,
225 gcvDB_NON_PAGED,
226 Record->info.u.FreeNonPagedMemory.logical));
227 break;
229 case gcvHAL_FREE_CONTIGUOUS_MEMORY:
230 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
231 Event->kernel,
232 Record->processID,
233 gcvDB_CONTIGUOUS,
234 Record->info.u.FreeContiguousMemory.logical));
235 break;
237 case gcvHAL_FREE_VIDEO_MEMORY:
238 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
239 Event->kernel,
240 Record->processID,
241 gcvDB_VIDEO_MEMORY,
242 Record->info.u.FreeVideoMemory.node));
243 break;
245 case gcvHAL_UNLOCK_VIDEO_MEMORY:
246 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
247 Event->kernel,
248 Record->processID,
249 gcvDB_VIDEO_MEMORY_LOCKED,
250 Record->info.u.UnlockVideoMemory.node));
251 break;
253 default:
254 break;
257 Record = Record->next;
259 gcmkFOOTER_NO();
260 return gcvSTATUS_OK;
263 static gceSTATUS
264 _IsEmpty(
265 IN gckEVENT Event,
266 OUT gctBOOL_PTR IsEmpty
269 gceSTATUS status;
270 gctSIZE_T i;
272 gcmkHEADER_ARG("Event=0x%x", Event);
274 /* Verify the arguments. */
275 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
276 gcmkVERIFY_ARGUMENT(IsEmpty != gcvNULL);
278 /* Assume the event queue is empty. */
279 *IsEmpty = gcvTRUE;
281 /* Walk the event queue. */
282 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
284 /* Check whether this event is in use. */
285 if (Event->queues[i].head != gcvNULL)
287 /* The event is in use, hence the queue is not empty. */
288 *IsEmpty = gcvFALSE;
289 break;
293 /* Try acquiring the mutex. */
294 status = gckOS_AcquireMutex(Event->os, Event->eventQueueMutex, 0);
295 if (status == gcvSTATUS_TIMEOUT)
297 /* Timeout - queue is no longer empty. */
298 *IsEmpty = gcvFALSE;
300 else
302 /* Bail out on error. */
303 gcmkONERROR(status);
305 /* Release the mutex. */
306 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
309 /* Success. */
310 gcmkFOOTER_ARG("*IsEmpty=%d", gcmOPT_VALUE(IsEmpty));
311 return gcvSTATUS_OK;
313 OnError:
314 /* Return the status. */
315 gcmkFOOTER();
316 return status;
319 /******************************************************************************\
320 ******************************* gckEVENT API Code *******************************
321 \******************************************************************************/
323 /*******************************************************************************
325 ** gckEVENT_Construct
327 ** Construct a new gckEVENT object.
329 ** INPUT:
331 ** gckKERNEL Kernel
332 ** Pointer to an gckKERNEL object.
334 ** OUTPUT:
336 ** gckEVENT * Event
337 ** Pointer to a variable that receives the gckEVENT object pointer.
339 gceSTATUS
340 gckEVENT_Construct(
341 IN gckKERNEL Kernel,
342 OUT gckEVENT * Event
345 gckOS os;
346 gceSTATUS status;
347 gckEVENT eventObj = gcvNULL;
348 int i;
349 gcsEVENT_PTR record;
350 gctPOINTER pointer = gcvNULL;
352 gcmkHEADER_ARG("Kernel=0x%x", Kernel);
354 /* Verify the arguments. */
355 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
356 gcmkVERIFY_ARGUMENT(Event != gcvNULL);
358 /* Extract the pointer to the gckOS object. */
359 os = Kernel->os;
360 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
362 /* Allocate the gckEVENT object. */
363 gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckEVENT), &pointer));
365 eventObj = pointer;
367 /* Reset the object. */
368 gcmkVERIFY_OK(gckOS_ZeroMemory(eventObj, gcmSIZEOF(struct _gckEVENT)));
370 /* Initialize the gckEVENT object. */
371 eventObj->object.type = gcvOBJ_EVENT;
372 eventObj->kernel = Kernel;
373 eventObj->os = os;
375 /* Create the mutexes. */
376 gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventQueueMutex));
377 gcmkONERROR(gckOS_CreateMutex(os, &eventObj->freeEventMutex));
378 gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventListMutex));
380 /* Create a bunch of event reccords. */
381 for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1)
383 /* Allocate an event record. */
384 gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsEVENT), &pointer));
386 record = pointer;
388 /* Push it on the free list. */
389 record->next = eventObj->freeEventList;
390 eventObj->freeEventList = record;
391 eventObj->freeEventCount += 1;
394 /* Initialize the free list of event queues. */
395 for (i = 0; i < gcdREPO_LIST_COUNT; i += 1)
397 eventObj->repoList[i].next = eventObj->freeList;
398 eventObj->freeList = &eventObj->repoList[i];
401 /* Construct the atom. */
402 gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->freeAtom));
403 gcmkONERROR(gckOS_AtomSet(os,
404 eventObj->freeAtom,
405 gcmCOUNTOF(eventObj->queues)));
407 /* Return pointer to the gckEVENT object. */
408 *Event = eventObj;
410 /* Success. */
411 gcmkFOOTER_ARG("*Event=0x%x", *Event);
412 return gcvSTATUS_OK;
414 OnError:
415 /* Roll back. */
416 if (eventObj != gcvNULL)
418 if (eventObj->eventQueueMutex != gcvNULL)
420 gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventQueueMutex));
423 if (eventObj->freeEventMutex != gcvNULL)
425 gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->freeEventMutex));
428 if (eventObj->eventListMutex != gcvNULL)
430 gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventListMutex));
433 while (eventObj->freeEventList != gcvNULL)
435 record = eventObj->freeEventList;
436 eventObj->freeEventList = record->next;
438 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, record));
441 if (eventObj->freeAtom != gcvNULL)
443 gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->freeAtom));
446 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, eventObj));
449 /* Return the status. */
450 gcmkFOOTER();
451 return status;
454 /*******************************************************************************
456 ** gckEVENT_Destroy
458 ** Destroy an gckEVENT object.
460 ** INPUT:
462 ** gckEVENT Event
463 ** Pointer to an gckEVENT object.
465 ** OUTPUT:
467 ** Nothing.
469 gceSTATUS
470 gckEVENT_Destroy(
471 IN gckEVENT Event
474 gcsEVENT_PTR record;
475 gcsEVENT_QUEUE_PTR queue;
477 gcmkHEADER_ARG("Event=0x%x", Event);
479 /* Verify the arguments. */
480 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
482 /* Delete the queue mutex. */
483 gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventQueueMutex));
485 /* Free all free events. */
486 while (Event->freeEventList != gcvNULL)
488 record = Event->freeEventList;
489 Event->freeEventList = record->next;
491 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record));
494 /* Delete the free mutex. */
495 gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->freeEventMutex));
497 /* Free all pending queues. */
498 while (Event->queueHead != gcvNULL)
500 /* Get the current queue. */
501 queue = Event->queueHead;
503 /* Free all pending events. */
504 while (queue->head != gcvNULL)
506 record = queue->head;
507 queue->head = record->next;
509 gcmkTRACE_ZONE_N(
510 gcvLEVEL_WARNING, gcvZONE_EVENT,
511 gcmSIZEOF(record) + gcmSIZEOF(queue->source),
512 "Event record 0x%x is still pending for %d.",
513 record, queue->source
516 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record));
519 /* Remove the top queue from the list. */
520 if (Event->queueHead == Event->queueTail)
522 Event->queueHead =
523 Event->queueTail = gcvNULL;
525 else
527 Event->queueHead = Event->queueHead->next;
530 /* Free the queue. */
531 gcmkVERIFY_OK(gckEVENT_FreeQueue(Event, queue));
534 /* Delete the list mutex. */
535 gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventListMutex));
537 /* Delete the atom. */
538 gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->freeAtom));
540 /* Mark the gckEVENT object as unknown. */
541 Event->object.type = gcvOBJ_UNKNOWN;
543 /* Free the gckEVENT object. */
544 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, Event));
546 /* Success. */
547 gcmkFOOTER_NO();
548 return gcvSTATUS_OK;
551 /*******************************************************************************
553 ** gckEVENT_GetEvent
555 ** Reserve the next available hardware event.
557 ** INPUT:
559 ** gckEVENT Event
560 ** Pointer to an gckEVENT object.
562 ** gctBOOL Wait
563 ** Set to gcvTRUE to force the function to wait if no events are
564 ** immediately available.
566 ** gceKERNEL_WHERE Source
567 ** Source of the event.
569 ** OUTPUT:
571 ** gctUINT8 * EventID
572 ** Reserved event ID.
574 gceSTATUS
575 gckEVENT_GetEvent(
576 IN gckEVENT Event,
577 IN gctBOOL Wait,
578 OUT gctUINT8 * EventID,
579 IN gceKERNEL_WHERE Source
582 gctINT i, id;
583 gceSTATUS status;
584 gctBOOL acquired = gcvFALSE;
585 gctBOOL suspended = gcvFALSE;
586 gctINT32 free;
588 #if gcdGPU_TIMEOUT
589 gctUINT32 timer = 0;
590 #endif
592 gcmkHEADER_ARG("Event=0x%x Source=%d", Event, Source);
594 while (gcvTRUE)
596 /* Grab the queue mutex. */
597 gcmkONERROR(gckOS_AcquireMutex(Event->os,
598 Event->eventQueueMutex,
599 gcvINFINITE));
600 acquired = gcvTRUE;
602 /* Walk through all events. */
603 id = Event->lastID;
604 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
606 gctINT nextID = gckMATH_ModuloInt((id + 1),
607 gcmCOUNTOF(Event->queues));
609 if (Event->queues[id].head == gcvNULL)
611 *EventID = (gctUINT8) id;
613 Event->lastID = (gctUINT8) nextID;
615 /* Save time stamp of event. */
616 Event->queues[id].stamp = ++(Event->stamp);
617 Event->queues[id].source = Source;
619 gcmkONERROR(gckOS_AtomDecrement(Event->os,
620 Event->freeAtom,
621 &free));
622 #if gcdDYNAMIC_SPEED
623 if (free <= gcdDYNAMIC_EVENT_THRESHOLD)
625 gcmkONERROR(gckOS_BroadcastHurry(
626 Event->os,
627 Event->kernel->hardware,
628 gcdDYNAMIC_EVENT_THRESHOLD - free));
630 #endif
632 /* Release the queue mutex. */
633 gcmkONERROR(gckOS_ReleaseMutex(Event->os,
634 Event->eventQueueMutex));
636 /* Success. */
637 gcmkTRACE_ZONE_N(
638 gcvLEVEL_INFO, gcvZONE_EVENT,
639 gcmSIZEOF(id),
640 "Using id=%d",
644 gcmkFOOTER_ARG("*EventID=%u", *EventID);
645 return gcvSTATUS_OK;
648 id = nextID;
651 #if gcdDYNAMIC_SPEED
652 /* No free events, speed up the GPU right now! */
653 gcmkONERROR(gckOS_BroadcastHurry(Event->os,
654 Event->kernel->hardware,
655 gcdDYNAMIC_EVENT_THRESHOLD));
656 #endif
658 /* Release the queue mutex. */
659 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
660 acquired = gcvFALSE;
662 /* Fail if wait is not requested. */
663 if (!Wait)
665 /* Out of resources. */
666 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
669 /* Delay a while. */
670 gcmkONERROR(gckOS_Delay(Event->os, 1));
672 #if gcdGPU_TIMEOUT
673 /* Increment the wait timer. */
674 timer += 1;
676 if (timer == gcdGPU_TIMEOUT)
678 /* Suspend interrupts. */
679 gcmkONERROR(gckOS_SuspendInterrupt(Event->os));
680 suspended = gcvTRUE;
682 /* Try to call any outstanding events. */
683 gcmkONERROR(gckHARDWARE_Interrupt(Event->kernel->hardware,
684 gcvTRUE));
686 /* Resume interrupts. */
687 gcmkONERROR(gckOS_ResumeInterrupt(Event->os));
688 suspended = gcvFALSE;
691 else if (timer > gcdGPU_TIMEOUT)
693 gcmkTRACE_N(
694 gcvLEVEL_ERROR,
695 gcmSIZEOF(gctCONST_STRING) + gcmSIZEOF(gctINT),
696 "%s(%d): no available events\n",
697 __FUNCTION__, __LINE__
700 /* Broadcast GPU stuck. */
701 gcmkONERROR(gckOS_Broadcast(Event->os,
702 Event->kernel->hardware,
703 gcvBROADCAST_GPU_STUCK));
705 /* Bail out. */
706 gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING);
708 #endif
711 OnError:
712 if (acquired)
714 /* Release the queue mutex. */
715 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
718 if (suspended)
720 /* Resume interrupts. */
721 gcmkVERIFY_OK(gckOS_ResumeInterrupt(Event->os));
724 /* Return the status. */
725 gcmkFOOTER();
726 return status;
729 /*******************************************************************************
731 ** gckEVENT_AllocateRecord
733 ** Allocate a record for the new event.
735 ** INPUT:
737 ** gckEVENT Event
738 ** Pointer to an gckEVENT object.
740 ** gctBOOL AllocateAllowed
741 ** State for allocation if out of free events.
743 ** OUTPUT:
745 ** gcsEVENT_PTR * Record
746 ** Allocated event record.
748 gceSTATUS
749 gckEVENT_AllocateRecord(
750 IN gckEVENT Event,
751 IN gctBOOL AllocateAllowed,
752 OUT gcsEVENT_PTR * Record
755 gceSTATUS status;
756 gctBOOL acquired = gcvFALSE;
757 gctINT i;
758 gcsEVENT_PTR record;
759 gctPOINTER pointer = gcvNULL;
761 gcmkHEADER_ARG("Event=0x%x AllocateAllowed=%d", Event, AllocateAllowed);
763 /* Verify the arguments. */
764 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
765 gcmkVERIFY_ARGUMENT(Record != gcvNULL);
767 /* Test if we are below the allocation threshold. */
768 if (AllocateAllowed && (Event->freeEventCount < gcdEVENT_MIN_THRESHOLD))
770 /* Allocate a bunch of records. */
771 for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1)
773 /* Allocate an event record. */
774 gcmkONERROR(gckOS_Allocate(Event->os,
775 gcmSIZEOF(gcsEVENT),
776 &pointer));
778 record = pointer;
780 /* Acquire the mutex. */
781 gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->freeEventMutex, gcvINFINITE));
782 acquired = gcvTRUE;
784 /* Push it on the free list. */
785 record->next = Event->freeEventList;
786 Event->freeEventList = record;
787 Event->freeEventCount += 1;
789 /* Release the mutex. */
790 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
791 acquired = gcvFALSE;
795 /* Acquire the mutex. */
796 gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->freeEventMutex, gcvINFINITE));
797 acquired = gcvTRUE;
799 *Record = Event->freeEventList;
800 Event->freeEventList = Event->freeEventList->next;
801 Event->freeEventCount -= 1;
803 /* Release the mutex. */
804 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
805 acquired = gcvFALSE;
807 /* Success. */
808 gcmkFOOTER_ARG("*Record=0x%x", gcmOPT_POINTER(Record));
809 return gcvSTATUS_OK;
811 OnError:
812 /* Roll back. */
813 if (acquired)
815 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
818 /* Return the status. */
819 gcmkFOOTER();
820 return status;
823 /*******************************************************************************
825 ** gckEVENT_AddList
827 ** Add a new event to the list of events.
829 ** INPUT:
831 ** gckEVENT Event
832 ** Pointer to an gckEVENT object.
834 ** gcsHAL_INTERFACE_PTR Interface
835 ** Pointer to the interface for the event to be added.
837 ** gceKERNEL_WHERE FromWhere
838 ** Place in the pipe where the event needs to be generated.
840 ** gctBOOL AllocateAllowed
841 ** State for allocation if out of free events.
843 ** OUTPUT:
845 ** Nothing.
847 gceSTATUS
848 gckEVENT_AddList(
849 IN gckEVENT Event,
850 IN gcsHAL_INTERFACE_PTR Interface,
851 IN gceKERNEL_WHERE FromWhere,
852 IN gctBOOL AllocateAllowed
855 gceSTATUS status;
856 gctBOOL acquired = gcvFALSE;
857 gcsEVENT_PTR record = gcvNULL;
858 gcsEVENT_QUEUE_PTR queue;
860 gcmkHEADER_ARG("Event=0x%x Interface=0x%x FromWhere=%d AllocateAllowed=%d",
861 Event, Interface, FromWhere, AllocateAllowed);
863 /* Verify the arguments. */
864 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
865 gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
867 /* Verify the event command. */
868 gcmkASSERT
869 ( (Interface->command == gcvHAL_FREE_NON_PAGED_MEMORY)
870 || (Interface->command == gcvHAL_FREE_CONTIGUOUS_MEMORY)
871 || (Interface->command == gcvHAL_FREE_VIDEO_MEMORY)
872 || (Interface->command == gcvHAL_WRITE_DATA)
873 || (Interface->command == gcvHAL_UNLOCK_VIDEO_MEMORY)
874 || (Interface->command == gcvHAL_SIGNAL)
875 || (Interface->command == gcvHAL_UNMAP_USER_MEMORY)
876 || (Interface->command == gcvHAL_TIMESTAMP)
879 /* Validate the source. */
880 if ((FromWhere != gcvKERNEL_COMMAND) && (FromWhere != gcvKERNEL_PIXEL))
882 /* Invalid argument. */
883 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
886 /* Allocate a free record. */
887 gcmkONERROR(gckEVENT_AllocateRecord(Event, AllocateAllowed, &record));
889 /* Termninate the record. */
890 record->next = gcvNULL;
892 /* Copy the event interface into the record. */
893 gcmkONERROR(gckOS_MemCopy(&record->info, Interface, gcmSIZEOF(record->info)));
895 /* Get process ID. */
896 gcmkONERROR(gckOS_GetProcessID(&record->processID));
898 #ifdef __QNXNTO__
899 record->kernel = Event->kernel;
900 #endif
902 /* Acquire the mutex. */
903 gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->eventListMutex, gcvINFINITE));
904 acquired = gcvTRUE;
906 /* Do we need to allocate a new queue? */
907 if ((Event->queueTail == gcvNULL) || (Event->queueTail->source != FromWhere))
909 /* Allocate a new queue. */
910 gcmkONERROR(gckEVENT_AllocateQueue(Event, &queue));
912 /* Initialize the queue. */
913 queue->source = FromWhere;
914 queue->head = gcvNULL;
915 queue->next = gcvNULL;
917 /* Attach it to the list of alloicated queues. */
918 if (Event->queueTail == gcvNULL)
920 Event->queueHead =
921 Event->queueTail = queue;
923 else
925 Event->queueTail->next = queue;
926 Event->queueTail = queue;
929 else
931 queue = Event->queueTail;
934 /* Attach the record to the queue. */
935 if (queue->head == gcvNULL)
937 queue->head = record;
938 queue->tail = record;
940 else
942 queue->tail->next = record;
943 queue->tail = record;
946 /* Release the mutex. */
947 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
949 /* Success. */
950 gcmkFOOTER_NO();
951 return gcvSTATUS_OK;
953 OnError:
954 /* Roll back. */
955 if (acquired)
957 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
960 if (record != gcvNULL)
962 gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record));
965 /* Return the status. */
966 gcmkFOOTER();
967 return status;
970 /*******************************************************************************
972 ** gckEVENT_Unlock
974 ** Schedule an event to unlock virtual memory.
976 ** INPUT:
978 ** gckEVENT Event
979 ** Pointer to an gckEVENT object.
981 ** gceKERNEL_WHERE FromWhere
982 ** Place in the pipe where the event needs to be generated.
984 ** gcuVIDMEM_NODE_PTR Node
985 ** Pointer to a gcuVIDMEM_NODE union that specifies the virtual memory
986 ** to unlock.
988 ** gceSURF_TYPE Type
989 ** Type of surface to unlock.
991 ** OUTPUT:
993 ** Nothing.
995 gceSTATUS
996 gckEVENT_Unlock(
997 IN gckEVENT Event,
998 IN gceKERNEL_WHERE FromWhere,
999 IN gcuVIDMEM_NODE_PTR Node,
1000 IN gceSURF_TYPE Type
1003 gceSTATUS status;
1004 gcsHAL_INTERFACE iface;
1006 gcmkHEADER_ARG("Event=0x%x FromWhere=%d Node=0x%x Type=%d",
1007 Event, FromWhere, Node, Type);
1009 /* Verify the arguments. */
1010 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1011 gcmkVERIFY_ARGUMENT(Node != gcvNULL);
1013 /* Mark the event as an unlock. */
1014 iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY;
1015 iface.u.UnlockVideoMemory.node = Node;
1016 iface.u.UnlockVideoMemory.type = Type;
1017 iface.u.UnlockVideoMemory.asynchroneous = 0;
1019 /* Append it to the queue. */
1020 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE));
1022 /* Success. */
1023 gcmkFOOTER_NO();
1024 return gcvSTATUS_OK;
1026 OnError:
1027 /* Return the status. */
1028 gcmkFOOTER();
1029 return status;
1032 /*******************************************************************************
1034 ** gckEVENT_FreeVideoMemory
1036 ** Schedule an event to free video memory.
1038 ** INPUT:
1040 ** gckEVENT Event
1041 ** Pointer to an gckEVENT object.
1043 ** gcuVIDMEM_NODE_PTR VideoMemory
1044 ** Pointer to a gcuVIDMEM_NODE object to free.
1046 ** gceKERNEL_WHERE FromWhere
1047 ** Place in the pipe where the event needs to be generated.
1049 ** OUTPUT:
1051 ** Nothing.
1053 gceSTATUS
1054 gckEVENT_FreeVideoMemory(
1055 IN gckEVENT Event,
1056 IN gcuVIDMEM_NODE_PTR VideoMemory,
1057 IN gceKERNEL_WHERE FromWhere
1060 gceSTATUS status;
1061 gcsHAL_INTERFACE iface;
1063 gcmkHEADER_ARG("Event=0x%x VideoMemory=0x%x FromWhere=%d",
1064 Event, VideoMemory, FromWhere);
1066 /* Verify the arguments. */
1067 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1068 gcmkVERIFY_ARGUMENT(VideoMemory != gcvNULL);
1070 /* Create an event. */
1071 iface.command = gcvHAL_FREE_VIDEO_MEMORY;
1072 iface.u.FreeVideoMemory.node = VideoMemory;
1074 /* Append it to the queue. */
1075 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE));
1077 /* Success. */
1078 gcmkFOOTER_NO();
1079 return gcvSTATUS_OK;
1081 OnError:
1082 /* Return the status. */
1083 gcmkFOOTER();
1084 return status;
1087 /*******************************************************************************
1089 ** gckEVENT_FreeNonPagedMemory
1091 ** Schedule an event to free non-paged memory.
1093 ** INPUT:
1095 ** gckEVENT Event
1096 ** Pointer to an gckEVENT object.
1098 ** gctSIZE_T Bytes
1099 ** Number of bytes of non-paged memory to free.
1101 ** gctPHYS_ADDR Physical
1102 ** Physical address of non-paged memory to free.
1104 ** gctPOINTER Logical
1105 ** Logical address of non-paged memory to free.
1107 ** gceKERNEL_WHERE FromWhere
1108 ** Place in the pipe where the event needs to be generated.
1110 gceSTATUS
1111 gckEVENT_FreeNonPagedMemory(
1112 IN gckEVENT Event,
1113 IN gctSIZE_T Bytes,
1114 IN gctPHYS_ADDR Physical,
1115 IN gctPOINTER Logical,
1116 IN gceKERNEL_WHERE FromWhere
1119 gceSTATUS status;
1120 gcsHAL_INTERFACE iface;
1122 gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
1123 "FromWhere=%d",
1124 Event, Bytes, Physical, Logical, FromWhere);
1126 /* Verify the arguments. */
1127 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1128 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
1129 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1130 gcmkVERIFY_ARGUMENT(Bytes > 0);
1132 /* Create an event. */
1133 iface.command = gcvHAL_FREE_NON_PAGED_MEMORY;
1134 iface.u.FreeNonPagedMemory.bytes = Bytes;
1135 iface.u.FreeNonPagedMemory.physical = Physical;
1136 iface.u.FreeNonPagedMemory.logical = Logical;
1138 /* Append it to the queue. */
1139 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE));
1141 /* Success. */
1142 gcmkFOOTER_NO();
1143 return gcvSTATUS_OK;
1145 OnError:
1146 /* Return the status. */
1147 gcmkFOOTER();
1148 return status;
1151 /*******************************************************************************
1153 ** gckEVENT_FreeContigiuousMemory
1155 ** Schedule an event to free contiguous memory.
1157 ** INPUT:
1159 ** gckEVENT Event
1160 ** Pointer to an gckEVENT object.
1162 ** gctSIZE_T Bytes
1163 ** Number of bytes of contiguous memory to free.
1165 ** gctPHYS_ADDR Physical
1166 ** Physical address of contiguous memory to free.
1168 ** gctPOINTER Logical
1169 ** Logical address of contiguous memory to free.
1171 ** gceKERNEL_WHERE FromWhere
1172 ** Place in the pipe where the event needs to be generated.
1174 gceSTATUS
1175 gckEVENT_FreeContiguousMemory(
1176 IN gckEVENT Event,
1177 IN gctSIZE_T Bytes,
1178 IN gctPHYS_ADDR Physical,
1179 IN gctPOINTER Logical,
1180 IN gceKERNEL_WHERE FromWhere
1183 gceSTATUS status;
1184 gcsHAL_INTERFACE iface;
1186 gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
1187 "FromWhere=%d",
1188 Event, Bytes, Physical, Logical, FromWhere);
1190 /* Verify the arguments. */
1191 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1192 gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
1193 gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
1194 gcmkVERIFY_ARGUMENT(Bytes > 0);
1196 /* Create an event. */
1197 iface.command = gcvHAL_FREE_CONTIGUOUS_MEMORY;
1198 iface.u.FreeContiguousMemory.bytes = Bytes;
1199 iface.u.FreeContiguousMemory.physical = Physical;
1200 iface.u.FreeContiguousMemory.logical = Logical;
1202 /* Append it to the queue. */
1203 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE));
1205 /* Success. */
1206 gcmkFOOTER_NO();
1207 return gcvSTATUS_OK;
1209 OnError:
1210 /* Return the status. */
1211 gcmkFOOTER();
1212 return status;
1215 /*******************************************************************************
1217 ** gckEVENT_Signal
1219 ** Schedule an event to trigger a signal.
1221 ** INPUT:
1223 ** gckEVENT Event
1224 ** Pointer to an gckEVENT object.
1226 ** gctSIGNAL Signal
1227 ** Pointer to the signal to trigger.
1229 ** gceKERNEL_WHERE FromWhere
1230 ** Place in the pipe where the event needs to be generated.
1232 ** OUTPUT:
1234 ** Nothing.
1236 gceSTATUS
1237 gckEVENT_Signal(
1238 IN gckEVENT Event,
1239 IN gctSIGNAL Signal,
1240 IN gceKERNEL_WHERE FromWhere
1243 gceSTATUS status;
1244 gcsHAL_INTERFACE iface;
1246 gcmkHEADER_ARG("Event=0x%x Signal=0x%x FromWhere=%d",
1247 Event, Signal, FromWhere);
1249 /* Verify the arguments. */
1250 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1251 gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
1253 /* Mark the event as a signal. */
1254 iface.command = gcvHAL_SIGNAL;
1255 iface.u.Signal.signal = Signal;
1256 #ifdef __QNXNTO__
1257 iface.u.Signal.coid = 0;
1258 iface.u.Signal.rcvid = 0;
1259 #endif
1260 iface.u.Signal.auxSignal = gcvNULL;
1261 iface.u.Signal.process = gcvNULL;
1263 /* Append it to the queue. */
1264 gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE));
1266 /* Success. */
1267 gcmkFOOTER_NO();
1268 return gcvSTATUS_OK;
1270 OnError:
1271 /* Return the status. */
1272 gcmkFOOTER();
1273 return status;
1276 /*******************************************************************************
1278 ** gckEVENT_Submit
1280 ** Submit the current event queue to the GPU.
1282 ** INPUT:
1284 ** gckEVENT Event
1285 ** Pointer to an gckEVENT object.
1287 ** gctBOOL Wait
1288 ** Submit requires one vacant event; if Wait is set to not zero,
1289 ** and there are no vacant events at this time, the function will
1290 ** wait until an event becomes vacant so that submission of the
1291 ** queue is successful.
1293 ** gctBOOL FromPower
1294 ** Determines whether the call originates from inside the power
1295 ** management or not.
1297 ** OUTPUT:
1299 ** Nothing.
1301 gceSTATUS
1302 gckEVENT_Submit(
1303 IN gckEVENT Event,
1304 IN gctBOOL Wait,
1305 IN gctBOOL FromPower
1308 gceSTATUS status;
1309 gctUINT8 id = 0xFF;
1310 gcsEVENT_QUEUE_PTR queue;
1311 gctBOOL acquired = gcvFALSE;
1313 #if !gcdNULL_DRIVER
1314 gctSIZE_T bytes;
1315 gctPOINTER buffer;
1316 gckCOMMAND command = gcvNULL;
1317 gctBOOL commitEntered = gcvFALSE;
1318 #endif
1320 gcmkHEADER_ARG("Event=0x%x Wait=%d", Event, Wait);
1322 #if !gcdNULL_DRIVER
1323 /* Get gckCOMMAND object. */
1324 command = Event->kernel->command;
1325 #endif
1327 /* Are there event queues? */
1328 if (Event->queueHead != gcvNULL)
1330 #if !gcdNULL_DRIVER
1331 /* Acquire the command queue. */
1332 gcmkONERROR(gckCOMMAND_EnterCommit(command, FromPower));
1333 commitEntered = gcvTRUE;
1334 #endif
1336 /* Process all queues. */
1337 while (Event->queueHead != gcvNULL)
1339 /* Acquire the list mutex. */
1340 gcmkONERROR(gckOS_AcquireMutex(Event->os,
1341 Event->eventListMutex,
1342 gcvINFINITE));
1343 acquired = gcvTRUE;
1345 /* Get the current queue. */
1346 queue = Event->queueHead;
1348 /* Allocate an event ID. */
1349 gcmkONERROR(gckEVENT_GetEvent(Event, Wait, &id, queue->source));
1351 /* Copy event list to event ID queue. */
1352 Event->queues[id].source = queue->source;
1353 Event->queues[id].head = queue->head;
1355 /* Remove the top queue from the list. */
1356 if (Event->queueHead == Event->queueTail)
1358 Event->queueHead = gcvNULL;
1359 Event->queueTail = gcvNULL;
1361 else
1363 Event->queueHead = Event->queueHead->next;
1366 /* Free the queue. */
1367 gcmkONERROR(gckEVENT_FreeQueue(Event, queue));
1369 /* Release the list mutex. */
1370 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1371 acquired = gcvFALSE;
1373 gcmkONERROR(__RemoveRecordFromProcessDB(Event,
1374 Event->queues[id].head));
1376 #if gcdNULL_DRIVER
1377 /* Notify immediately on infinite hardware. */
1378 gcmkONERROR(gckEVENT_Interrupt(Event, 1 << id));
1380 gcmkONERROR(gckEVENT_Notify(Event, 0));
1381 #else
1382 /* Get the size of the hardware event. */
1383 gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware,
1384 gcvNULL,
1386 gcvKERNEL_PIXEL,
1387 &bytes));
1389 /* Reserve space in the command queue. */
1390 gcmkONERROR(gckCOMMAND_Reserve(command,
1391 bytes,
1392 &buffer,
1393 &bytes));
1395 /* Set the hardware event in the command queue. */
1396 gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware,
1397 buffer,
1399 Event->queues[id].source,
1400 &bytes));
1402 /* Execute the hardware event. */
1403 gcmkONERROR(gckCOMMAND_Execute(command, bytes));
1404 #endif
1407 #if !gcdNULL_DRIVER
1408 /* Release the command queue. */
1409 gcmkONERROR(gckCOMMAND_ExitCommit(command, FromPower));
1410 commitEntered = gcvFALSE;
1411 #endif
1414 /* Success. */
1415 gcmkFOOTER_NO();
1416 return gcvSTATUS_OK;
1418 OnError:
1419 #if !gcdNULL_DRIVER
1420 if (commitEntered)
1422 /* Release the command queue mutex. */
1423 gcmkVERIFY_OK(gckCOMMAND_ExitCommit(command, FromPower));
1425 #endif
1427 if (acquired)
1429 /* Need to unroll the mutex acquire. */
1430 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1433 if (id != 0xFF)
1435 /* Need to unroll the event allocation. */
1436 Event->queues[id].head = gcvNULL;
1439 /* Return the status. */
1440 gcmkFOOTER();
1441 return status;
1444 /*******************************************************************************
1446 ** gckEVENT_Commit
1448 ** Commit an event queue from the user.
1450 ** INPUT:
1452 ** gckEVENT Event
1453 ** Pointer to an gckEVENT object.
1455 ** gcsQUEUE_PTR Queue
1456 ** User event queue.
1458 ** OUTPUT:
1460 ** Nothing.
1462 gceSTATUS
1463 gckEVENT_Commit(
1464 IN gckEVENT Event,
1465 IN gcsQUEUE_PTR Queue
1468 gceSTATUS status;
1469 gcsQUEUE_PTR record = gcvNULL, next;
1470 gctUINT32 processID;
1471 gctBOOL needCopy = gcvFALSE;
1473 gcmkHEADER_ARG("Event=0x%x Queue=0x%x", Event, Queue);
1475 /* Verify the arguments. */
1476 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1478 /* Get the current process ID. */
1479 gcmkONERROR(gckOS_GetProcessID(&processID));
1481 /* Query if we need to copy the client data. */
1482 gcmkONERROR(gckOS_QueryNeedCopy(Event->os, processID, &needCopy));
1484 /* Loop while there are records in the queue. */
1485 while (Queue != gcvNULL)
1487 gcsQUEUE queue;
1489 if (needCopy)
1491 /* Point to stack record. */
1492 record = &queue;
1494 /* Copy the data from the client. */
1495 gcmkONERROR(gckOS_CopyFromUserData(Event->os,
1496 record,
1497 Queue,
1498 gcmSIZEOF(gcsQUEUE)));
1500 else
1502 gctPOINTER pointer = gcvNULL;
1504 /* Map record into kernel memory. */
1505 gcmkONERROR(gckOS_MapUserPointer(Event->os,
1506 Queue,
1507 gcmSIZEOF(gcsQUEUE),
1508 &pointer));
1510 record = pointer;
1513 /* Append event record to event queue. */
1514 gcmkONERROR(
1515 gckEVENT_AddList(Event, &record->iface, gcvKERNEL_PIXEL, gcvTRUE));
1517 /* Next record in the queue. */
1518 next = record->next;
1520 if (!needCopy)
1522 /* Unmap record from kernel memory. */
1523 gcmkONERROR(
1524 gckOS_UnmapUserPointer(Event->os,
1525 Queue,
1526 gcmSIZEOF(gcsQUEUE),
1527 (gctPOINTER *) record));
1528 record = gcvNULL;
1531 Queue = next;
1534 /* Submit the event list. */
1535 gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE));
1537 /* Success */
1538 gcmkFOOTER_NO();
1539 return gcvSTATUS_OK;
1541 OnError:
1542 if ((record != gcvNULL) && !needCopy)
1544 /* Roll back. */
1545 gcmkVERIFY_OK(gckOS_UnmapUserPointer(Event->os,
1546 Queue,
1547 gcmSIZEOF(gcsQUEUE),
1548 (gctPOINTER *) record));
1551 /* Return the status. */
1552 gcmkFOOTER();
1553 return status;
1556 /*******************************************************************************
1558 ** gckEVENT_Compose
1560 ** Schedule a composition event and start a composition.
1562 ** INPUT:
1564 ** gckEVENT Event
1565 ** Pointer to an gckEVENT object.
1567 ** gcsHAL_COMPOSE_PTR Info
1568 ** Pointer to the composition structure.
1570 ** OUTPUT:
1572 ** Nothing.
1574 gceSTATUS
1575 gckEVENT_Compose(
1576 IN gckEVENT Event,
1577 IN gcsHAL_COMPOSE_PTR Info
1580 gceSTATUS status;
1581 gcsEVENT_PTR headRecord;
1582 gcsEVENT_PTR tailRecord;
1583 gcsEVENT_PTR tempRecord;
1584 gctUINT8 id = 0xFF;
1585 gctUINT32 processID;
1587 gcmkHEADER_ARG("Event=0x%x Info=0x%x", Event, Info);
1589 /* Verify the arguments. */
1590 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1591 gcmkVERIFY_ARGUMENT(Info != gcvNULL);
1593 /* Allocate an event ID. */
1594 gcmkONERROR(gckEVENT_GetEvent(Event, gcvTRUE, &id, gcvKERNEL_PIXEL));
1596 /* Get process ID. */
1597 gcmkONERROR(gckOS_GetProcessID(&processID));
1599 /* Allocate a record. */
1600 gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord));
1601 headRecord = tailRecord = tempRecord;
1603 /* Initialize the record. */
1604 tempRecord->info.command = gcvHAL_SIGNAL;
1605 tempRecord->info.u.Signal.process = Info->process;
1606 #ifdef __QNXNTO__
1607 tempRecord->info.u.Signal.coid = Info->coid;
1608 tempRecord->info.u.Signal.rcvid = Info->rcvid;
1609 #endif
1610 tempRecord->info.u.Signal.signal = Info->signal;
1611 tempRecord->info.u.Signal.auxSignal = gcvNULL;
1612 tempRecord->next = gcvNULL;
1613 tempRecord->processID = processID;
1615 /* Allocate another record for user signal #1. */
1616 if (Info->userSignal1 != gcvNULL)
1618 /* Allocate a record. */
1619 gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord));
1620 tailRecord->next = tempRecord;
1621 tailRecord = tempRecord;
1623 /* Initialize the record. */
1624 tempRecord->info.command = gcvHAL_SIGNAL;
1625 tempRecord->info.u.Signal.process = Info->userProcess;
1626 #ifdef __QNXNTO__
1627 tempRecord->info.u.Signal.coid = Info->coid;
1628 tempRecord->info.u.Signal.rcvid = Info->rcvid;
1629 #endif
1630 tempRecord->info.u.Signal.signal = Info->userSignal1;
1631 tempRecord->info.u.Signal.auxSignal = gcvNULL;
1632 tempRecord->next = gcvNULL;
1633 tempRecord->processID = processID;
1636 /* Allocate another record for user signal #2. */
1637 if (Info->userSignal2 != gcvNULL)
1639 /* Allocate a record. */
1640 gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord));
1641 tailRecord->next = tempRecord;
1642 tailRecord = tempRecord;
1644 /* Initialize the record. */
1645 tempRecord->info.command = gcvHAL_SIGNAL;
1646 tempRecord->info.u.Signal.process = Info->userProcess;
1647 #ifdef __QNXNTO__
1648 tempRecord->info.u.Signal.coid = Info->coid;
1649 tempRecord->info.u.Signal.rcvid = Info->rcvid;
1650 #endif
1651 tempRecord->info.u.Signal.signal = Info->userSignal2;
1652 tempRecord->info.u.Signal.auxSignal = gcvNULL;
1653 tempRecord->next = gcvNULL;
1654 tempRecord->processID = processID;
1657 /* Set the event list. */
1658 Event->queues[id].head = headRecord;
1660 /* Start composition. */
1661 gcmkONERROR(gckHARDWARE_Compose(
1662 Event->kernel->hardware, processID,
1663 Info->size, Info->physical, Info->logical, id
1666 /* Success. */
1667 gcmkFOOTER_NO();
1668 return gcvSTATUS_OK;
1670 OnError:
1671 /* Return the status. */
1672 gcmkFOOTER();
1673 return status;
1676 /*******************************************************************************
1678 ** gckEVENT_Interrupt
1680 ** Called by the interrupt service routine to store the triggered interrupt
1681 ** mask to be later processed by gckEVENT_Notify.
1683 ** INPUT:
1685 ** gckEVENT Event
1686 ** Pointer to an gckEVENT object.
1688 ** gctUINT32 Data
1689 ** Mask for the 32 interrupts.
1691 ** OUTPUT:
1693 ** Nothing.
1695 gceSTATUS
1696 gckEVENT_Interrupt(
1697 IN gckEVENT Event,
1698 IN gctUINT32 Data
1701 gcmkHEADER_ARG("Event=0x%x Data=0x%x", Event, Data);
1703 /* Verify the arguments. */
1704 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1706 /* Combine current interrupt status with pending flags. */
1707 #ifdef __QNXNTO__
1708 atomic_set(&Event->pending, Data);
1709 #else
1710 #ifdef LINUX
1712 gctUINT32 oldVal,newVal;
1714 oldVal = Event->pending;
1715 newVal = oldVal| Data;
1716 }while(atomic_cmpxchg((atomic_t *)&Event->pending,oldVal,newVal)!=oldVal);
1718 #else
1719 Event->pending |= Data;
1720 #endif
1721 #endif
1723 /* Success. */
1724 gcmkFOOTER_NO();
1725 return gcvSTATUS_OK;
1728 /*******************************************************************************
1730 ** gckEVENT_Notify
1732 ** Process all triggered interrupts.
1734 ** INPUT:
1736 ** gckEVENT Event
1737 ** Pointer to an gckEVENT object.
1739 ** OUTPUT:
1741 ** Nothing.
1743 gceSTATUS
1744 gckEVENT_Notify(
1745 IN gckEVENT Event,
1746 IN gctUINT32 IDs
1749 gceSTATUS status = gcvSTATUS_OK;
1750 gctINT i;
1751 gcsEVENT_QUEUE * queue;
1752 gctUINT mask = 0;
1753 gctBOOL acquired = gcvFALSE;
1754 #ifdef __QNXNTO__
1755 gcuVIDMEM_NODE_PTR node;
1756 #endif
1757 gctUINT pending;
1758 gctBOOL suspended = gcvFALSE;
1759 #ifndef __QNXNTO__
1760 gctBOOL empty = gcvFALSE, idle = gcvFALSE;
1761 #endif
1762 gcmDEBUG_ONLY(gctINT eventNumber = 0;)
1763 gctINT32 free;
1764 #if gcdSECURE_USER
1765 gcskSECURE_CACHE_PTR cache;
1766 #endif
1768 gcmkHEADER_ARG("Event=0x%x IDs=0x%x", Event, IDs);
1770 /* Verify the arguments. */
1771 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1773 gcmDEBUG_ONLY(
1774 if (IDs != 0)
1776 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
1778 if (Event->queues[i].head != gcvNULL)
1780 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
1781 "Queue(%d): stamp=%llu source=%d",
1783 Event->queues[i].stamp,
1784 Event->queues[i].source);
1790 for (;;)
1792 /* Suspend interrupts. */
1793 gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core));
1794 suspended = gcvTRUE;
1796 /* Get current interrupts. */
1797 pending = Event->pending;
1799 /* Resume interrupts. */
1800 gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
1801 suspended = gcvFALSE;
1803 if (pending == 0)
1805 /* No more pending interrupts - done. */
1806 break;
1809 gcmkTRACE_ZONE_N(
1810 gcvLEVEL_INFO, gcvZONE_EVENT,
1811 gcmSIZEOF(pending),
1812 "Pending interrupts 0x%x",
1813 pending
1816 queue = gcvNULL;
1818 gcmDEBUG_ONLY(
1819 if (IDs == 0)
1821 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
1823 if (Event->queues[i].head != gcvNULL)
1825 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
1826 "Queue(%d): stamp=%llu source=%d",
1828 Event->queues[i].stamp,
1829 Event->queues[i].source);
1835 /* Find the oldest pending interrupt. */
1836 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
1838 if ((Event->queues[i].head != gcvNULL)
1839 && (pending & (1 << i))
1842 if ((queue == gcvNULL)
1843 || (Event->queues[i].stamp < queue->stamp)
1846 queue = &Event->queues[i];
1847 mask = 1 << i;
1848 gcmDEBUG_ONLY(eventNumber = i);
1853 if (queue == gcvNULL)
1855 gcmkTRACE_ZONE_N(
1856 gcvLEVEL_ERROR, gcvZONE_EVENT,
1857 gcmSIZEOF(pending),
1858 "Interrupts 0x%x are not pending.",
1859 pending
1862 /* Suspend interrupts. */
1863 gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core));
1864 suspended = gcvTRUE;
1866 /* Mark pending interrupts as handled. */
1867 #ifdef __QNXNTO__
1868 atomic_clr(&Event->pending, pending);
1869 #else
1870 #ifdef LINUX
1872 gctUINT32 oldVal,newVal;
1874 oldVal = Event->pending;
1875 newVal = oldVal & (~pending);
1876 }while(atomic_cmpxchg((atomic_t *)&Event->pending,oldVal,newVal)!=oldVal);
1878 #else
1879 Event->pending &= ~pending;
1880 #endif
1881 #endif
1883 /* Resume interrupts. */
1884 gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
1885 suspended = gcvFALSE;
1887 break;
1890 /* Check whether there is a missed interrupt. */
1891 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
1893 if ((Event->queues[i].head != gcvNULL)
1894 && (Event->queues[i].stamp < queue->stamp)
1895 && (Event->queues[i].source == queue->source)
1898 gcmkTRACE_N(
1899 gcvLEVEL_ERROR,
1900 gcmSIZEOF(i) + gcmSIZEOF(Event->queues[i].stamp),
1901 "Event %d lost (stamp %llu)",
1902 i, Event->queues[i].stamp
1905 /* Use this event instead. */
1906 queue = &Event->queues[i];
1907 mask = 0;
1911 if (mask != 0)
1913 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
1914 gcmkTRACE_ZONE_N(
1915 gcvLEVEL_INFO, gcvZONE_EVENT,
1916 gcmSIZEOF(eventNumber),
1917 "Processing interrupt %d",
1918 eventNumber
1920 #endif
1923 /* Walk all events for this interrupt. */
1924 while (1)
1926 gcsEVENT_PTR record,record_next;
1927 #ifndef __QNXNTO__
1928 gctPOINTER logical;
1929 #endif
1930 #if gcdSECURE_USER
1931 gctSIZE_T bytes;
1932 #endif
1934 /* Grab the mutex queue. */
1935 gcmkONERROR(gckOS_AcquireMutex(Event->os,
1936 Event->eventQueueMutex,
1937 gcvINFINITE));
1938 acquired = gcvTRUE;
1940 /* Grab the event head. */
1941 record = queue->head;
1942 record_next = gcvNULL;
1943 if (record != gcvNULL)
1945 record_next = record->next;
1946 queue->head = record_next;
1949 /* Release the mutex queue. */
1950 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
1951 acquired = gcvFALSE;
1953 /* Dispatch on event type. */
1954 if (record != gcvNULL)
1956 #ifdef __QNXNTO__
1957 /* Assign record->processID as the pid for this galcore thread.
1958 * Used in OS calls like gckOS_UnlockMemory() which do not take a pid.
1960 drv_thread_specific_key_assign(record->processID, 0);
1961 #endif
1963 #if gcdSECURE_USER
1964 /* Get the cache that belongs to this process. */
1965 gcmkONERROR(gckKERNEL_GetProcessDBCache(Event->kernel,
1966 record->processID,
1967 &cache));
1968 #endif
1970 gcmkTRACE_ZONE_N(
1971 gcvLEVEL_INFO, gcvZONE_EVENT,
1972 gcmSIZEOF(record->info.command),
1973 "Processing event type: %d",
1974 record->info.command
1977 switch (record->info.command)
1979 case gcvHAL_FREE_NON_PAGED_MEMORY:
1980 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
1981 "gcvHAL_FREE_NON_PAGED_MEMORY: 0x%x",
1982 record->info.u.FreeNonPagedMemory.physical);
1984 /* Free non-paged memory. */
1985 status = gckOS_FreeNonPagedMemory(
1986 Event->os,
1987 record->info.u.FreeNonPagedMemory.bytes,
1988 record->info.u.FreeNonPagedMemory.physical,
1989 record->info.u.FreeNonPagedMemory.logical);
1991 if (gcmIS_SUCCESS(status))
1993 #if gcdSECURE_USER
1994 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
1995 Event->kernel,
1996 cache,
1997 record->event.u.FreeNonPagedMemory.logical,
1998 record->event.u.FreeNonPagedMemory.bytes));
1999 #endif
2001 break;
2003 case gcvHAL_FREE_CONTIGUOUS_MEMORY:
2004 gcmkTRACE_ZONE(
2005 gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2006 "gcvHAL_FREE_CONTIGUOUS_MEMORY: 0x%x",
2007 record->info.u.FreeContiguousMemory.physical);
2009 /* Unmap the user memory. */
2010 status = gckOS_FreeContiguous(
2011 Event->os,
2012 record->info.u.FreeContiguousMemory.physical,
2013 record->info.u.FreeContiguousMemory.logical,
2014 record->info.u.FreeContiguousMemory.bytes);
2016 if (gcmIS_SUCCESS(status))
2018 #if gcdSECURE_USER
2019 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2020 Event->kernel,
2021 cache,
2022 event->event.u.FreeContiguousMemory.logical,
2023 event->event.u.FreeContiguousMemory.bytes));
2024 #endif
2026 break;
2028 case gcvHAL_FREE_VIDEO_MEMORY:
2029 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2030 "gcvHAL_FREE_VIDEO_MEMORY: 0x%x",
2031 record->info.u.FreeVideoMemory.node);
2033 #ifdef __QNXNTO__
2034 node = record->info.u.FreeVideoMemory.node;
2035 #if gcdUSE_VIDMEM_PER_PID
2036 /* Check if the VidMem object still exists. */
2037 if (gckKERNEL_GetVideoMemoryPoolPid(record->kernel,
2038 gcvPOOL_SYSTEM,
2039 record->processID,
2040 gcvNULL) == gcvSTATUS_NOT_FOUND)
2042 /*printf("Vidmem not found for process:%d\n", queue->processID);*/
2043 status = gcvSTATUS_OK;
2044 break;
2046 #else
2047 if ((node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
2048 && (node->VidMem.logical != gcvNULL)
2051 gcmkERR_BREAK(
2052 gckKERNEL_UnmapVideoMemory(record->kernel,
2053 node->VidMem.logical,
2054 record->processID,
2055 node->VidMem.bytes));
2056 node->VidMem.logical = gcvNULL;
2058 #endif
2059 #endif
2061 /* Free video memory. */
2062 status =
2063 gckVIDMEM_Free(record->info.u.FreeVideoMemory.node);
2065 break;
2067 case gcvHAL_WRITE_DATA:
2068 #ifndef __QNXNTO__
2069 /* Convert physical into logical address. */
2070 gcmkERR_BREAK(
2071 gckOS_MapPhysical(Event->os,
2072 record->info.u.WriteData.address,
2073 gcmSIZEOF(gctUINT32),
2074 &logical));
2076 /* Write data. */
2077 gcmkERR_BREAK(
2078 gckOS_WriteMemory(Event->os,
2079 logical,
2080 record->info.u.WriteData.data));
2082 /* Unmap the physical memory. */
2083 gcmkERR_BREAK(
2084 gckOS_UnmapPhysical(Event->os,
2085 logical,
2086 gcmSIZEOF(gctUINT32)));
2087 #else
2088 /* Write data. */
2089 gcmkERR_BREAK(
2090 gckOS_WriteMemory(Event->os,
2091 (gctPOINTER)
2092 record->info.u.WriteData.address,
2093 record->info.u.WriteData.data));
2094 #endif
2095 break;
2097 case gcvHAL_UNLOCK_VIDEO_MEMORY:
2098 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2099 "gcvHAL_UNLOCK_VIDEO_MEMORY: 0x%x",
2100 record->info.u.UnlockVideoMemory.node);
2102 /* Save node information before it disappears. */
2103 #if gcdSECURE_USER
2104 node = event->event.u.UnlockVideoMemory.node;
2105 if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
2107 logical = gcvNULL;
2108 bytes = 0;
2110 else
2112 logical = node->Virtual.logical;
2113 bytes = node->Virtual.bytes;
2115 #endif
2117 /* Unlock. */
2118 status = gckVIDMEM_Unlock(
2119 Event->kernel,
2120 record->info.u.UnlockVideoMemory.node,
2121 record->info.u.UnlockVideoMemory.type,
2122 gcvNULL);
2124 #if gcdSECURE_USER
2125 if (gcmIS_SUCCESS(status) && (logical != gcvNULL))
2127 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2128 Event->kernel,
2129 cache,
2130 logical,
2131 bytes));
2133 #endif
2134 break;
2136 case gcvHAL_SIGNAL:
2137 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2138 "gcvHAL_SIGNAL: 0x%x",
2139 record->info.u.Signal.signal);
2141 #ifdef __QNXNTO__
2142 if ((record->info.u.Signal.coid == 0)
2143 && (record->info.u.Signal.rcvid == 0)
2146 /* Kernel signal. */
2147 gcmkERR_BREAK(
2148 gckOS_Signal(Event->os,
2149 record->info.u.Signal.signal,
2150 gcvTRUE));
2152 else
2154 /* User signal. */
2155 gcmkERR_BREAK(
2156 gckOS_UserSignal(Event->os,
2157 record->info.u.Signal.signal,
2158 record->info.u.Signal.rcvid,
2159 record->info.u.Signal.coid));
2161 #else
2162 /* Set signal. */
2163 if (record->info.u.Signal.process == gcvNULL)
2165 /* Kernel signal. */
2166 gcmkERR_BREAK(
2167 gckOS_Signal(Event->os,
2168 record->info.u.Signal.signal,
2169 gcvTRUE));
2171 else
2173 /* User signal. */
2174 gcmkERR_BREAK(
2175 gckOS_UserSignal(Event->os,
2176 record->info.u.Signal.signal,
2177 record->info.u.Signal.process));
2180 gcmkASSERT(record->info.u.Signal.auxSignal == gcvNULL);
2181 #endif
2182 break;
2184 case gcvHAL_UNMAP_USER_MEMORY:
2185 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2186 "gcvHAL_UNMAP_USER_MEMORY: 0x%x",
2187 record->info.u.UnmapUserMemory.info);
2189 /* Unmap the user memory. */
2190 status = gckOS_UnmapUserMemoryEx(
2191 Event->os,
2192 Event->kernel->core,
2193 record->info.u.UnmapUserMemory.memory,
2194 record->info.u.UnmapUserMemory.size,
2195 record->info.u.UnmapUserMemory.info,
2196 record->info.u.UnmapUserMemory.address);
2198 #if gcdSECURE_USER
2199 if (gcmIS_SUCCESS(status))
2201 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2202 Event->kernel,
2203 cache,
2204 event->event.u.UnmapUserMemory.memory,
2205 event->event.u.UnmapUserMemory.size));
2207 #endif
2208 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
2209 Event->kernel,
2210 record->processID, gcvDB_MAP_USER_MEMORY,
2211 record->info.u.UnmapUserMemory.memory));
2212 break;
2214 case gcvHAL_TIMESTAMP:
2215 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2216 "gcvHAL_TIMESTAMP: %d %d",
2217 record->info.u.TimeStamp.timer,
2218 record->info.u.TimeStamp.request);
2220 /* Process the timestamp. */
2221 switch (record->info.u.TimeStamp.request)
2223 case 0:
2224 status = gckOS_GetTime(&Event->kernel->timers[
2225 record->info.u.TimeStamp.timer].
2226 stopTime);
2227 break;
2229 case 1:
2230 status = gckOS_GetTime(&Event->kernel->timers[
2231 record->info.u.TimeStamp.timer].
2232 startTime);
2233 break;
2235 default:
2236 gcmkTRACE_ZONE_N(
2237 gcvLEVEL_ERROR, gcvZONE_EVENT,
2238 gcmSIZEOF(record->info.u.TimeStamp.request),
2239 "Invalid timestamp request: %d",
2240 record->info.u.TimeStamp.request
2243 status = gcvSTATUS_INVALID_ARGUMENT;
2244 break;
2246 break;
2248 default:
2249 /* Invalid argument. */
2250 gcmkTRACE_ZONE_N(
2251 gcvLEVEL_ERROR, gcvZONE_EVENT,
2252 gcmSIZEOF(record->info.command),
2253 "Unknown event type: %d",
2254 record->info.command
2257 status = gcvSTATUS_INVALID_ARGUMENT;
2258 break;
2261 /* Make sure there are no errors generated. */
2262 if (gcmIS_ERROR(status))
2264 gcmkTRACE_ZONE_N(
2265 gcvLEVEL_WARNING, gcvZONE_EVENT,
2266 gcmSIZEOF(status),
2267 "Event produced status: %d(%s)",
2268 status, gckOS_DebugStatus2Name(status));
2271 /* Free the event. */
2272 gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record));
2275 //Can't use queue->head to check, as the value may be updated while it equals to NULL.
2276 //So use the shadow value to check.
2277 if(record_next == gcvNULL)
2278 break;
2282 /* Increase the number of free events. */
2283 gcmkONERROR(gckOS_AtomIncrement(Event->os, Event->freeAtom, &free));
2285 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2286 "Handled interrupt 0x%x", mask);
2288 /* Suspend interrupts. */
2289 gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core));
2290 suspended = gcvTRUE;
2292 /* Mark pending interrupt as handled. */
2293 #ifdef LINUX
2295 gctUINT32 oldVal,newVal;
2297 oldVal = Event->pending;
2298 newVal = oldVal & (~mask);
2299 }while(atomic_cmpxchg((atomic_t *)&Event->pending,oldVal,newVal)!=oldVal);
2301 #elif defined __QNXNTO__
2302 atomic_clr(&Event->pending, mask);
2303 #else
2304 Event->pending &= ~mask;
2305 #endif
2307 /* Resume interrupts. */
2308 gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
2309 suspended = gcvFALSE;
2312 #ifndef __QNXNTO__
2314 /* Check whether the event queue is empty. */
2315 gcmkONERROR(gckEVENT_IsEmpty(Event, &empty));
2317 if (empty && (IDs == 0))
2319 /* Query whether the hardware is idle. */
2320 gcmkONERROR(gckHARDWARE_QueryIdle(Event->kernel->hardware, &idle));
2322 if (idle)
2324 /* Inform the system of idle GPU. */
2325 gcmkONERROR(gckOS_Broadcast(Event->os,
2326 Event->kernel->hardware,
2327 gcvBROADCAST_GPU_IDLE));
2330 #endif
2332 /* Success. */
2333 gcmkFOOTER_NO();
2334 return gcvSTATUS_OK;
2336 OnError:
2337 if (acquired)
2339 /* Release mutex. */
2340 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2343 if (suspended)
2345 /* Resume interrupts. */
2346 gcmkVERIFY_OK(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
2349 /* Return the status. */
2350 gcmkFOOTER();
2351 return status;
2354 /*******************************************************************************
2355 ** gckEVENT_FreeProcess
2357 ** Free all events owned by a particular process ID.
2359 ** INPUT:
2361 ** gckEVENT Event
2362 ** Pointer to an gckEVENT object.
2364 ** gctUINT32 ProcessID
2365 ** Process ID of the process to be freed up.
2367 ** OUTPUT:
2369 ** Nothing.
2371 gceSTATUS
2372 gckEVENT_FreeProcess(
2373 IN gckEVENT Event,
2374 IN gctUINT32 ProcessID
2377 gctSIZE_T i;
2378 gctBOOL acquired = gcvFALSE;
2379 gcsEVENT_PTR record, next;
2380 gceSTATUS status;
2381 gcsEVENT_PTR deleteHead, deleteTail;
2382 gctBOOL empty, idle;
2384 gcmkHEADER_ARG("Event=0x%x ProcessID=%d", Event, ProcessID);
2386 /* Verify the arguments. */
2387 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
2389 /* Walk through all queues. */
2390 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
2392 if (Event->queues[i].head != gcvNULL)
2394 /* Grab the event queue mutex. */
2395 gcmkONERROR(gckOS_AcquireMutex(Event->os,
2396 Event->eventQueueMutex,
2397 gcvINFINITE));
2398 acquired = gcvTRUE;
2400 /* Grab the mutex head. */
2401 record = Event->queues[i].head;
2402 Event->queues[i].head = gcvNULL;
2403 Event->queues[i].tail = gcvNULL;
2404 deleteHead = gcvNULL;
2405 deleteTail = gcvNULL;
2407 while (record != gcvNULL)
2409 next = record->next;
2410 if (record->processID == ProcessID)
2412 if (deleteHead == gcvNULL)
2414 deleteHead = record;
2416 else
2418 deleteTail->next = record;
2421 deleteTail = record;
2423 else
2425 if (Event->queues[i].head == gcvNULL)
2427 Event->queues[i].head = record;
2429 else
2431 Event->queues[i].tail->next = record;
2434 Event->queues[i].tail = record;
2437 record->next = gcvNULL;
2438 record = next;
2441 /* Release the mutex queue. */
2442 gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2443 acquired = gcvFALSE;
2445 /* Loop through the entire list of events. */
2446 for (record = deleteHead; record != gcvNULL; record = next)
2448 /* Get the next event record. */
2449 next = record->next;
2451 /* Free the event record. */
2452 gcmkONERROR(gckEVENT_FreeRecord(Event, record));
2457 /*Check whether the event queue is empty.*/
2458 gcmkONERROR(_IsEmpty(Event, &empty));
2460 if (empty)
2462 /* Query whether the hardware is idle. */
2463 gcmkONERROR(gckHARDWARE_QueryIdle(Event->kernel->hardware, &idle));
2465 if (idle)
2467 /* Inform the system of idle GPU. */
2468 gcmkONERROR(gckOS_Broadcast(Event->os,
2469 Event->kernel->hardware,
2470 gcvBROADCAST_GPU_IDLE));
2474 /* Success. */
2475 gcmkFOOTER_NO();
2476 return gcvSTATUS_OK;
2478 OnError:
2479 /* Release the event queue mutex. */
2480 if (acquired)
2482 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2485 /* Return the status. */
2486 gcmkFOOTER();
2487 return status;
2490 /*******************************************************************************
2491 ** gckEVENT_Stop
2493 ** Stop the hardware using the End event mechanism.
2495 ** INPUT:
2497 ** gckEVENT Event
2498 ** Pointer to an gckEVENT object.
2500 ** gctUINT32 ProcessID
2501 ** Process ID Logical belongs.
2503 ** gctPHYS_ADDR Handle
2504 ** Physical address handle. If gcvNULL it is video memory.
2506 ** gctPOINTER Logical
2507 ** Logical address to flush.
2509 ** gctSIGNAL Signal
2510 ** Pointer to the signal to trigger.
2512 ** OUTPUT:
2514 ** Nothing.
2516 gceSTATUS
2517 gckEVENT_Stop(
2518 IN gckEVENT Event,
2519 IN gctUINT32 ProcessID,
2520 IN gctPHYS_ADDR Handle,
2521 IN gctPOINTER Logical,
2522 IN gctSIGNAL Signal,
2523 IN OUT gctSIZE_T * waitSize
2526 gceSTATUS status;
2527 /* gctSIZE_T waitSize;*/
2528 gcsEVENT_PTR record;
2529 gctUINT8 id = 0xFF;
2531 gcmkHEADER_ARG("Event=0x%x ProcessID=%u Handle=0x%x Logical=0x%x "
2532 "Signal=0x%x",
2533 Event, ProcessID, Handle, Logical, Signal);
2535 /* Verify the arguments. */
2536 gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
2538 /* Submit the current event queue. */
2539 gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE));
2541 gcmkONERROR(gckEVENT_GetEvent(Event, gcvTRUE, &id, gcvKERNEL_PIXEL));
2543 /* Allocate a record. */
2544 gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &record));
2546 /* Initialize the record. */
2547 record->next = gcvNULL;
2548 record->processID = ProcessID;
2549 record->info.command = gcvHAL_SIGNAL;
2550 record->info.u.Signal.signal = Signal;
2551 #ifdef __QNXNTO__
2552 record->info.u.Signal.coid = 0;
2553 record->info.u.Signal.rcvid = 0;
2554 #endif
2555 record->info.u.Signal.auxSignal = gcvNULL;
2556 record->info.u.Signal.process = gcvNULL;
2558 /* Append the record. */
2559 Event->queues[id].head = record;
2561 /* Replace last WAIT with END. */
2562 gcmkONERROR(gckHARDWARE_End(
2563 Event->kernel->hardware, Logical, waitSize
2566 #if gcdNONPAGED_MEMORY_CACHEABLE
2567 /* Flush the cache for the END. */
2568 gcmkONERROR(gckOS_CacheClean(
2569 Event->os,
2570 ProcessID,
2571 gcvNULL,
2572 Handle,
2573 Logical,
2574 *waitSize
2576 #endif
2578 /* Wait for the signal. */
2579 gcmkONERROR(gckOS_WaitSignal(Event->os, Signal, gcvINFINITE));
2581 /* Success. */
2582 gcmkFOOTER_NO();
2583 return gcvSTATUS_OK;
2585 OnError:
2587 /* Return the status. */
2588 gcmkFOOTER();
2589 return status;