]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c
ENGR00240988: gpu: copy gpu-viv driver from 3.5.7 kernel
[karo-tx-linux.git] / drivers / mxc / gpu-viv / hal / kernel / gc_hal_kernel_event.c
1 /****************************************************************************
2 *
3 *    Copyright (C) 2005 - 2013 by Vivante Corp.
4 *
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.
9 *
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.
14 *
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.
18 *
19 *****************************************************************************/
20
21
22 #include "gc_hal_kernel_precomp.h"
23 #include "gc_hal_kernel_buffer.h"
24
25 #ifdef __QNXNTO__
26 #include <atomic.h>
27 #include "gc_hal_kernel_qnx.h"
28 #endif
29
30 #define _GC_OBJ_ZONE                    gcvZONE_EVENT
31
32 #define gcdEVENT_ALLOCATION_COUNT       (4096 / gcmSIZEOF(gcsHAL_INTERFACE))
33 #define gcdEVENT_MIN_THRESHOLD          4
34
35 /******************************************************************************\
36 ********************************* Support Code *********************************
37 \******************************************************************************/
38
39 static gceSTATUS
40 gckEVENT_AllocateQueue(
41     IN gckEVENT Event,
42     OUT gcsEVENT_QUEUE_PTR * Queue
43     )
44 {
45     gceSTATUS status;
46
47     gcmkHEADER_ARG("Event=0x%x", Event);
48
49     /* Verify the arguments. */
50     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
51     gcmkVERIFY_ARGUMENT(Queue != gcvNULL);
52
53     /* Do we have free queues? */
54     if (Event->freeList == gcvNULL)
55     {
56         gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
57     }
58
59     /* Move one free queue from the free list. */
60     * Queue = Event->freeList;
61     Event->freeList = Event->freeList->next;
62
63     /* Success. */
64     gcmkFOOTER_ARG("*Queue=0x%x", gcmOPT_POINTER(Queue));
65     return gcvSTATUS_OK;
66
67 OnError:
68     /* Return the status. */
69     gcmkFOOTER();
70     return status;
71 }
72
73 static gceSTATUS
74 gckEVENT_FreeQueue(
75     IN gckEVENT Event,
76     OUT gcsEVENT_QUEUE_PTR Queue
77     )
78 {
79     gceSTATUS status = gcvSTATUS_OK;
80
81     gcmkHEADER_ARG("Event=0x%x", Event);
82
83     /* Verify the arguments. */
84     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
85     gcmkVERIFY_ARGUMENT(Queue != gcvNULL);
86
87     /* Move one free queue from the free list. */
88     Queue->next = Event->freeList;
89     Event->freeList = Queue;
90
91     /* Success. */
92     gcmkFOOTER();
93     return status;
94 }
95
96 static gceSTATUS
97 gckEVENT_FreeRecord(
98     IN gckEVENT Event,
99     IN gcsEVENT_PTR Record
100     )
101 {
102     gceSTATUS status;
103     gctBOOL acquired = gcvFALSE;
104
105     gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
106
107     /* Verify the arguments. */
108     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
109     gcmkVERIFY_ARGUMENT(Record != gcvNULL);
110
111     /* Acquire the mutex. */
112     gcmkONERROR(gckOS_AcquireMutex(Event->os,
113                                    Event->freeEventMutex,
114                                    gcvINFINITE));
115     acquired = gcvTRUE;
116
117     /* Push the record on the free list. */
118     Record->next           = Event->freeEventList;
119     Event->freeEventList   = Record;
120     Event->freeEventCount += 1;
121
122     /* Release the mutex. */
123     gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
124
125     /* Success. */
126     gcmkFOOTER_NO();
127     return gcvSTATUS_OK;
128
129 OnError:
130     /* Roll back. */
131     if (acquired)
132     {
133         gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
134     }
135
136     /* Return the status. */
137     gcmkFOOTER();
138     return gcvSTATUS_OK;
139 }
140
141 static gceSTATUS
142 gckEVENT_IsEmpty(
143     IN gckEVENT Event,
144     OUT gctBOOL_PTR IsEmpty
145     )
146 {
147     gceSTATUS status;
148     gctSIZE_T i;
149
150     gcmkHEADER_ARG("Event=0x%x", Event);
151
152     /* Verify the arguments. */
153     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
154     gcmkVERIFY_ARGUMENT(IsEmpty != gcvNULL);
155
156     /* Assume the event queue is empty. */
157     *IsEmpty = gcvTRUE;
158
159     /* Walk the event queue. */
160     for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
161     {
162         /* Check whether this event is in use. */
163         if (Event->queues[i].head != gcvNULL)
164         {
165             /* The event is in use, hence the queue is not empty. */
166             *IsEmpty = gcvFALSE;
167             break;
168         }
169     }
170
171     /* Try acquiring the mutex. */
172     status = gckOS_AcquireMutex(Event->os, Event->eventQueueMutex, 0);
173     if (status == gcvSTATUS_TIMEOUT)
174     {
175         /* Timeout - queue is no longer empty. */
176         *IsEmpty = gcvFALSE;
177     }
178     else
179     {
180         /* Bail out on error. */
181         gcmkONERROR(status);
182
183         /* Release the mutex. */
184         gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
185     }
186
187     /* Success. */
188     gcmkFOOTER_ARG("*IsEmpty=%d", gcmOPT_VALUE(IsEmpty));
189     return gcvSTATUS_OK;
190
191 OnError:
192     /* Return the status. */
193     gcmkFOOTER();
194     return status;
195 }
196
197 static gceSTATUS
198 _TryToIdleGPU(
199     IN gckEVENT Event
200 )
201 {
202     gceSTATUS status;
203     gctBOOL empty = gcvFALSE, idle = gcvFALSE;
204     gctUINT32 process, thread;
205     gctBOOL powerLocked = gcvFALSE;
206     gckHARDWARE hardware;
207
208
209     gcmkHEADER_ARG("Event=0x%x", Event);
210
211     /* Verify the arguments. */
212     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
213
214     /* Grab gckHARDWARE object. */
215     hardware = Event->kernel->hardware;
216     gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
217
218
219     /* Check whether the event queue is empty. */
220     gcmkONERROR(gckEVENT_IsEmpty(Event, &empty));
221
222     if (empty)
223     {
224         status = gckOS_AcquireMutex(hardware->os, hardware->powerMutex, 0);
225         if (status == gcvSTATUS_TIMEOUT)
226         {
227             gcmkONERROR(gckOS_GetProcessID(&process));
228             gcmkONERROR(gckOS_GetThreadID(&thread));
229
230             /* Just return to prevent deadlock. */
231             if ((hardware->powerProcess != process)
232             ||  (hardware->powerThread  != thread))
233             {
234                 gcmkFOOTER_NO();
235                 return gcvSTATUS_OK;
236             }
237         }
238         else
239         {
240             powerLocked = gcvTRUE;
241         }
242
243         /* Query whether the hardware is idle. */
244         gcmkONERROR(gckHARDWARE_QueryIdle(Event->kernel->hardware, &idle));
245
246         if (powerLocked)
247         {
248             gcmkONERROR(gckOS_ReleaseMutex(hardware->os, hardware->powerMutex));
249             powerLocked = gcvFALSE;
250         }
251
252         if (idle)
253         {
254             /* Inform the system of idle GPU. */
255             gcmkONERROR(gckOS_Broadcast(Event->os,
256                                         Event->kernel->hardware,
257                                         gcvBROADCAST_GPU_IDLE));
258         }
259     }
260
261     gcmkFOOTER_NO();
262     return gcvSTATUS_OK;
263
264 OnError:
265
266     if (powerLocked)
267     {
268         gcmkONERROR(gckOS_ReleaseMutex(hardware->os, hardware->powerMutex));
269         powerLocked = gcvFALSE;
270     }
271
272     gcmkFOOTER();
273     return status;
274 }
275
276 static gceSTATUS
277 __RemoveRecordFromProcessDB(
278     IN gckEVENT Event,
279     IN gcsEVENT_PTR Record
280     )
281 {
282     gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
283     gcmkVERIFY_ARGUMENT(Record != gcvNULL);
284
285     while (Record != gcvNULL)
286     {
287         if (Record->info.command == gcvHAL_SIGNAL)
288         {
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));
293         }
294
295         if (Record->fromKernel)
296         {
297             /* No need to check db if event is from kernel. */
298             Record = Record->next;
299             continue;
300         }
301
302         switch (Record->info.command)
303         {
304         case gcvHAL_FREE_NON_PAGED_MEMORY:
305             gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
306                 Event->kernel,
307                 Record->processID,
308                 gcvDB_NON_PAGED,
309                 gcmUINT64_TO_PTR(Record->info.u.FreeNonPagedMemory.logical)));
310             break;
311
312         case gcvHAL_FREE_CONTIGUOUS_MEMORY:
313             gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
314                 Event->kernel,
315                 Record->processID,
316                 gcvDB_CONTIGUOUS,
317                 gcmUINT64_TO_PTR(Record->info.u.FreeContiguousMemory.logical)));
318             break;
319
320         case gcvHAL_FREE_VIDEO_MEMORY:
321             gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
322                 Event->kernel,
323                 Record->processID,
324                 gcvDB_VIDEO_MEMORY,
325                 gcmUINT64_TO_PTR(Record->info.u.FreeVideoMemory.node)));
326             break;
327
328         case gcvHAL_UNLOCK_VIDEO_MEMORY:
329             gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
330                 Event->kernel,
331                 Record->processID,
332                 gcvDB_VIDEO_MEMORY_LOCKED,
333                 gcmUINT64_TO_PTR(Record->info.u.UnlockVideoMemory.node)));
334             break;
335
336         case gcvHAL_UNMAP_USER_MEMORY:
337             gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
338                 Event->kernel,
339                 Record->processID,
340                 gcvDB_MAP_USER_MEMORY,
341                 gcmINT2PTR(Record->info.u.UnmapUserMemory.info)));
342             break;
343
344         case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
345             gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
346                 Event->kernel,
347                 Record->processID,
348                 gcvDB_COMMAND_BUFFER,
349                 gcmUINT64_TO_PTR(Record->info.u.FreeVirtualCommandBuffer.logical)));
350             break;
351
352         default:
353             break;
354         }
355
356         Record = Record->next;
357     }
358     gcmkFOOTER_NO();
359     return gcvSTATUS_OK;
360 }
361
362 void
363 _SubmitTimerFunction(
364     gctPOINTER Data
365     )
366 {
367     gckEVENT event = (gckEVENT)Data;
368     gcmkVERIFY_OK(gckEVENT_Submit(event, gcvTRUE, gcvFALSE));
369 }
370
371 /******************************************************************************\
372 ******************************* gckEVENT API Code *******************************
373 \******************************************************************************/
374
375 /*******************************************************************************
376 **
377 **  gckEVENT_Construct
378 **
379 **  Construct a new gckEVENT object.
380 **
381 **  INPUT:
382 **
383 **      gckKERNEL Kernel
384 **          Pointer to an gckKERNEL object.
385 **
386 **  OUTPUT:
387 **
388 **      gckEVENT * Event
389 **          Pointer to a variable that receives the gckEVENT object pointer.
390 */
391 gceSTATUS
392 gckEVENT_Construct(
393     IN gckKERNEL Kernel,
394     OUT gckEVENT * Event
395     )
396 {
397     gckOS os;
398     gceSTATUS status;
399     gckEVENT eventObj = gcvNULL;
400     int i;
401     gcsEVENT_PTR record;
402     gctPOINTER pointer = gcvNULL;
403
404     gcmkHEADER_ARG("Kernel=0x%x", Kernel);
405
406     /* Verify the arguments. */
407     gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
408     gcmkVERIFY_ARGUMENT(Event != gcvNULL);
409
410     /* Extract the pointer to the gckOS object. */
411     os = Kernel->os;
412     gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
413
414     /* Allocate the gckEVENT object. */
415     gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckEVENT), &pointer));
416
417     eventObj = pointer;
418
419     /* Reset the object. */
420     gcmkVERIFY_OK(gckOS_ZeroMemory(eventObj, gcmSIZEOF(struct _gckEVENT)));
421
422     /* Initialize the gckEVENT object. */
423     eventObj->object.type = gcvOBJ_EVENT;
424     eventObj->kernel      = Kernel;
425     eventObj->os          = os;
426
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));
431
432     /* Create a bunch of event reccords. */
433     for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1)
434     {
435         /* Allocate an event record. */
436         gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsEVENT), &pointer));
437
438         record = pointer;
439
440         /* Push it on the free list. */
441         record->next              = eventObj->freeEventList;
442         eventObj->freeEventList   = record;
443         eventObj->freeEventCount += 1;
444     }
445
446     /* Initialize the free list of event queues. */
447     for (i = 0; i < gcdREPO_LIST_COUNT; i += 1)
448     {
449         eventObj->repoList[i].next = eventObj->freeList;
450         eventObj->freeList = &eventObj->repoList[i];
451     }
452
453     /* Construct the atom. */
454     gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->freeAtom));
455     gcmkONERROR(gckOS_AtomSet(os,
456                               eventObj->freeAtom,
457                               gcmCOUNTOF(eventObj->queues)));
458
459 #if gcdSMP
460     gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->pending));
461 #endif
462
463     gcmkVERIFY_OK(gckOS_CreateTimer(os,
464                                     _SubmitTimerFunction,
465                                     (gctPOINTER)eventObj,
466                                     &eventObj->submitTimer));
467
468     /* Return pointer to the gckEVENT object. */
469     *Event = eventObj;
470
471     /* Success. */
472     gcmkFOOTER_ARG("*Event=0x%x", *Event);
473     return gcvSTATUS_OK;
474
475 OnError:
476     /* Roll back. */
477     if (eventObj != gcvNULL)
478     {
479         if (eventObj->eventQueueMutex != gcvNULL)
480         {
481             gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventQueueMutex));
482         }
483
484         if (eventObj->freeEventMutex != gcvNULL)
485         {
486             gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->freeEventMutex));
487         }
488
489         if (eventObj->eventListMutex != gcvNULL)
490         {
491             gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventListMutex));
492         }
493
494         while (eventObj->freeEventList != gcvNULL)
495         {
496             record = eventObj->freeEventList;
497             eventObj->freeEventList = record->next;
498
499             gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, record));
500         }
501
502         if (eventObj->freeAtom != gcvNULL)
503         {
504             gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->freeAtom));
505         }
506
507 #if gcdSMP
508         if (eventObj->pending != gcvNULL)
509         {
510             gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->pending));
511         }
512 #endif
513         gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, eventObj));
514     }
515
516     /* Return the status. */
517     gcmkFOOTER();
518     return status;
519 }
520
521 /*******************************************************************************
522 **
523 **  gckEVENT_Destroy
524 **
525 **  Destroy an gckEVENT object.
526 **
527 **  INPUT:
528 **
529 **      gckEVENT Event
530 **          Pointer to an gckEVENT object.
531 **
532 **  OUTPUT:
533 **
534 **      Nothing.
535 */
536 gceSTATUS
537 gckEVENT_Destroy(
538     IN gckEVENT Event
539     )
540 {
541     gcsEVENT_PTR record;
542     gcsEVENT_QUEUE_PTR queue;
543
544     gcmkHEADER_ARG("Event=0x%x", Event);
545
546     /* Verify the arguments. */
547     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
548
549     if (Event->submitTimer != gcvNULL)
550     {
551         gcmkVERIFY_OK(gckOS_StopTimer(Event->os, Event->submitTimer));
552         gcmkVERIFY_OK(gckOS_DestroyTimer(Event->os, Event->submitTimer));
553     }
554
555     /* Delete the queue mutex. */
556     gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventQueueMutex));
557
558     /* Free all free events. */
559     while (Event->freeEventList != gcvNULL)
560     {
561         record = Event->freeEventList;
562         Event->freeEventList = record->next;
563
564         gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record));
565     }
566
567     /* Delete the free mutex. */
568     gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->freeEventMutex));
569
570     /* Free all pending queues. */
571     while (Event->queueHead != gcvNULL)
572     {
573         /* Get the current queue. */
574         queue = Event->queueHead;
575
576         /* Free all pending events. */
577         while (queue->head != gcvNULL)
578         {
579             record      = queue->head;
580             queue->head = record->next;
581
582             gcmkTRACE_ZONE_N(
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
587                 );
588
589             gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record));
590         }
591
592         /* Remove the top queue from the list. */
593         if (Event->queueHead == Event->queueTail)
594         {
595             Event->queueHead =
596             Event->queueTail = gcvNULL;
597         }
598         else
599         {
600             Event->queueHead = Event->queueHead->next;
601         }
602
603         /* Free the queue. */
604         gcmkVERIFY_OK(gckEVENT_FreeQueue(Event, queue));
605     }
606
607     /* Delete the list mutex. */
608     gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventListMutex));
609
610     /* Delete the atom. */
611     gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->freeAtom));
612
613 #if gcdSMP
614     gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->pending));
615 #endif
616
617     /* Mark the gckEVENT object as unknown. */
618     Event->object.type = gcvOBJ_UNKNOWN;
619
620     /* Free the gckEVENT object. */
621     gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, Event));
622
623     /* Success. */
624     gcmkFOOTER_NO();
625     return gcvSTATUS_OK;
626 }
627
628 /*******************************************************************************
629 **
630 **  gckEVENT_GetEvent
631 **
632 **  Reserve the next available hardware event.
633 **
634 **  INPUT:
635 **
636 **      gckEVENT Event
637 **          Pointer to an gckEVENT object.
638 **
639 **      gctBOOL Wait
640 **          Set to gcvTRUE to force the function to wait if no events are
641 **          immediately available.
642 **
643 **      gceKERNEL_WHERE Source
644 **          Source of the event.
645 **
646 **  OUTPUT:
647 **
648 **      gctUINT8 * EventID
649 **          Reserved event ID.
650 */
651 gceSTATUS
652 gckEVENT_GetEvent(
653     IN gckEVENT Event,
654     IN gctBOOL Wait,
655     OUT gctUINT8 * EventID,
656     IN gceKERNEL_WHERE Source
657     )
658 {
659     gctINT i, id;
660     gceSTATUS status;
661     gctBOOL acquired = gcvFALSE;
662     gctINT32 free;
663
664 #if gcdGPU_TIMEOUT
665     gctUINT32 timer = 0;
666 #endif
667
668     gcmkHEADER_ARG("Event=0x%x Source=%d", Event, Source);
669
670     while (gcvTRUE)
671     {
672         /* Grab the queue mutex. */
673         gcmkONERROR(gckOS_AcquireMutex(Event->os,
674                                        Event->eventQueueMutex,
675                                        gcvINFINITE));
676         acquired = gcvTRUE;
677
678         /* Walk through all events. */
679         id = Event->lastID;
680         for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
681         {
682             gctINT nextID = gckMATH_ModuloInt((id + 1),
683                                               gcmCOUNTOF(Event->queues));
684
685             if (Event->queues[id].head == gcvNULL)
686             {
687                 *EventID = (gctUINT8) id;
688
689                 Event->lastID = (gctUINT8) nextID;
690
691                 /* Save time stamp of event. */
692                 Event->queues[id].stamp  = ++(Event->stamp);
693                 Event->queues[id].source = Source;
694
695                 gcmkONERROR(gckOS_AtomDecrement(Event->os,
696                                                 Event->freeAtom,
697                                                 &free));
698 #if gcdDYNAMIC_SPEED
699                 if (free <= gcdDYNAMIC_EVENT_THRESHOLD)
700                 {
701                     gcmkONERROR(gckOS_BroadcastHurry(
702                         Event->os,
703                         Event->kernel->hardware,
704                         gcdDYNAMIC_EVENT_THRESHOLD - free));
705                 }
706 #endif
707
708                 /* Release the queue mutex. */
709                 gcmkONERROR(gckOS_ReleaseMutex(Event->os,
710                                                Event->eventQueueMutex));
711
712                 /* Success. */
713                 gcmkTRACE_ZONE_N(
714                     gcvLEVEL_INFO, gcvZONE_EVENT,
715                     gcmSIZEOF(id),
716                     "Using id=%d",
717                     id
718                     );
719
720                 gcmkFOOTER_ARG("*EventID=%u", *EventID);
721                 return gcvSTATUS_OK;
722             }
723
724             id = nextID;
725         }
726
727 #if gcdDYNAMIC_SPEED
728         /* No free events, speed up the GPU right now! */
729         gcmkONERROR(gckOS_BroadcastHurry(Event->os,
730                                          Event->kernel->hardware,
731                                          gcdDYNAMIC_EVENT_THRESHOLD));
732 #endif
733
734         /* Release the queue mutex. */
735         gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
736         acquired = gcvFALSE;
737
738         /* Fail if wait is not requested. */
739         if (!Wait)
740         {
741             /* Out of resources. */
742             gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
743         }
744
745         /* Delay a while. */
746         gcmkONERROR(gckOS_Delay(Event->os, 1));
747
748 #if gcdGPU_TIMEOUT
749         /* Increment the wait timer. */
750         timer += 1;
751
752         if (timer == gcdGPU_TIMEOUT)
753         {
754             /* Try to call any outstanding events. */
755             gcmkONERROR(gckHARDWARE_Interrupt(Event->kernel->hardware,
756                                               gcvTRUE));
757         }
758         else if (timer > gcdGPU_TIMEOUT)
759         {
760             gcmkTRACE_N(
761                 gcvLEVEL_ERROR,
762                 gcmSIZEOF(gctCONST_STRING) + gcmSIZEOF(gctINT),
763                 "%s(%d): no available events\n",
764                 __FUNCTION__, __LINE__
765                 );
766
767             /* Bail out. */
768             gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING);
769         }
770 #endif
771     }
772
773 OnError:
774     if (acquired)
775     {
776         /* Release the queue mutex. */
777         gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
778     }
779
780     /* Return the status. */
781     gcmkFOOTER();
782     return status;
783 }
784
785 /*******************************************************************************
786 **
787 **  gckEVENT_AllocateRecord
788 **
789 **  Allocate a record for the new event.
790 **
791 **  INPUT:
792 **
793 **      gckEVENT Event
794 **          Pointer to an gckEVENT object.
795 **
796 **      gctBOOL AllocateAllowed
797 **          State for allocation if out of free events.
798 **
799 **  OUTPUT:
800 **
801 **      gcsEVENT_PTR * Record
802 **          Allocated event record.
803 */
804 gceSTATUS
805 gckEVENT_AllocateRecord(
806     IN gckEVENT Event,
807     IN gctBOOL AllocateAllowed,
808     OUT gcsEVENT_PTR * Record
809     )
810 {
811     gceSTATUS status;
812     gctBOOL acquired = gcvFALSE;
813     gctINT i;
814     gcsEVENT_PTR record;
815     gctPOINTER pointer = gcvNULL;
816
817     gcmkHEADER_ARG("Event=0x%x AllocateAllowed=%d", Event, AllocateAllowed);
818
819     /* Verify the arguments. */
820     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
821     gcmkVERIFY_ARGUMENT(Record != gcvNULL);
822
823     /* Acquire the mutex. */
824     gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->freeEventMutex, gcvINFINITE));
825     acquired = gcvTRUE;
826
827     /* Test if we are below the allocation threshold. */
828     if ( (AllocateAllowed && (Event->freeEventCount < gcdEVENT_MIN_THRESHOLD)) ||
829          (Event->freeEventCount == 0) )
830     {
831         /* Allocate a bunch of records. */
832         for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1)
833         {
834             /* Allocate an event record. */
835             gcmkONERROR(gckOS_Allocate(Event->os,
836                                        gcmSIZEOF(gcsEVENT),
837                                        &pointer));
838
839             record = pointer;
840
841             /* Push it on the free list. */
842             record->next           = Event->freeEventList;
843             Event->freeEventList   = record;
844             Event->freeEventCount += 1;
845         }
846     }
847
848     *Record                = Event->freeEventList;
849     Event->freeEventList   = Event->freeEventList->next;
850     Event->freeEventCount -= 1;
851
852     /* Release the mutex. */
853     gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
854     acquired = gcvFALSE;
855
856     /* Success. */
857     gcmkFOOTER_ARG("*Record=0x%x", gcmOPT_POINTER(Record));
858     return gcvSTATUS_OK;
859
860 OnError:
861     /* Roll back. */
862     if (acquired)
863     {
864         gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
865     }
866
867     /* Return the status. */
868     gcmkFOOTER();
869     return status;
870 }
871
872 /*******************************************************************************
873 **
874 **  gckEVENT_AddList
875 **
876 **  Add a new event to the list of events.
877 **
878 **  INPUT:
879 **
880 **      gckEVENT Event
881 **          Pointer to an gckEVENT object.
882 **
883 **      gcsHAL_INTERFACE_PTR Interface
884 **          Pointer to the interface for the event to be added.
885 **
886 **      gceKERNEL_WHERE FromWhere
887 **          Place in the pipe where the event needs to be generated.
888 **
889 **      gctBOOL AllocateAllowed
890 **          State for allocation if out of free events.
891 **
892 **  OUTPUT:
893 **
894 **      Nothing.
895 */
896 gceSTATUS
897 gckEVENT_AddList(
898     IN gckEVENT Event,
899     IN gcsHAL_INTERFACE_PTR Interface,
900     IN gceKERNEL_WHERE FromWhere,
901     IN gctBOOL AllocateAllowed,
902     IN gctBOOL FromKernel
903     )
904 {
905     gceSTATUS status;
906     gctBOOL acquired = gcvFALSE;
907     gcsEVENT_PTR record = gcvNULL;
908     gcsEVENT_QUEUE_PTR queue;
909     gckKERNEL kernel = Event->kernel;
910
911     gcmkHEADER_ARG("Event=0x%x Interface=0x%x",
912                    Event, Interface);
913
914     gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, _GC_OBJ_ZONE,
915                     "FromWhere=%d AllocateAllowed=%d",
916                     FromWhere, AllocateAllowed);
917
918     /* Verify the arguments. */
919     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
920     gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
921
922     /* Verify the event command. */
923     gcmkASSERT
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)
934         );
935
936     /* Validate the source. */
937     if ((FromWhere != gcvKERNEL_COMMAND) && (FromWhere != gcvKERNEL_PIXEL))
938     {
939         /* Invalid argument. */
940         gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
941     }
942
943     /* Allocate a free record. */
944     gcmkONERROR(gckEVENT_AllocateRecord(Event, AllocateAllowed, &record));
945
946     /* Termninate the record. */
947     record->next = gcvNULL;
948
949     /* Record the committer. */
950     record->fromKernel = FromKernel;
951
952     /* Copy the event interface into the record. */
953     gckOS_MemCopy(&record->info, Interface, gcmSIZEOF(record->info));
954
955     /* Get process ID. */
956     gcmkONERROR(gckOS_GetProcessID(&record->processID));
957
958 #ifdef __QNXNTO__
959     record->kernel = Event->kernel;
960 #endif
961
962     gcmkONERROR(__RemoveRecordFromProcessDB(Event, record));
963
964     /* Acquire the mutex. */
965     gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->eventListMutex, gcvINFINITE));
966     acquired = gcvTRUE;
967
968     /* Do we need to allocate a new queue? */
969     if ((Event->queueTail == gcvNULL) || (Event->queueTail->source < FromWhere))
970     {
971         /* Allocate a new queue. */
972         gcmkONERROR(gckEVENT_AllocateQueue(Event, &queue));
973
974         /* Initialize the queue. */
975         queue->source = FromWhere;
976         queue->head   = gcvNULL;
977         queue->next   = gcvNULL;
978
979         /* Attach it to the list of allocated queues. */
980         if (Event->queueTail == gcvNULL)
981         {
982             Event->queueHead =
983             Event->queueTail = queue;
984         }
985         else
986         {
987             Event->queueTail->next = queue;
988             Event->queueTail       = queue;
989         }
990     }
991     else
992     {
993         queue = Event->queueTail;
994     }
995
996     /* Attach the record to the queue. */
997     if (queue->head == gcvNULL)
998     {
999         queue->head = record;
1000         queue->tail = record;
1001     }
1002     else
1003     {
1004         queue->tail->next = record;
1005         queue->tail       = record;
1006     }
1007
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.
1011      * */
1012     switch(Interface->command)
1013     {
1014     case gcvHAL_FREE_NON_PAGED_MEMORY:
1015         gcmkONERROR(gckOS_UnmapUserLogical(
1016                         Event->os,
1017                         gcmNAME_TO_PTR(Interface->u.FreeNonPagedMemory.physical),
1018                         (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes,
1019                         gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical)));
1020         break;
1021     case gcvHAL_FREE_CONTIGUOUS_MEMORY:
1022         gcmkONERROR(gckOS_UnmapUserLogical(
1023                         Event->os,
1024                         gcmNAME_TO_PTR(Interface->u.FreeContiguousMemory.physical),
1025                         (gctSIZE_T) Interface->u.FreeContiguousMemory.bytes,
1026                         gcmUINT64_TO_PTR(Interface->u.FreeContiguousMemory.logical)));
1027         break;
1028     default:
1029         break;
1030     }
1031
1032
1033     /* Release the mutex. */
1034     gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1035
1036     /* Success. */
1037     gcmkFOOTER_NO();
1038     return gcvSTATUS_OK;
1039
1040 OnError:
1041     /* Roll back. */
1042     if (acquired)
1043     {
1044         gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1045     }
1046
1047     if (record != gcvNULL)
1048     {
1049         gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record));
1050     }
1051
1052     /* Return the status. */
1053     gcmkFOOTER();
1054     return status;
1055 }
1056
1057 /*******************************************************************************
1058 **
1059 **  gckEVENT_Unlock
1060 **
1061 **  Schedule an event to unlock virtual memory.
1062 **
1063 **  INPUT:
1064 **
1065 **      gckEVENT Event
1066 **          Pointer to an gckEVENT object.
1067 **
1068 **      gceKERNEL_WHERE FromWhere
1069 **          Place in the pipe where the event needs to be generated.
1070 **
1071 **      gcuVIDMEM_NODE_PTR Node
1072 **          Pointer to a gcuVIDMEM_NODE union that specifies the virtual memory
1073 **          to unlock.
1074 **
1075 **      gceSURF_TYPE Type
1076 **          Type of surface to unlock.
1077 **
1078 **  OUTPUT:
1079 **
1080 **      Nothing.
1081 */
1082 gceSTATUS
1083 gckEVENT_Unlock(
1084     IN gckEVENT Event,
1085     IN gceKERNEL_WHERE FromWhere,
1086     IN gcuVIDMEM_NODE_PTR Node,
1087     IN gceSURF_TYPE Type
1088     )
1089 {
1090     gceSTATUS status;
1091     gcsHAL_INTERFACE iface;
1092
1093     gcmkHEADER_ARG("Event=0x%x FromWhere=%d Node=0x%x Type=%d",
1094                    Event, FromWhere, Node, Type);
1095
1096     /* Verify the arguments. */
1097     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1098     gcmkVERIFY_ARGUMENT(Node != gcvNULL);
1099
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;
1105
1106     /* Append it to the queue. */
1107     gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1108
1109     /* Success. */
1110     gcmkFOOTER_NO();
1111     return gcvSTATUS_OK;
1112
1113 OnError:
1114     /* Return the status. */
1115     gcmkFOOTER();
1116     return status;
1117 }
1118
1119 /*******************************************************************************
1120 **
1121 **  gckEVENT_FreeVideoMemory
1122 **
1123 **  Schedule an event to free video memory.
1124 **
1125 **  INPUT:
1126 **
1127 **      gckEVENT Event
1128 **          Pointer to an gckEVENT object.
1129 **
1130 **      gcuVIDMEM_NODE_PTR VideoMemory
1131 **          Pointer to a gcuVIDMEM_NODE object to free.
1132 **
1133 **      gceKERNEL_WHERE FromWhere
1134 **          Place in the pipe where the event needs to be generated.
1135 **
1136 **  OUTPUT:
1137 **
1138 **      Nothing.
1139 */
1140 gceSTATUS
1141 gckEVENT_FreeVideoMemory(
1142     IN gckEVENT Event,
1143     IN gcuVIDMEM_NODE_PTR VideoMemory,
1144     IN gceKERNEL_WHERE FromWhere
1145     )
1146 {
1147     gceSTATUS status;
1148     gcsHAL_INTERFACE iface;
1149
1150     gcmkHEADER_ARG("Event=0x%x VideoMemory=0x%x FromWhere=%d",
1151                    Event, VideoMemory, FromWhere);
1152
1153     /* Verify the arguments. */
1154     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1155     gcmkVERIFY_ARGUMENT(VideoMemory != gcvNULL);
1156
1157     /* Create an event. */
1158     iface.command = gcvHAL_FREE_VIDEO_MEMORY;
1159     iface.u.FreeVideoMemory.node = gcmPTR_TO_UINT64(VideoMemory);
1160
1161     /* Append it to the queue. */
1162     gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1163
1164     /* Success. */
1165     gcmkFOOTER_NO();
1166     return gcvSTATUS_OK;
1167
1168 OnError:
1169     /* Return the status. */
1170     gcmkFOOTER();
1171     return status;
1172 }
1173
1174 /*******************************************************************************
1175 **
1176 **  gckEVENT_FreeNonPagedMemory
1177 **
1178 **  Schedule an event to free non-paged memory.
1179 **
1180 **  INPUT:
1181 **
1182 **      gckEVENT Event
1183 **          Pointer to an gckEVENT object.
1184 **
1185 **      gctSIZE_T Bytes
1186 **          Number of bytes of non-paged memory to free.
1187 **
1188 **      gctPHYS_ADDR Physical
1189 **          Physical address of non-paged memory to free.
1190 **
1191 **      gctPOINTER Logical
1192 **          Logical address of non-paged memory to free.
1193 **
1194 **      gceKERNEL_WHERE FromWhere
1195 **          Place in the pipe where the event needs to be generated.
1196 */
1197 gceSTATUS
1198 gckEVENT_FreeNonPagedMemory(
1199     IN gckEVENT Event,
1200     IN gctSIZE_T Bytes,
1201     IN gctPHYS_ADDR Physical,
1202     IN gctPOINTER Logical,
1203     IN gceKERNEL_WHERE FromWhere
1204     )
1205 {
1206     gceSTATUS status;
1207     gcsHAL_INTERFACE iface;
1208     gckKERNEL kernel = Event->kernel;
1209
1210     gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
1211                    "FromWhere=%d",
1212                    Event, Bytes, Physical, Logical, FromWhere);
1213
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);
1219
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);
1225
1226     /* Append it to the queue. */
1227     gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1228
1229     /* Success. */
1230     gcmkFOOTER_NO();
1231     return gcvSTATUS_OK;
1232
1233 OnError:
1234     /* Return the status. */
1235     gcmkFOOTER();
1236     return status;
1237 }
1238
1239 gceSTATUS
1240 gckEVENT_DestroyVirtualCommandBuffer(
1241     IN gckEVENT Event,
1242     IN gctSIZE_T Bytes,
1243     IN gctPHYS_ADDR Physical,
1244     IN gctPOINTER Logical,
1245     IN gceKERNEL_WHERE FromWhere
1246     )
1247 {
1248     gceSTATUS status;
1249     gcsHAL_INTERFACE iface;
1250     gckKERNEL kernel = Event->kernel;
1251
1252     gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
1253                    "FromWhere=%d",
1254                    Event, Bytes, Physical, Logical, FromWhere);
1255
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);
1261
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);
1267
1268     /* Append it to the queue. */
1269     gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1270
1271     /* Success. */
1272     gcmkFOOTER_NO();
1273     return gcvSTATUS_OK;
1274
1275 OnError:
1276     /* Return the status. */
1277     gcmkFOOTER();
1278     return status;
1279 }
1280
1281 /*******************************************************************************
1282 **
1283 **  gckEVENT_FreeContigiuousMemory
1284 **
1285 **  Schedule an event to free contiguous memory.
1286 **
1287 **  INPUT:
1288 **
1289 **      gckEVENT Event
1290 **          Pointer to an gckEVENT object.
1291 **
1292 **      gctSIZE_T Bytes
1293 **          Number of bytes of contiguous memory to free.
1294 **
1295 **      gctPHYS_ADDR Physical
1296 **          Physical address of contiguous memory to free.
1297 **
1298 **      gctPOINTER Logical
1299 **          Logical address of contiguous memory to free.
1300 **
1301 **      gceKERNEL_WHERE FromWhere
1302 **          Place in the pipe where the event needs to be generated.
1303 */
1304 gceSTATUS
1305 gckEVENT_FreeContiguousMemory(
1306     IN gckEVENT Event,
1307     IN gctSIZE_T Bytes,
1308     IN gctPHYS_ADDR Physical,
1309     IN gctPOINTER Logical,
1310     IN gceKERNEL_WHERE FromWhere
1311     )
1312 {
1313     gceSTATUS status;
1314     gcsHAL_INTERFACE iface;
1315     gckKERNEL kernel = Event->kernel;
1316
1317     gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
1318                    "FromWhere=%d",
1319                    Event, Bytes, Physical, Logical, FromWhere);
1320
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);
1326
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);
1332
1333     /* Append it to the queue. */
1334     gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1335
1336     /* Success. */
1337     gcmkFOOTER_NO();
1338     return gcvSTATUS_OK;
1339
1340 OnError:
1341     /* Return the status. */
1342     gcmkFOOTER();
1343     return status;
1344 }
1345
1346 /*******************************************************************************
1347 **
1348 **  gckEVENT_Signal
1349 **
1350 **  Schedule an event to trigger a signal.
1351 **
1352 **  INPUT:
1353 **
1354 **      gckEVENT Event
1355 **          Pointer to an gckEVENT object.
1356 **
1357 **      gctSIGNAL Signal
1358 **          Pointer to the signal to trigger.
1359 **
1360 **      gceKERNEL_WHERE FromWhere
1361 **          Place in the pipe where the event needs to be generated.
1362 **
1363 **  OUTPUT:
1364 **
1365 **      Nothing.
1366 */
1367 gceSTATUS
1368 gckEVENT_Signal(
1369     IN gckEVENT Event,
1370     IN gctSIGNAL Signal,
1371     IN gceKERNEL_WHERE FromWhere
1372     )
1373 {
1374     gceSTATUS status;
1375     gcsHAL_INTERFACE iface;
1376
1377     gcmkHEADER_ARG("Event=0x%x Signal=0x%x FromWhere=%d",
1378                    Event, Signal, FromWhere);
1379
1380     /* Verify the arguments. */
1381     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1382     gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
1383
1384     /* Mark the event as a signal. */
1385     iface.command            = gcvHAL_SIGNAL;
1386     iface.u.Signal.signal    = gcmPTR_TO_UINT64(Signal);
1387 #ifdef __QNXNTO__
1388     iface.u.Signal.coid      = 0;
1389     iface.u.Signal.rcvid     = 0;
1390 #endif
1391     iface.u.Signal.auxSignal = 0;
1392     iface.u.Signal.process   = 0;
1393
1394     /* Append it to the queue. */
1395     gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1396
1397     /* Success. */
1398     gcmkFOOTER_NO();
1399     return gcvSTATUS_OK;
1400
1401 OnError:
1402     /* Return the status. */
1403     gcmkFOOTER();
1404     return status;
1405 }
1406
1407 /*******************************************************************************
1408 **
1409 **  gckEVENT_CommitDone
1410 **
1411 **  Schedule an event to wake up work thread when commit is done by GPU.
1412 **
1413 **  INPUT:
1414 **
1415 **      gckEVENT Event
1416 **          Pointer to an gckEVENT object.
1417 **
1418 **      gceKERNEL_WHERE FromWhere
1419 **          Place in the pipe where the event needs to be generated.
1420 **
1421 **  OUTPUT:
1422 **
1423 **      Nothing.
1424 */
1425 gceSTATUS
1426 gckEVENT_CommitDone(
1427     IN gckEVENT Event,
1428     IN gceKERNEL_WHERE FromWhere
1429     )
1430 {
1431     gceSTATUS status;
1432     gcsHAL_INTERFACE iface;
1433
1434     gcmkHEADER_ARG("Event=0x%x FromWhere=%d", Event, FromWhere);
1435
1436     /* Verify the arguments. */
1437     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1438
1439     iface.command = gcvHAL_COMMIT_DONE;
1440
1441     /* Append it to the queue. */
1442     gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
1443
1444     /* Success. */
1445     gcmkFOOTER_NO();
1446     return gcvSTATUS_OK;
1447
1448 OnError:
1449     /* Return the status. */
1450     gcmkFOOTER();
1451     return status;
1452 }
1453 /*******************************************************************************
1454 **
1455 **  gckEVENT_Submit
1456 **
1457 **  Submit the current event queue to the GPU.
1458 **
1459 **  INPUT:
1460 **
1461 **      gckEVENT Event
1462 **          Pointer to an gckEVENT object.
1463 **
1464 **      gctBOOL Wait
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.
1469 **
1470 **      gctBOOL FromPower
1471 **          Determines whether the call originates from inside the power
1472 **          management or not.
1473 **
1474 **  OUTPUT:
1475 **
1476 **      Nothing.
1477 */
1478 gceSTATUS
1479 gckEVENT_Submit(
1480     IN gckEVENT Event,
1481     IN gctBOOL Wait,
1482     IN gctBOOL FromPower
1483     )
1484 {
1485     gceSTATUS status;
1486     gctUINT8 id = 0xFF;
1487     gcsEVENT_QUEUE_PTR queue;
1488     gctBOOL acquired = gcvFALSE;
1489     gckCOMMAND command = gcvNULL;
1490     gctBOOL commitEntered = gcvFALSE;
1491 #if !gcdNULL_DRIVER
1492     gctSIZE_T bytes;
1493     gctPOINTER buffer;
1494 #endif
1495
1496     gcmkHEADER_ARG("Event=0x%x Wait=%d", Event, Wait);
1497
1498     /* Get gckCOMMAND object. */
1499     command = Event->kernel->command;
1500
1501     /* Are there event queues? */
1502     if (Event->queueHead != gcvNULL)
1503     {
1504         /* Acquire the command queue. */
1505         gcmkONERROR(gckCOMMAND_EnterCommit(command, FromPower));
1506         commitEntered = gcvTRUE;
1507
1508         /* Process all queues. */
1509         while (Event->queueHead != gcvNULL)
1510         {
1511             /* Acquire the list mutex. */
1512             gcmkONERROR(gckOS_AcquireMutex(Event->os,
1513                                            Event->eventListMutex,
1514                                            gcvINFINITE));
1515             acquired = gcvTRUE;
1516
1517             /* Get the current queue. */
1518             queue = Event->queueHead;
1519
1520             /* Allocate an event ID. */
1521             gcmkONERROR(gckEVENT_GetEvent(Event, Wait, &id, queue->source));
1522
1523             /* Copy event list to event ID queue. */
1524             Event->queues[id].head   = queue->head;
1525
1526             /* Remove the top queue from the list. */
1527             if (Event->queueHead == Event->queueTail)
1528             {
1529                 Event->queueHead = gcvNULL;
1530                 Event->queueTail = gcvNULL;
1531             }
1532             else
1533             {
1534                 Event->queueHead = Event->queueHead->next;
1535             }
1536
1537             /* Free the queue. */
1538             gcmkONERROR(gckEVENT_FreeQueue(Event, queue));
1539
1540             /* Release the list mutex. */
1541             gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1542             acquired = gcvFALSE;
1543
1544 #if gcdNULL_DRIVER
1545             /* Notify immediately on infinite hardware. */
1546             gcmkONERROR(gckEVENT_Interrupt(Event, 1 << id));
1547
1548             gcmkONERROR(gckEVENT_Notify(Event, 0));
1549 #else
1550             /* Get the size of the hardware event. */
1551             gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware,
1552                                           gcvNULL,
1553                                           id,
1554                                           Event->queues[id].source,
1555                                           &bytes));
1556
1557             /* Reserve space in the command queue. */
1558             gcmkONERROR(gckCOMMAND_Reserve(command,
1559                                            bytes,
1560                                            &buffer,
1561                                            &bytes));
1562
1563             /* Set the hardware event in the command queue. */
1564             gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware,
1565                                           buffer,
1566                                           id,
1567                                           Event->queues[id].source,
1568                                           &bytes));
1569
1570             /* Execute the hardware event. */
1571             gcmkONERROR(gckCOMMAND_Execute(command, bytes));
1572 #endif
1573         }
1574
1575         /* Release the command queue. */
1576         gcmkONERROR(gckCOMMAND_ExitCommit(command, FromPower));
1577         commitEntered = gcvFALSE;
1578
1579 #if !gcdNULL_DRIVER
1580         gcmkVERIFY_OK(_TryToIdleGPU(Event));
1581 #endif
1582     }
1583
1584     /* Success. */
1585     gcmkFOOTER_NO();
1586     return gcvSTATUS_OK;
1587
1588 OnError:
1589     if (commitEntered)
1590     {
1591         /* Release the command queue mutex. */
1592         gcmkVERIFY_OK(gckCOMMAND_ExitCommit(command, FromPower));
1593     }
1594
1595     if (acquired)
1596     {
1597         /* Need to unroll the mutex acquire. */
1598         gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
1599     }
1600
1601     if (id != 0xFF)
1602     {
1603         /* Need to unroll the event allocation. */
1604         Event->queues[id].head = gcvNULL;
1605     }
1606
1607     if (status == gcvSTATUS_GPU_NOT_RESPONDING)
1608     {
1609         /* Broadcast GPU stuck. */
1610         status = gckOS_Broadcast(Event->os,
1611                                  Event->kernel->hardware,
1612                                  gcvBROADCAST_GPU_STUCK);
1613     }
1614
1615     /* Return the status. */
1616     gcmkFOOTER();
1617     return status;
1618 }
1619
1620 /*******************************************************************************
1621 **
1622 **  gckEVENT_Commit
1623 **
1624 **  Commit an event queue from the user.
1625 **
1626 **  INPUT:
1627 **
1628 **      gckEVENT Event
1629 **          Pointer to an gckEVENT object.
1630 **
1631 **      gcsQUEUE_PTR Queue
1632 **          User event queue.
1633 **
1634 **  OUTPUT:
1635 **
1636 **      Nothing.
1637 */
1638 gceSTATUS
1639 gckEVENT_Commit(
1640     IN gckEVENT Event,
1641     IN gcsQUEUE_PTR Queue
1642     )
1643 {
1644     gceSTATUS status;
1645     gcsQUEUE_PTR record = gcvNULL, next;
1646     gctUINT32 processID;
1647     gctBOOL needCopy = gcvFALSE;
1648
1649     gcmkHEADER_ARG("Event=0x%x Queue=0x%x", Event, Queue);
1650
1651     /* Verify the arguments. */
1652     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1653
1654     /* Get the current process ID. */
1655     gcmkONERROR(gckOS_GetProcessID(&processID));
1656
1657     /* Query if we need to copy the client data. */
1658     gcmkONERROR(gckOS_QueryNeedCopy(Event->os, processID, &needCopy));
1659
1660     /* Loop while there are records in the queue. */
1661     while (Queue != gcvNULL)
1662     {
1663         gcsQUEUE queue;
1664
1665         if (needCopy)
1666         {
1667             /* Point to stack record. */
1668             record = &queue;
1669
1670             /* Copy the data from the client. */
1671             gcmkONERROR(gckOS_CopyFromUserData(Event->os,
1672                                                record,
1673                                                Queue,
1674                                                gcmSIZEOF(gcsQUEUE)));
1675         }
1676         else
1677         {
1678             gctPOINTER pointer = gcvNULL;
1679
1680             /* Map record into kernel memory. */
1681             gcmkONERROR(gckOS_MapUserPointer(Event->os,
1682                                              Queue,
1683                                              gcmSIZEOF(gcsQUEUE),
1684                                              &pointer));
1685
1686             record = pointer;
1687         }
1688
1689         /* Append event record to event queue. */
1690         gcmkONERROR(
1691             gckEVENT_AddList(Event, &record->iface, gcvKERNEL_PIXEL, gcvTRUE, gcvFALSE));
1692
1693         /* Next record in the queue. */
1694         next = gcmUINT64_TO_PTR(record->next);
1695
1696         if (!needCopy)
1697         {
1698             /* Unmap record from kernel memory. */
1699             gcmkONERROR(
1700                 gckOS_UnmapUserPointer(Event->os,
1701                                        Queue,
1702                                        gcmSIZEOF(gcsQUEUE),
1703                                        (gctPOINTER *) record));
1704             record = gcvNULL;
1705         }
1706
1707         Queue = next;
1708     }
1709
1710     /* Submit the event list. */
1711     gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE));
1712
1713     /* Success */
1714     gcmkFOOTER_NO();
1715     return gcvSTATUS_OK;
1716
1717 OnError:
1718     if ((record != gcvNULL) && !needCopy)
1719     {
1720         /* Roll back. */
1721         gcmkVERIFY_OK(gckOS_UnmapUserPointer(Event->os,
1722                                              Queue,
1723                                              gcmSIZEOF(gcsQUEUE),
1724                                              (gctPOINTER *) record));
1725     }
1726
1727     /* Return the status. */
1728     gcmkFOOTER();
1729     return status;
1730 }
1731
1732 /*******************************************************************************
1733 **
1734 **  gckEVENT_Compose
1735 **
1736 **  Schedule a composition event and start a composition.
1737 **
1738 **  INPUT:
1739 **
1740 **      gckEVENT Event
1741 **          Pointer to an gckEVENT object.
1742 **
1743 **      gcsHAL_COMPOSE_PTR Info
1744 **          Pointer to the composition structure.
1745 **
1746 **  OUTPUT:
1747 **
1748 **      Nothing.
1749 */
1750 gceSTATUS
1751 gckEVENT_Compose(
1752     IN gckEVENT Event,
1753     IN gcsHAL_COMPOSE_PTR Info
1754     )
1755 {
1756     gceSTATUS status;
1757     gcsEVENT_PTR headRecord;
1758     gcsEVENT_PTR tailRecord;
1759     gcsEVENT_PTR tempRecord;
1760     gctUINT8 id = 0xFF;
1761     gctUINT32 processID;
1762
1763     gcmkHEADER_ARG("Event=0x%x Info=0x%x", Event, Info);
1764
1765     /* Verify the arguments. */
1766     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1767     gcmkVERIFY_ARGUMENT(Info != gcvNULL);
1768
1769     /* Allocate an event ID. */
1770     gcmkONERROR(gckEVENT_GetEvent(Event, gcvTRUE, &id, gcvKERNEL_PIXEL));
1771
1772     /* Get process ID. */
1773     gcmkONERROR(gckOS_GetProcessID(&processID));
1774
1775     /* Allocate a record. */
1776     gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord));
1777     headRecord = tailRecord = tempRecord;
1778
1779     /* Initialize the record. */
1780     tempRecord->info.command            = gcvHAL_SIGNAL;
1781     tempRecord->info.u.Signal.process   = Info->process;
1782 #ifdef __QNXNTO__
1783     tempRecord->info.u.Signal.coid      = Info->coid;
1784     tempRecord->info.u.Signal.rcvid     = Info->rcvid;
1785 #endif
1786     tempRecord->info.u.Signal.signal    = Info->signal;
1787     tempRecord->info.u.Signal.auxSignal = 0;
1788     tempRecord->next = gcvNULL;
1789     tempRecord->processID = processID;
1790
1791     /* Allocate another record for user signal #1. */
1792     if (gcmUINT64_TO_PTR(Info->userSignal1) != gcvNULL)
1793     {
1794         /* Allocate a record. */
1795         gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord));
1796         tailRecord->next = tempRecord;
1797         tailRecord = tempRecord;
1798
1799         /* Initialize the record. */
1800         tempRecord->info.command            = gcvHAL_SIGNAL;
1801         tempRecord->info.u.Signal.process   = Info->userProcess;
1802 #ifdef __QNXNTO__
1803         tempRecord->info.u.Signal.coid      = Info->coid;
1804         tempRecord->info.u.Signal.rcvid     = Info->rcvid;
1805 #endif
1806         tempRecord->info.u.Signal.signal    = Info->userSignal1;
1807         tempRecord->info.u.Signal.auxSignal = 0;
1808         tempRecord->next = gcvNULL;
1809         tempRecord->processID = processID;
1810     }
1811
1812     /* Allocate another record for user signal #2. */
1813     if (gcmUINT64_TO_PTR(Info->userSignal2) != gcvNULL)
1814     {
1815         /* Allocate a record. */
1816         gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord));
1817         tailRecord->next = tempRecord;
1818         tailRecord = tempRecord;
1819
1820         /* Initialize the record. */
1821         tempRecord->info.command            = gcvHAL_SIGNAL;
1822         tempRecord->info.u.Signal.process   = Info->userProcess;
1823 #ifdef __QNXNTO__
1824         tempRecord->info.u.Signal.coid      = Info->coid;
1825         tempRecord->info.u.Signal.rcvid     = Info->rcvid;
1826 #endif
1827         tempRecord->info.u.Signal.signal    = Info->userSignal2;
1828         tempRecord->info.u.Signal.auxSignal = 0;
1829         tempRecord->next = gcvNULL;
1830         tempRecord->processID = processID;
1831     }
1832
1833         /* Set the event list. */
1834     Event->queues[id].head = headRecord;
1835
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
1840         ));
1841
1842     /* Success. */
1843     gcmkFOOTER_NO();
1844     return gcvSTATUS_OK;
1845
1846 OnError:
1847     /* Return the status. */
1848     gcmkFOOTER();
1849     return status;
1850 }
1851
1852 /*******************************************************************************
1853 **
1854 **  gckEVENT_Interrupt
1855 **
1856 **  Called by the interrupt service routine to store the triggered interrupt
1857 **  mask to be later processed by gckEVENT_Notify.
1858 **
1859 **  INPUT:
1860 **
1861 **      gckEVENT Event
1862 **          Pointer to an gckEVENT object.
1863 **
1864 **      gctUINT32 Data
1865 **          Mask for the 32 interrupts.
1866 **
1867 **  OUTPUT:
1868 **
1869 **      Nothing.
1870 */
1871 gceSTATUS
1872 gckEVENT_Interrupt(
1873     IN gckEVENT Event,
1874     IN gctUINT32 Data
1875     )
1876 {
1877     gcmkHEADER_ARG("Event=0x%x Data=0x%x", Event, Data);
1878
1879     /* Verify the arguments. */
1880     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1881
1882     /* Combine current interrupt status with pending flags. */
1883 #if gcdSMP
1884     gckOS_AtomSetMask(Event->pending, Data);
1885 #elif defined(__QNXNTO__)
1886     atomic_set(&Event->pending, Data);
1887 #else
1888     Event->pending |= Data;
1889 #endif
1890
1891     /* Success. */
1892     gcmkFOOTER_NO();
1893     return gcvSTATUS_OK;
1894 }
1895
1896 /*******************************************************************************
1897 **
1898 **  gckEVENT_Notify
1899 **
1900 **  Process all triggered interrupts.
1901 **
1902 **  INPUT:
1903 **
1904 **      gckEVENT Event
1905 **          Pointer to an gckEVENT object.
1906 **
1907 **  OUTPUT:
1908 **
1909 **      Nothing.
1910 */
1911 gceSTATUS
1912 gckEVENT_Notify(
1913     IN gckEVENT Event,
1914     IN gctUINT32 IDs
1915     )
1916 {
1917     gceSTATUS status = gcvSTATUS_OK;
1918     gctINT i;
1919     gcsEVENT_QUEUE * queue;
1920     gctUINT mask = 0;
1921     gctBOOL acquired = gcvFALSE;
1922     gcuVIDMEM_NODE_PTR node;
1923     gctPOINTER info;
1924     gctSIGNAL signal;
1925     gctUINT pending;
1926     gckKERNEL kernel = Event->kernel;
1927 #if !gcdSMP
1928     gctBOOL suspended = gcvFALSE;
1929 #endif
1930 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
1931     gctINT eventNumber = 0;
1932 #endif
1933     gctINT32 free;
1934 #if gcdSECURE_USER
1935     gcskSECURE_CACHE_PTR cache;
1936 #endif
1937
1938     gcmkHEADER_ARG("Event=0x%x IDs=0x%x", Event, IDs);
1939
1940     /* Verify the arguments. */
1941     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
1942
1943     gcmDEBUG_ONLY(
1944         if (IDs != 0)
1945         {
1946             for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
1947             {
1948                 if (Event->queues[i].head != gcvNULL)
1949                 {
1950                     gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
1951                                    "Queue(%d): stamp=%llu source=%d",
1952                                    i,
1953                                    Event->queues[i].stamp,
1954                                    Event->queues[i].source);
1955                 }
1956             }
1957         }
1958     );
1959
1960     for (;;)
1961     {
1962         gcsEVENT_PTR record;
1963
1964 #if gcdSMP
1965         /* Get current interrupts. */
1966         gckOS_AtomGet(Event->os, Event->pending, (gctINT32_PTR)&pending);
1967 #else
1968         /* Suspend interrupts. */
1969         gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core));
1970         suspended = gcvTRUE;
1971
1972         /* Get current interrupts. */
1973         pending = Event->pending;
1974
1975         /* Resume interrupts. */
1976         gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
1977         suspended = gcvFALSE;
1978 #endif
1979
1980         if (pending == 0)
1981         {
1982             /* No more pending interrupts - done. */
1983             break;
1984         }
1985
1986         if (pending & 0x80000000)
1987         {
1988             gckOS_Print("!!!!!!!!!!!!! AXI BUS ERROR !!!!!!!!!!!!!\n");
1989             gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_EVENT, "AXI BUS ERROR");
1990             pending &= 0x7FFFFFFF;
1991         }
1992
1993         if (pending & 0x40000000)
1994         {
1995             gckHARDWARE_DumpMMUException(Event->kernel->hardware);
1996
1997             pending &= 0xBFFFFFFF;
1998         }
1999
2000         gcmkTRACE_ZONE_N(
2001             gcvLEVEL_INFO, gcvZONE_EVENT,
2002             gcmSIZEOF(pending),
2003             "Pending interrupts 0x%x",
2004             pending
2005             );
2006
2007         queue = gcvNULL;
2008
2009         gcmDEBUG_ONLY(
2010             if (IDs == 0)
2011             {
2012                 for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
2013                 {
2014                     if (Event->queues[i].head != gcvNULL)
2015                     {
2016                         gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2017                                        "Queue(%d): stamp=%llu source=%d",
2018                                        i,
2019                                        Event->queues[i].stamp,
2020                                        Event->queues[i].source);
2021                     }
2022                 }
2023             }
2024         );
2025
2026         /* Find the oldest pending interrupt. */
2027         for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
2028         {
2029             if ((Event->queues[i].head != gcvNULL)
2030             &&  (pending & (1 << i))
2031             )
2032             {
2033                 if ((queue == gcvNULL)
2034                 ||  (Event->queues[i].stamp < queue->stamp)
2035                 )
2036                 {
2037                     queue = &Event->queues[i];
2038                     mask  = 1 << i;
2039 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
2040                     eventNumber = i;
2041 #endif
2042                 }
2043             }
2044         }
2045
2046         if (queue == gcvNULL)
2047         {
2048             gcmkTRACE_ZONE_N(
2049                 gcvLEVEL_ERROR, gcvZONE_EVENT,
2050                 gcmSIZEOF(pending),
2051                 "Interrupts 0x%x are not pending.",
2052                 pending
2053                 );
2054
2055 #if gcdSMP
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);
2061 #else
2062             /* Suspend interrupts. */
2063             gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core));
2064             suspended = gcvTRUE;
2065
2066             /* Mark pending interrupts as handled. */
2067             Event->pending &= ~pending;
2068
2069             /* Resume interrupts. */
2070             gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
2071             suspended = gcvFALSE;
2072 #endif
2073             break;
2074         }
2075
2076         /* Check whether there is a missed interrupt. */
2077         for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
2078         {
2079             if ((Event->queues[i].head != gcvNULL)
2080             &&  (Event->queues[i].stamp < queue->stamp)
2081             &&  (Event->queues[i].source <= queue->source)
2082             )
2083             {
2084                 gcmkTRACE_N(
2085                     gcvLEVEL_ERROR,
2086                     gcmSIZEOF(i) + gcmSIZEOF(Event->queues[i].stamp),
2087                     "Event %d lost (stamp %llu)",
2088                     i, Event->queues[i].stamp
2089                     );
2090
2091                 /* Use this event instead. */
2092                 queue = &Event->queues[i];
2093                 mask  = 0;
2094             }
2095         }
2096
2097         if (mask != 0)
2098         {
2099 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
2100             gcmkTRACE_ZONE_N(
2101                 gcvLEVEL_INFO, gcvZONE_EVENT,
2102                 gcmSIZEOF(eventNumber),
2103                 "Processing interrupt %d",
2104                 eventNumber
2105                 );
2106 #endif
2107         }
2108
2109 #if gcdSMP
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);
2115 #else
2116         /* Suspend interrupts. */
2117         gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core));
2118         suspended = gcvTRUE;
2119
2120         /* Mark pending interrupt as handled. */
2121         Event->pending &= ~mask;
2122
2123         /* Resume interrupts. */
2124         gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
2125         suspended = gcvFALSE;
2126 #endif
2127
2128         /* Grab the mutex queue. */
2129         gcmkONERROR(gckOS_AcquireMutex(Event->os,
2130                                        Event->eventQueueMutex,
2131                                        gcvINFINITE));
2132         acquired = gcvTRUE;
2133
2134         /* Grab the event head. */
2135         record = queue->head;
2136
2137         /* Now quickly clear its event list. */
2138         queue->head = gcvNULL;
2139
2140         /* Release the mutex queue. */
2141         gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2142         acquired = gcvFALSE;
2143
2144         /* Increase the number of free events. */
2145         gcmkONERROR(gckOS_AtomIncrement(Event->os, Event->freeAtom, &free));
2146
2147         /* Walk all events for this interrupt. */
2148         while (record != gcvNULL)
2149         {
2150             gcsEVENT_PTR recordNext;
2151 #ifndef __QNXNTO__
2152             gctPOINTER logical;
2153 #endif
2154 #if gcdSECURE_USER
2155             gctSIZE_T bytes;
2156 #endif
2157
2158             /* Grab next record. */
2159             recordNext = record->next;
2160
2161 #ifdef __QNXNTO__
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.
2164              */
2165             drv_thread_specific_key_assign(record->processID, 0, Event->kernel->core);
2166 #endif
2167
2168 #if gcdSECURE_USER
2169             /* Get the cache that belongs to this process. */
2170             gcmkONERROR(gckKERNEL_GetProcessDBCache(Event->kernel,
2171                         record->processID,
2172                         &cache));
2173 #endif
2174
2175             gcmkTRACE_ZONE_N(
2176                 gcvLEVEL_INFO, gcvZONE_EVENT,
2177                 gcmSIZEOF(record->info.command),
2178                 "Processing event type: %d",
2179                 record->info.command
2180                 );
2181
2182             switch (record->info.command)
2183             {
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));
2188
2189                 /* Free non-paged memory. */
2190                 status = gckOS_FreeNonPagedMemory(
2191                             Event->os,
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));
2195
2196                 if (gcmIS_SUCCESS(status))
2197                 {
2198 #if gcdSECURE_USER
2199                     gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2200                         Event->kernel,
2201                         cache,
2202                         gcmUINT64_TO_PTR(record->record.u.FreeNonPagedMemory.logical),
2203                         (gctSIZE_T) record->record.u.FreeNonPagedMemory.bytes));
2204 #endif
2205                 }
2206                 gcmRELEASE_NAME(record->info.u.FreeNonPagedMemory.physical);
2207                 break;
2208
2209             case gcvHAL_FREE_CONTIGUOUS_MEMORY:
2210                 gcmkTRACE_ZONE(
2211                     gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2212                     "gcvHAL_FREE_CONTIGUOUS_MEMORY: 0x%x",
2213                     gcmNAME_TO_PTR(record->info.u.FreeContiguousMemory.physical));
2214
2215                 /* Unmap the user memory. */
2216                 status = gckOS_FreeContiguous(
2217                             Event->os,
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);
2221
2222                 if (gcmIS_SUCCESS(status))
2223                 {
2224 #if gcdSECURE_USER
2225                     gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2226                         Event->kernel,
2227                         cache,
2228                         gcmUINT64_TO_PTR(record->record.u.FreeContiguousMemory.logical),
2229                         (gctSIZE_T) record->record.u.FreeContiguousMemory.bytes));
2230 #endif
2231                 }
2232                 gcmRELEASE_NAME(record->info.u.FreeContiguousMemory.physical);
2233                 break;
2234
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",
2239                                node);
2240 #ifdef __QNXNTO__
2241 #if gcdUSE_VIDMEM_PER_PID
2242                 /* Check if the VidMem object still exists. */
2243                 if (gckKERNEL_GetVideoMemoryPoolPid(record->kernel,
2244                                                     gcvPOOL_SYSTEM,
2245                                                     record->processID,
2246                                                     gcvNULL) == gcvSTATUS_NOT_FOUND)
2247                 {
2248                     /*printf("Vidmem not found for process:%d\n", queue->processID);*/
2249                     status = gcvSTATUS_OK;
2250                     break;
2251                 }
2252 #else
2253                 if ((node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
2254                 &&  (node->VidMem.logical != gcvNULL)
2255                 )
2256                 {
2257                     gcmkERR_BREAK(
2258                         gckKERNEL_UnmapVideoMemory(record->kernel,
2259                                                    node->VidMem.logical,
2260                                                    record->processID,
2261                                                    node->VidMem.bytes));
2262                     node->VidMem.logical = gcvNULL;
2263                 }
2264 #endif
2265 #endif
2266
2267                 /* Free video memory. */
2268                 status =
2269                     gckVIDMEM_Free(node);
2270
2271                 break;
2272
2273             case gcvHAL_WRITE_DATA:
2274 #ifndef __QNXNTO__
2275                 /* Convert physical into logical address. */
2276                 gcmkERR_BREAK(
2277                     gckOS_MapPhysical(Event->os,
2278                                       record->info.u.WriteData.address,
2279                                       gcmSIZEOF(gctUINT32),
2280                                       &logical));
2281
2282                 /* Write data. */
2283                 gcmkERR_BREAK(
2284                     gckOS_WriteMemory(Event->os,
2285                                       logical,
2286                                       record->info.u.WriteData.data));
2287
2288                 /* Unmap the physical memory. */
2289                 gcmkERR_BREAK(
2290                     gckOS_UnmapPhysical(Event->os,
2291                                         logical,
2292                                         gcmSIZEOF(gctUINT32)));
2293 #else
2294                 /* Write data. */
2295                 gcmkERR_BREAK(
2296                     gckOS_WriteMemory(Event->os,
2297                                       (gctPOINTER)
2298                                           record->info.u.WriteData.address,
2299                                       record->info.u.WriteData.data));
2300 #endif
2301                 break;
2302
2303             case gcvHAL_UNLOCK_VIDEO_MEMORY:
2304                 node = gcmUINT64_TO_PTR(record->info.u.UnlockVideoMemory.node);
2305
2306                 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2307                                "gcvHAL_UNLOCK_VIDEO_MEMORY: 0x%x",
2308                                node);
2309
2310                 /* Save node information before it disappears. */
2311 #if gcdSECURE_USER
2312                 if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
2313                 {
2314                     logical = gcvNULL;
2315                     bytes   = 0;
2316                 }
2317                 else
2318                 {
2319                     logical = node->Virtual.logical;
2320                     bytes   = node->Virtual.bytes;
2321                 }
2322 #endif
2323
2324                 /* Unlock. */
2325                 status = gckVIDMEM_Unlock(
2326                     Event->kernel,
2327                     node,
2328                     record->info.u.UnlockVideoMemory.type,
2329                     gcvNULL);
2330
2331 #if gcdSECURE_USER
2332                 if (gcmIS_SUCCESS(status) && (logical != gcvNULL))
2333                 {
2334                     gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2335                         Event->kernel,
2336                         cache,
2337                         logical,
2338                         bytes));
2339                 }
2340 #endif
2341                 break;
2342
2343             case gcvHAL_SIGNAL:
2344                 signal = gcmUINT64_TO_PTR(record->info.u.Signal.signal);
2345                 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2346                                "gcvHAL_SIGNAL: 0x%x",
2347                                signal);
2348
2349 #ifdef __QNXNTO__
2350                 if ((record->info.u.Signal.coid == 0)
2351                 &&  (record->info.u.Signal.rcvid == 0)
2352                 )
2353                 {
2354                     /* Kernel signal. */
2355                     gcmkERR_BREAK(
2356                         gckOS_Signal(Event->os,
2357                                      signal,
2358                                      gcvTRUE));
2359                 }
2360                 else
2361                 {
2362                     /* User signal. */
2363                     gcmkERR_BREAK(
2364                         gckOS_UserSignal(Event->os,
2365                                          signal,
2366                                          record->info.u.Signal.rcvid,
2367                                          record->info.u.Signal.coid));
2368                 }
2369 #else
2370                 /* Set signal. */
2371                 if (gcmUINT64_TO_PTR(record->info.u.Signal.process) == gcvNULL)
2372                 {
2373                     /* Kernel signal. */
2374                     gcmkERR_BREAK(
2375                         gckOS_Signal(Event->os,
2376                                      signal,
2377                                      gcvTRUE));
2378                 }
2379                 else
2380                 {
2381                     /* User signal. */
2382                     gcmkERR_BREAK(
2383                         gckOS_UserSignal(Event->os,
2384                                          signal,
2385                                          gcmUINT64_TO_PTR(record->info.u.Signal.process)));
2386                 }
2387
2388                 gcmkASSERT(record->info.u.Signal.auxSignal == 0);
2389 #endif
2390                 break;
2391
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",
2396                                info);
2397
2398                 /* Unmap the user memory. */
2399                 status = gckOS_UnmapUserMemory(
2400                     Event->os,
2401                     Event->kernel->core,
2402                     gcmUINT64_TO_PTR(record->info.u.UnmapUserMemory.memory),
2403                     (gctSIZE_T) record->info.u.UnmapUserMemory.size,
2404                     info,
2405                     record->info.u.UnmapUserMemory.address);
2406
2407 #if gcdSECURE_USER
2408                 if (gcmIS_SUCCESS(status))
2409                 {
2410                     gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2411                         Event->kernel,
2412                         cache,
2413                         gcmUINT64_TO_PTR(record->info.u.UnmapUserMemory.memory),
2414                         (gctSIZE_T) record->info.u.UnmapUserMemory.size));
2415                 }
2416 #endif
2417                 gcmRELEASE_NAME(record->info.u.UnmapUserMemory.info);
2418                 break;
2419
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);
2425
2426                 /* Process the timestamp. */
2427                 switch (record->info.u.TimeStamp.request)
2428                 {
2429                 case 0:
2430                     status = gckOS_GetTime(&Event->kernel->timers[
2431                                            record->info.u.TimeStamp.timer].
2432                                            stopTime);
2433                     break;
2434
2435                 case 1:
2436                     status = gckOS_GetTime(&Event->kernel->timers[
2437                                            record->info.u.TimeStamp.timer].
2438                                            startTime);
2439                     break;
2440
2441                 default:
2442                     gcmkTRACE_ZONE_N(
2443                         gcvLEVEL_ERROR, gcvZONE_EVENT,
2444                         gcmSIZEOF(record->info.u.TimeStamp.request),
2445                         "Invalid timestamp request: %d",
2446                         record->info.u.TimeStamp.request
2447                         );
2448
2449                     status = gcvSTATUS_INVALID_ARGUMENT;
2450                     break;
2451                 }
2452                 break;
2453
2454 #if gcdVIRTUAL_COMMAND_BUFFER
2455              case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
2456                  gcmkVERIFY_OK(
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)
2461                          ));
2462                  gcmRELEASE_NAME(record->info.u.FreeVirtualCommandBuffer.physical);
2463                  break;
2464 #endif
2465
2466             case gcvHAL_COMMIT_DONE:
2467                 break;
2468
2469             default:
2470                 /* Invalid argument. */
2471                 gcmkTRACE_ZONE_N(
2472                     gcvLEVEL_ERROR, gcvZONE_EVENT,
2473                     gcmSIZEOF(record->info.command),
2474                     "Unknown event type: %d",
2475                     record->info.command
2476                     );
2477
2478                 status = gcvSTATUS_INVALID_ARGUMENT;
2479                 break;
2480             }
2481
2482             /* Make sure there are no errors generated. */
2483             if (gcmIS_ERROR(status))
2484             {
2485                 gcmkTRACE_ZONE_N(
2486                     gcvLEVEL_WARNING, gcvZONE_EVENT,
2487                     gcmSIZEOF(status),
2488                     "Event produced status: %d(%s)",
2489                     status, gckOS_DebugStatus2Name(status));
2490             }
2491
2492             /* Free the event. */
2493             gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record));
2494
2495             /* Advance to next record. */
2496             record = recordNext;
2497         }
2498
2499         gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
2500                        "Handled interrupt 0x%x", mask);
2501     }
2502
2503     if (IDs == 0)
2504     {
2505         gcmkONERROR(_TryToIdleGPU(Event));
2506     }
2507
2508     /* Success. */
2509     gcmkFOOTER_NO();
2510     return gcvSTATUS_OK;
2511
2512 OnError:
2513     if (acquired)
2514     {
2515         /* Release mutex. */
2516         gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2517     }
2518
2519 #if !gcdSMP
2520     if (suspended)
2521     {
2522         /* Resume interrupts. */
2523         gcmkVERIFY_OK(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core));
2524     }
2525 #endif
2526
2527     /* Return the status. */
2528     gcmkFOOTER();
2529     return status;
2530 }
2531
2532 /*******************************************************************************
2533 **  gckEVENT_FreeProcess
2534 **
2535 **  Free all events owned by a particular process ID.
2536 **
2537 **  INPUT:
2538 **
2539 **      gckEVENT Event
2540 **          Pointer to an gckEVENT object.
2541 **
2542 **      gctUINT32 ProcessID
2543 **          Process ID of the process to be freed up.
2544 **
2545 **  OUTPUT:
2546 **
2547 **      Nothing.
2548 */
2549 gceSTATUS
2550 gckEVENT_FreeProcess(
2551     IN gckEVENT Event,
2552     IN gctUINT32 ProcessID
2553     )
2554 {
2555     gctSIZE_T i;
2556     gctBOOL acquired = gcvFALSE;
2557     gcsEVENT_PTR record, next;
2558     gceSTATUS status;
2559     gcsEVENT_PTR deleteHead, deleteTail;
2560
2561     gcmkHEADER_ARG("Event=0x%x ProcessID=%d", Event, ProcessID);
2562
2563     /* Verify the arguments. */
2564     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
2565
2566     /* Walk through all queues. */
2567     for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
2568     {
2569         if (Event->queues[i].head != gcvNULL)
2570         {
2571             /* Grab the event queue mutex. */
2572             gcmkONERROR(gckOS_AcquireMutex(Event->os,
2573                                            Event->eventQueueMutex,
2574                                            gcvINFINITE));
2575             acquired = gcvTRUE;
2576
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;
2583
2584             while (record != gcvNULL)
2585             {
2586                 next = record->next;
2587                 if (record->processID == ProcessID)
2588                 {
2589                     if (deleteHead == gcvNULL)
2590                     {
2591                         deleteHead = record;
2592                     }
2593                     else
2594                     {
2595                         deleteTail->next = record;
2596                     }
2597
2598                     deleteTail = record;
2599                 }
2600                 else
2601                 {
2602                     if (Event->queues[i].head == gcvNULL)
2603                     {
2604                         Event->queues[i].head = record;
2605                     }
2606                     else
2607                     {
2608                         Event->queues[i].tail->next = record;
2609                     }
2610
2611                     Event->queues[i].tail = record;
2612                 }
2613
2614                 record->next = gcvNULL;
2615                 record = next;
2616             }
2617
2618             /* Release the mutex queue. */
2619             gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2620             acquired = gcvFALSE;
2621
2622             /* Loop through the entire list of events. */
2623             for (record = deleteHead; record != gcvNULL; record = next)
2624             {
2625                 /* Get the next event record. */
2626                 next = record->next;
2627
2628                 /* Free the event record. */
2629                 gcmkONERROR(gckEVENT_FreeRecord(Event, record));
2630             }
2631         }
2632     }
2633
2634     gcmkONERROR(_TryToIdleGPU(Event));
2635
2636     /* Success. */
2637     gcmkFOOTER_NO();
2638     return gcvSTATUS_OK;
2639
2640 OnError:
2641     /* Release the event queue mutex. */
2642     if (acquired)
2643     {
2644         gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
2645     }
2646
2647     /* Return the status. */
2648     gcmkFOOTER();
2649     return status;
2650 }
2651
2652 /*******************************************************************************
2653 **  gckEVENT_Stop
2654 **
2655 **  Stop the hardware using the End event mechanism.
2656 **
2657 **  INPUT:
2658 **
2659 **      gckEVENT Event
2660 **          Pointer to an gckEVENT object.
2661 **
2662 **      gctUINT32 ProcessID
2663 **          Process ID Logical belongs.
2664 **
2665 **      gctPHYS_ADDR Handle
2666 **          Physical address handle.  If gcvNULL it is video memory.
2667 **
2668 **      gctPOINTER Logical
2669 **          Logical address to flush.
2670 **
2671 **      gctSIGNAL Signal
2672 **          Pointer to the signal to trigger.
2673 **
2674 **  OUTPUT:
2675 **
2676 **      Nothing.
2677 */
2678 gceSTATUS
2679 gckEVENT_Stop(
2680     IN gckEVENT Event,
2681     IN gctUINT32 ProcessID,
2682     IN gctPHYS_ADDR Handle,
2683     IN gctPOINTER Logical,
2684     IN gctSIGNAL Signal,
2685         IN OUT gctSIZE_T * waitSize
2686     )
2687 {
2688     gceSTATUS status;
2689    /* gctSIZE_T waitSize;*/
2690     gcsEVENT_PTR record;
2691     gctUINT8 id = 0xFF;
2692
2693     gcmkHEADER_ARG("Event=0x%x ProcessID=%u Handle=0x%x Logical=0x%x "
2694                    "Signal=0x%x",
2695                    Event, ProcessID, Handle, Logical, Signal);
2696
2697     /* Verify the arguments. */
2698     gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
2699
2700     /* Submit the current event queue. */
2701     gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE));
2702
2703     gcmkONERROR(gckEVENT_GetEvent(Event, gcvTRUE, &id, gcvKERNEL_PIXEL));
2704
2705     /* Allocate a record. */
2706     gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &record));
2707
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);
2713 #ifdef __QNXNTO__
2714     record->info.u.Signal.coid      = 0;
2715     record->info.u.Signal.rcvid     = 0;
2716 #endif
2717     record->info.u.Signal.auxSignal = 0;
2718     record->info.u.Signal.process   = 0;
2719
2720     /* Append the record. */
2721     Event->queues[id].head      = record;
2722
2723     /* Replace last WAIT with END. */
2724     gcmkONERROR(gckHARDWARE_End(
2725         Event->kernel->hardware, Logical, waitSize
2726         ));
2727
2728 #if gcdNONPAGED_MEMORY_CACHEABLE
2729     /* Flush the cache for the END. */
2730     gcmkONERROR(gckOS_CacheClean(
2731         Event->os,
2732         ProcessID,
2733         gcvNULL,
2734         Handle,
2735         Logical,
2736         *waitSize
2737         ));
2738 #endif
2739
2740     /* Wait for the signal. */
2741     gcmkONERROR(gckOS_WaitSignal(Event->os, Signal, gcvINFINITE));
2742
2743     /* Success. */
2744     gcmkFOOTER_NO();
2745     return gcvSTATUS_OK;
2746
2747 OnError:
2748
2749     /* Return the status. */
2750     gcmkFOOTER();
2751     return status;
2752 }
2753
2754 static void
2755 _PrintRecord(
2756     gcsEVENT_PTR record
2757     )
2758 {
2759     switch (record->info.command)
2760     {
2761     case gcvHAL_FREE_NON_PAGED_MEMORY:
2762         gcmkPRINT("      gcvHAL_FREE_NON_PAGED_MEMORY");
2763             break;
2764
2765     case gcvHAL_FREE_CONTIGUOUS_MEMORY:
2766         gcmkPRINT("      gcvHAL_FREE_CONTIGUOUS_MEMORY");
2767             break;
2768
2769     case gcvHAL_FREE_VIDEO_MEMORY:
2770         gcmkPRINT("      gcvHAL_FREE_VIDEO_MEMORY");
2771             break;
2772
2773     case gcvHAL_WRITE_DATA:
2774         gcmkPRINT("      gcvHAL_WRITE_DATA");
2775        break;
2776
2777     case gcvHAL_UNLOCK_VIDEO_MEMORY:
2778         gcmkPRINT("      gcvHAL_UNLOCK_VIDEO_MEMORY");
2779         break;
2780
2781     case gcvHAL_SIGNAL:
2782         gcmkPRINT("      gcvHAL_SIGNAL process=%d signal=0x%x",
2783                   record->info.u.Signal.process,
2784                   record->info.u.Signal.signal);
2785         break;
2786
2787     case gcvHAL_UNMAP_USER_MEMORY:
2788         gcmkPRINT("      gcvHAL_UNMAP_USER_MEMORY");
2789        break;
2790
2791     case gcvHAL_TIMESTAMP:
2792         gcmkPRINT("      gcvHAL_TIMESTAMP");
2793         break;
2794
2795     case gcvHAL_COMMIT_DONE:
2796         gcmkPRINT("      gcvHAL_COMMIT_DONE");
2797         break;
2798
2799     case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
2800         gcmkPRINT("      gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER logical=0x%08x",
2801                   record->info.u.FreeVirtualCommandBuffer.logical);
2802         break;
2803
2804     default:
2805         gcmkPRINT("      Illegal Event %d", record->info.command);
2806         break;
2807     }
2808 }
2809
2810 /*******************************************************************************
2811 ** gckEVENT_Dump
2812 **
2813 ** Dump record in event queue when stuck happens.
2814 ** No protection for the event queue.
2815 **/
2816 gceSTATUS
2817 gckEVENT_Dump(
2818     IN gckEVENT Event
2819     )
2820 {
2821     gcsEVENT_QUEUE_PTR queueHead = Event->queueHead;
2822     gcsEVENT_QUEUE_PTR queue;
2823     gcsEVENT_PTR record = gcvNULL;
2824     gctINT i;
2825
2826     gcmkHEADER_ARG("Event=0x%x", Event);
2827
2828     gcmkPRINT("**************************\n");
2829     gcmkPRINT("***  EVENT STATE DUMP  ***\n");
2830     gcmkPRINT("**************************\n");
2831
2832
2833     gcmkPRINT("  Unsumbitted Event:");
2834     while(queueHead)
2835     {
2836         queue = queueHead;
2837         record = queueHead->head;
2838
2839         gcmkPRINT("    [%x]:", queue);
2840         while(record)
2841         {
2842             _PrintRecord(record);
2843             record = record->next;
2844         }
2845
2846         if (queueHead == Event->queueTail)
2847         {
2848             queueHead = gcvNULL;
2849         }
2850         else
2851         {
2852             queueHead = queueHead->next;
2853         }
2854     }
2855
2856     gcmkPRINT("  Untriggered Event:");
2857     for (i = 0; i < 30; i++)
2858     {
2859         queue = &Event->queues[i];
2860         record = queue->head;
2861
2862         gcmkPRINT("    [%d]:", i);
2863         while(record)
2864         {
2865             _PrintRecord(record);
2866             record = record->next;
2867         }
2868     }
2869
2870     gcmkFOOTER_NO();
2871     return gcvSTATUS_OK;
2872 }
2873