1 /****************************************************************************
3 * Copyright (C) 2005 - 2011 by Vivante Corp.
4 * Copyright (C) 2011 Freescale Semiconductor, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the license, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *****************************************************************************/
25 #include "gc_hal_kernel_precomp.h"
26 #include "gc_hal_kernel_buffer.h"
30 #include "gc_hal_kernel_qnx.h"
34 #include <asm/atomic.h>
37 #define _GC_OBJ_ZONE gcvZONE_EVENT
39 #define gcdEVENT_ALLOCATION_COUNT (4096 / gcmSIZEOF(gcsHAL_INTERFACE))
40 #define gcdEVENT_MIN_THRESHOLD 4
42 /******************************************************************************\
43 ********************************* Support Code *********************************
44 \******************************************************************************/
47 gckEVENT_AllocateQueue(
49 OUT gcsEVENT_QUEUE_PTR
* Queue
54 gcmkHEADER_ARG("Event=0x%x", Event
);
56 /* Verify the arguments. */
57 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
58 gcmkVERIFY_ARGUMENT(Queue
!= gcvNULL
);
60 /* Do we have free queues? */
61 if (Event
->freeList
== gcvNULL
)
63 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES
);
66 /* Move one free queue from the free list. */
67 * Queue
= Event
->freeList
;
68 Event
->freeList
= Event
->freeList
->next
;
71 gcmkFOOTER_ARG("*Queue=0x%x", gcmOPT_POINTER(Queue
));
75 /* Return the status. */
83 OUT gcsEVENT_QUEUE_PTR Queue
86 gceSTATUS status
= gcvSTATUS_OK
;
88 gcmkHEADER_ARG("Event=0x%x", Event
);
90 /* Verify the arguments. */
91 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
92 gcmkVERIFY_ARGUMENT(Queue
!= gcvNULL
);
94 /* Move one free queue from the free list. */
95 Queue
->next
= Event
->freeList
;
96 Event
->freeList
= Queue
;
106 IN gcsEVENT_PTR Record
110 gctBOOL acquired
= gcvFALSE
;
112 gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event
, Record
);
114 /* Verify the arguments. */
115 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
116 gcmkVERIFY_ARGUMENT(Record
!= gcvNULL
);
118 /* Acquire the mutex. */
119 gcmkONERROR(gckOS_AcquireMutex(Event
->os
,
120 Event
->freeEventMutex
,
124 /* Push the record on the free list. */
125 Record
->next
= Event
->freeEventList
;
126 Event
->freeEventList
= Record
;
127 Event
->freeEventCount
+= 1;
129 /* Release the mutex. */
130 gcmkONERROR(gckOS_ReleaseMutex(Event
->os
, Event
->freeEventMutex
));
140 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event
->os
, Event
->freeEventMutex
));
143 /* Return the status. */
153 OUT gctBOOL_PTR IsEmpty
159 gcmkHEADER_ARG("Event=0x%x", Event
);
161 /* Verify the arguments. */
162 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
163 gcmkVERIFY_ARGUMENT(IsEmpty
!= gcvNULL
);
165 /* Assume the event queue is empty. */
168 /* Walk the event queue. */
169 for (i
= 0; i
< gcmCOUNTOF(Event
->queues
); ++i
)
171 /* Check whether this event is in use. */
172 if (Event
->queues
[i
].head
!= gcvNULL
)
174 /* The event is in use, hence the queue is not empty. */
180 /* Try acquiring the mutex. */
181 status
= gckOS_AcquireMutex(Event
->os
, Event
->eventQueueMutex
, 0);
182 if (status
== gcvSTATUS_TIMEOUT
)
184 /* Timeout - queue is no longer empty. */
189 /* Bail out on error. */
192 /* Release the mutex. */
193 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event
->os
, Event
->eventQueueMutex
));
197 gcmkFOOTER_ARG("*IsEmpty=%d", gcmOPT_VALUE(IsEmpty
));
201 /* Return the status. */
209 __RemoveRecordFromProcessDB(
211 IN gcsEVENT_PTR Record
214 gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event
, Record
);
215 gcmkVERIFY_ARGUMENT(Record
!= gcvNULL
);
217 while (Record
!= gcvNULL
)
219 switch (Record
->info
.command
)
221 case gcvHAL_FREE_NON_PAGED_MEMORY
:
222 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
226 Record
->info
.u
.FreeNonPagedMemory
.logical
));
229 case gcvHAL_FREE_CONTIGUOUS_MEMORY
:
230 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
234 Record
->info
.u
.FreeContiguousMemory
.logical
));
237 case gcvHAL_FREE_VIDEO_MEMORY
:
238 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
242 Record
->info
.u
.FreeVideoMemory
.node
));
245 case gcvHAL_UNLOCK_VIDEO_MEMORY
:
246 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
249 gcvDB_VIDEO_MEMORY_LOCKED
,
250 Record
->info
.u
.UnlockVideoMemory
.node
));
257 Record
= Record
->next
;
266 OUT gctBOOL_PTR IsEmpty
272 gcmkHEADER_ARG("Event=0x%x", Event
);
274 /* Verify the arguments. */
275 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
276 gcmkVERIFY_ARGUMENT(IsEmpty
!= gcvNULL
);
278 /* Assume the event queue is empty. */
281 /* Walk the event queue. */
282 for (i
= 0; i
< gcmCOUNTOF(Event
->queues
); ++i
)
284 /* Check whether this event is in use. */
285 if (Event
->queues
[i
].head
!= gcvNULL
)
287 /* The event is in use, hence the queue is not empty. */
293 /* Try acquiring the mutex. */
294 status
= gckOS_AcquireMutex(Event
->os
, Event
->eventQueueMutex
, 0);
295 if (status
== gcvSTATUS_TIMEOUT
)
297 /* Timeout - queue is no longer empty. */
302 /* Bail out on error. */
305 /* Release the mutex. */
306 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event
->os
, Event
->eventQueueMutex
));
310 gcmkFOOTER_ARG("*IsEmpty=%d", gcmOPT_VALUE(IsEmpty
));
314 /* Return the status. */
319 /******************************************************************************\
320 ******************************* gckEVENT API Code *******************************
321 \******************************************************************************/
323 /*******************************************************************************
325 ** gckEVENT_Construct
327 ** Construct a new gckEVENT object.
332 ** Pointer to an gckKERNEL object.
337 ** Pointer to a variable that receives the gckEVENT object pointer.
347 gckEVENT eventObj
= gcvNULL
;
350 gctPOINTER pointer
= gcvNULL
;
352 gcmkHEADER_ARG("Kernel=0x%x", Kernel
);
354 /* Verify the arguments. */
355 gcmkVERIFY_OBJECT(Kernel
, gcvOBJ_KERNEL
);
356 gcmkVERIFY_ARGUMENT(Event
!= gcvNULL
);
358 /* Extract the pointer to the gckOS object. */
360 gcmkVERIFY_OBJECT(os
, gcvOBJ_OS
);
362 /* Allocate the gckEVENT object. */
363 gcmkONERROR(gckOS_Allocate(os
, gcmSIZEOF(struct _gckEVENT
), &pointer
));
367 /* Reset the object. */
368 gcmkVERIFY_OK(gckOS_ZeroMemory(eventObj
, gcmSIZEOF(struct _gckEVENT
)));
370 /* Initialize the gckEVENT object. */
371 eventObj
->object
.type
= gcvOBJ_EVENT
;
372 eventObj
->kernel
= Kernel
;
375 /* Create the mutexes. */
376 gcmkONERROR(gckOS_CreateMutex(os
, &eventObj
->eventQueueMutex
));
377 gcmkONERROR(gckOS_CreateMutex(os
, &eventObj
->freeEventMutex
));
378 gcmkONERROR(gckOS_CreateMutex(os
, &eventObj
->eventListMutex
));
380 /* Create a bunch of event reccords. */
381 for (i
= 0; i
< gcdEVENT_ALLOCATION_COUNT
; i
+= 1)
383 /* Allocate an event record. */
384 gcmkONERROR(gckOS_Allocate(os
, gcmSIZEOF(gcsEVENT
), &pointer
));
388 /* Push it on the free list. */
389 record
->next
= eventObj
->freeEventList
;
390 eventObj
->freeEventList
= record
;
391 eventObj
->freeEventCount
+= 1;
394 /* Initialize the free list of event queues. */
395 for (i
= 0; i
< gcdREPO_LIST_COUNT
; i
+= 1)
397 eventObj
->repoList
[i
].next
= eventObj
->freeList
;
398 eventObj
->freeList
= &eventObj
->repoList
[i
];
401 /* Construct the atom. */
402 gcmkONERROR(gckOS_AtomConstruct(os
, &eventObj
->freeAtom
));
403 gcmkONERROR(gckOS_AtomSet(os
,
405 gcmCOUNTOF(eventObj
->queues
)));
407 /* Return pointer to the gckEVENT object. */
411 gcmkFOOTER_ARG("*Event=0x%x", *Event
);
416 if (eventObj
!= gcvNULL
)
418 if (eventObj
->eventQueueMutex
!= gcvNULL
)
420 gcmkVERIFY_OK(gckOS_DeleteMutex(os
, eventObj
->eventQueueMutex
));
423 if (eventObj
->freeEventMutex
!= gcvNULL
)
425 gcmkVERIFY_OK(gckOS_DeleteMutex(os
, eventObj
->freeEventMutex
));
428 if (eventObj
->eventListMutex
!= gcvNULL
)
430 gcmkVERIFY_OK(gckOS_DeleteMutex(os
, eventObj
->eventListMutex
));
433 while (eventObj
->freeEventList
!= gcvNULL
)
435 record
= eventObj
->freeEventList
;
436 eventObj
->freeEventList
= record
->next
;
438 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os
, record
));
441 if (eventObj
->freeAtom
!= gcvNULL
)
443 gcmkVERIFY_OK(gckOS_AtomDestroy(os
, eventObj
->freeAtom
));
446 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os
, eventObj
));
449 /* Return the status. */
454 /*******************************************************************************
458 ** Destroy an gckEVENT object.
463 ** Pointer to an gckEVENT object.
475 gcsEVENT_QUEUE_PTR queue
;
477 gcmkHEADER_ARG("Event=0x%x", Event
);
479 /* Verify the arguments. */
480 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
482 /* Delete the queue mutex. */
483 gcmkVERIFY_OK(gckOS_DeleteMutex(Event
->os
, Event
->eventQueueMutex
));
485 /* Free all free events. */
486 while (Event
->freeEventList
!= gcvNULL
)
488 record
= Event
->freeEventList
;
489 Event
->freeEventList
= record
->next
;
491 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event
->os
, record
));
494 /* Delete the free mutex. */
495 gcmkVERIFY_OK(gckOS_DeleteMutex(Event
->os
, Event
->freeEventMutex
));
497 /* Free all pending queues. */
498 while (Event
->queueHead
!= gcvNULL
)
500 /* Get the current queue. */
501 queue
= Event
->queueHead
;
503 /* Free all pending events. */
504 while (queue
->head
!= gcvNULL
)
506 record
= queue
->head
;
507 queue
->head
= record
->next
;
510 gcvLEVEL_WARNING
, gcvZONE_EVENT
,
511 gcmSIZEOF(record
) + gcmSIZEOF(queue
->source
),
512 "Event record 0x%x is still pending for %d.",
513 record
, queue
->source
516 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event
->os
, record
));
519 /* Remove the top queue from the list. */
520 if (Event
->queueHead
== Event
->queueTail
)
523 Event
->queueTail
= gcvNULL
;
527 Event
->queueHead
= Event
->queueHead
->next
;
530 /* Free the queue. */
531 gcmkVERIFY_OK(gckEVENT_FreeQueue(Event
, queue
));
534 /* Delete the list mutex. */
535 gcmkVERIFY_OK(gckOS_DeleteMutex(Event
->os
, Event
->eventListMutex
));
537 /* Delete the atom. */
538 gcmkVERIFY_OK(gckOS_AtomDestroy(Event
->os
, Event
->freeAtom
));
540 /* Mark the gckEVENT object as unknown. */
541 Event
->object
.type
= gcvOBJ_UNKNOWN
;
543 /* Free the gckEVENT object. */
544 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event
->os
, Event
));
551 /*******************************************************************************
555 ** Reserve the next available hardware event.
560 ** Pointer to an gckEVENT object.
563 ** Set to gcvTRUE to force the function to wait if no events are
564 ** immediately available.
566 ** gceKERNEL_WHERE Source
567 ** Source of the event.
571 ** gctUINT8 * EventID
572 ** Reserved event ID.
578 OUT gctUINT8
* EventID
,
579 IN gceKERNEL_WHERE Source
584 gctBOOL acquired
= gcvFALSE
;
585 gctBOOL suspended
= gcvFALSE
;
592 gcmkHEADER_ARG("Event=0x%x Source=%d", Event
, Source
);
596 /* Grab the queue mutex. */
597 gcmkONERROR(gckOS_AcquireMutex(Event
->os
,
598 Event
->eventQueueMutex
,
602 /* Walk through all events. */
604 for (i
= 0; i
< gcmCOUNTOF(Event
->queues
); ++i
)
606 gctINT nextID
= gckMATH_ModuloInt((id
+ 1),
607 gcmCOUNTOF(Event
->queues
));
609 if (Event
->queues
[id
].head
== gcvNULL
)
611 *EventID
= (gctUINT8
) id
;
613 Event
->lastID
= (gctUINT8
) nextID
;
615 /* Save time stamp of event. */
616 Event
->queues
[id
].stamp
= ++(Event
->stamp
);
617 Event
->queues
[id
].source
= Source
;
619 gcmkONERROR(gckOS_AtomDecrement(Event
->os
,
623 if (free
<= gcdDYNAMIC_EVENT_THRESHOLD
)
625 gcmkONERROR(gckOS_BroadcastHurry(
627 Event
->kernel
->hardware
,
628 gcdDYNAMIC_EVENT_THRESHOLD
- free
));
632 /* Release the queue mutex. */
633 gcmkONERROR(gckOS_ReleaseMutex(Event
->os
,
634 Event
->eventQueueMutex
));
638 gcvLEVEL_INFO
, gcvZONE_EVENT
,
644 gcmkFOOTER_ARG("*EventID=%u", *EventID
);
652 /* No free events, speed up the GPU right now! */
653 gcmkONERROR(gckOS_BroadcastHurry(Event
->os
,
654 Event
->kernel
->hardware
,
655 gcdDYNAMIC_EVENT_THRESHOLD
));
658 /* Release the queue mutex. */
659 gcmkONERROR(gckOS_ReleaseMutex(Event
->os
, Event
->eventQueueMutex
));
662 /* Fail if wait is not requested. */
665 /* Out of resources. */
666 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES
);
670 gcmkONERROR(gckOS_Delay(Event
->os
, 1));
673 /* Increment the wait timer. */
676 if (timer
== gcdGPU_TIMEOUT
)
678 /* Suspend interrupts. */
679 gcmkONERROR(gckOS_SuspendInterrupt(Event
->os
));
682 /* Try to call any outstanding events. */
683 gcmkONERROR(gckHARDWARE_Interrupt(Event
->kernel
->hardware
,
686 /* Resume interrupts. */
687 gcmkONERROR(gckOS_ResumeInterrupt(Event
->os
));
688 suspended
= gcvFALSE
;
691 else if (timer
> gcdGPU_TIMEOUT
)
695 gcmSIZEOF(gctCONST_STRING
) + gcmSIZEOF(gctINT
),
696 "%s(%d): no available events\n",
697 __FUNCTION__
, __LINE__
700 /* Broadcast GPU stuck. */
701 gcmkONERROR(gckOS_Broadcast(Event
->os
,
702 Event
->kernel
->hardware
,
703 gcvBROADCAST_GPU_STUCK
));
706 gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING
);
714 /* Release the queue mutex. */
715 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event
->os
, Event
->eventQueueMutex
));
720 /* Resume interrupts. */
721 gcmkVERIFY_OK(gckOS_ResumeInterrupt(Event
->os
));
724 /* Return the status. */
729 /*******************************************************************************
731 ** gckEVENT_AllocateRecord
733 ** Allocate a record for the new event.
738 ** Pointer to an gckEVENT object.
740 ** gctBOOL AllocateAllowed
741 ** State for allocation if out of free events.
745 ** gcsEVENT_PTR * Record
746 ** Allocated event record.
749 gckEVENT_AllocateRecord(
751 IN gctBOOL AllocateAllowed
,
752 OUT gcsEVENT_PTR
* Record
756 gctBOOL acquired
= gcvFALSE
;
759 gctPOINTER pointer
= gcvNULL
;
761 gcmkHEADER_ARG("Event=0x%x AllocateAllowed=%d", Event
, AllocateAllowed
);
763 /* Verify the arguments. */
764 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
765 gcmkVERIFY_ARGUMENT(Record
!= gcvNULL
);
767 /* Test if we are below the allocation threshold. */
768 if (AllocateAllowed
&& (Event
->freeEventCount
< gcdEVENT_MIN_THRESHOLD
))
770 /* Allocate a bunch of records. */
771 for (i
= 0; i
< gcdEVENT_ALLOCATION_COUNT
; i
+= 1)
773 /* Allocate an event record. */
774 gcmkONERROR(gckOS_Allocate(Event
->os
,
780 /* Acquire the mutex. */
781 gcmkONERROR(gckOS_AcquireMutex(Event
->os
, Event
->freeEventMutex
, gcvINFINITE
));
784 /* Push it on the free list. */
785 record
->next
= Event
->freeEventList
;
786 Event
->freeEventList
= record
;
787 Event
->freeEventCount
+= 1;
789 /* Release the mutex. */
790 gcmkONERROR(gckOS_ReleaseMutex(Event
->os
, Event
->freeEventMutex
));
795 /* Acquire the mutex. */
796 gcmkONERROR(gckOS_AcquireMutex(Event
->os
, Event
->freeEventMutex
, gcvINFINITE
));
799 *Record
= Event
->freeEventList
;
800 Event
->freeEventList
= Event
->freeEventList
->next
;
801 Event
->freeEventCount
-= 1;
803 /* Release the mutex. */
804 gcmkONERROR(gckOS_ReleaseMutex(Event
->os
, Event
->freeEventMutex
));
808 gcmkFOOTER_ARG("*Record=0x%x", gcmOPT_POINTER(Record
));
815 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event
->os
, Event
->freeEventMutex
));
818 /* Return the status. */
823 /*******************************************************************************
827 ** Add a new event to the list of events.
832 ** Pointer to an gckEVENT object.
834 ** gcsHAL_INTERFACE_PTR Interface
835 ** Pointer to the interface for the event to be added.
837 ** gceKERNEL_WHERE FromWhere
838 ** Place in the pipe where the event needs to be generated.
840 ** gctBOOL AllocateAllowed
841 ** State for allocation if out of free events.
850 IN gcsHAL_INTERFACE_PTR Interface
,
851 IN gceKERNEL_WHERE FromWhere
,
852 IN gctBOOL AllocateAllowed
856 gctBOOL acquired
= gcvFALSE
;
857 gcsEVENT_PTR record
= gcvNULL
;
858 gcsEVENT_QUEUE_PTR queue
;
860 gcmkHEADER_ARG("Event=0x%x Interface=0x%x FromWhere=%d AllocateAllowed=%d",
861 Event
, Interface
, FromWhere
, AllocateAllowed
);
863 /* Verify the arguments. */
864 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
865 gcmkVERIFY_ARGUMENT(Interface
!= gcvNULL
);
867 /* Verify the event command. */
869 ( (Interface
->command
== gcvHAL_FREE_NON_PAGED_MEMORY
)
870 || (Interface
->command
== gcvHAL_FREE_CONTIGUOUS_MEMORY
)
871 || (Interface
->command
== gcvHAL_FREE_VIDEO_MEMORY
)
872 || (Interface
->command
== gcvHAL_WRITE_DATA
)
873 || (Interface
->command
== gcvHAL_UNLOCK_VIDEO_MEMORY
)
874 || (Interface
->command
== gcvHAL_SIGNAL
)
875 || (Interface
->command
== gcvHAL_UNMAP_USER_MEMORY
)
876 || (Interface
->command
== gcvHAL_TIMESTAMP
)
879 /* Validate the source. */
880 if ((FromWhere
!= gcvKERNEL_COMMAND
) && (FromWhere
!= gcvKERNEL_PIXEL
))
882 /* Invalid argument. */
883 gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT
);
886 /* Allocate a free record. */
887 gcmkONERROR(gckEVENT_AllocateRecord(Event
, AllocateAllowed
, &record
));
889 /* Termninate the record. */
890 record
->next
= gcvNULL
;
892 /* Copy the event interface into the record. */
893 gcmkONERROR(gckOS_MemCopy(&record
->info
, Interface
, gcmSIZEOF(record
->info
)));
895 /* Get process ID. */
896 gcmkONERROR(gckOS_GetProcessID(&record
->processID
));
899 record
->kernel
= Event
->kernel
;
902 /* Acquire the mutex. */
903 gcmkONERROR(gckOS_AcquireMutex(Event
->os
, Event
->eventListMutex
, gcvINFINITE
));
906 /* Do we need to allocate a new queue? */
907 if ((Event
->queueTail
== gcvNULL
) || (Event
->queueTail
->source
!= FromWhere
))
909 /* Allocate a new queue. */
910 gcmkONERROR(gckEVENT_AllocateQueue(Event
, &queue
));
912 /* Initialize the queue. */
913 queue
->source
= FromWhere
;
914 queue
->head
= gcvNULL
;
915 queue
->next
= gcvNULL
;
917 /* Attach it to the list of alloicated queues. */
918 if (Event
->queueTail
== gcvNULL
)
921 Event
->queueTail
= queue
;
925 Event
->queueTail
->next
= queue
;
926 Event
->queueTail
= queue
;
931 queue
= Event
->queueTail
;
934 /* Attach the record to the queue. */
935 if (queue
->head
== gcvNULL
)
937 queue
->head
= record
;
938 queue
->tail
= record
;
942 queue
->tail
->next
= record
;
943 queue
->tail
= record
;
946 /* Release the mutex. */
947 gcmkONERROR(gckOS_ReleaseMutex(Event
->os
, Event
->eventListMutex
));
957 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event
->os
, Event
->eventListMutex
));
960 if (record
!= gcvNULL
)
962 gcmkVERIFY_OK(gckEVENT_FreeRecord(Event
, record
));
965 /* Return the status. */
970 /*******************************************************************************
974 ** Schedule an event to unlock virtual memory.
979 ** Pointer to an gckEVENT object.
981 ** gceKERNEL_WHERE FromWhere
982 ** Place in the pipe where the event needs to be generated.
984 ** gcuVIDMEM_NODE_PTR Node
985 ** Pointer to a gcuVIDMEM_NODE union that specifies the virtual memory
989 ** Type of surface to unlock.
998 IN gceKERNEL_WHERE FromWhere
,
999 IN gcuVIDMEM_NODE_PTR Node
,
1000 IN gceSURF_TYPE Type
1004 gcsHAL_INTERFACE iface
;
1006 gcmkHEADER_ARG("Event=0x%x FromWhere=%d Node=0x%x Type=%d",
1007 Event
, FromWhere
, Node
, Type
);
1009 /* Verify the arguments. */
1010 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
1011 gcmkVERIFY_ARGUMENT(Node
!= gcvNULL
);
1013 /* Mark the event as an unlock. */
1014 iface
.command
= gcvHAL_UNLOCK_VIDEO_MEMORY
;
1015 iface
.u
.UnlockVideoMemory
.node
= Node
;
1016 iface
.u
.UnlockVideoMemory
.type
= Type
;
1017 iface
.u
.UnlockVideoMemory
.asynchroneous
= 0;
1019 /* Append it to the queue. */
1020 gcmkONERROR(gckEVENT_AddList(Event
, &iface
, FromWhere
, gcvFALSE
));
1024 return gcvSTATUS_OK
;
1027 /* Return the status. */
1032 /*******************************************************************************
1034 ** gckEVENT_FreeVideoMemory
1036 ** Schedule an event to free video memory.
1041 ** Pointer to an gckEVENT object.
1043 ** gcuVIDMEM_NODE_PTR VideoMemory
1044 ** Pointer to a gcuVIDMEM_NODE object to free.
1046 ** gceKERNEL_WHERE FromWhere
1047 ** Place in the pipe where the event needs to be generated.
1054 gckEVENT_FreeVideoMemory(
1056 IN gcuVIDMEM_NODE_PTR VideoMemory
,
1057 IN gceKERNEL_WHERE FromWhere
1061 gcsHAL_INTERFACE iface
;
1063 gcmkHEADER_ARG("Event=0x%x VideoMemory=0x%x FromWhere=%d",
1064 Event
, VideoMemory
, FromWhere
);
1066 /* Verify the arguments. */
1067 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
1068 gcmkVERIFY_ARGUMENT(VideoMemory
!= gcvNULL
);
1070 /* Create an event. */
1071 iface
.command
= gcvHAL_FREE_VIDEO_MEMORY
;
1072 iface
.u
.FreeVideoMemory
.node
= VideoMemory
;
1074 /* Append it to the queue. */
1075 gcmkONERROR(gckEVENT_AddList(Event
, &iface
, FromWhere
, gcvFALSE
));
1079 return gcvSTATUS_OK
;
1082 /* Return the status. */
1087 /*******************************************************************************
1089 ** gckEVENT_FreeNonPagedMemory
1091 ** Schedule an event to free non-paged memory.
1096 ** Pointer to an gckEVENT object.
1099 ** Number of bytes of non-paged memory to free.
1101 ** gctPHYS_ADDR Physical
1102 ** Physical address of non-paged memory to free.
1104 ** gctPOINTER Logical
1105 ** Logical address of non-paged memory to free.
1107 ** gceKERNEL_WHERE FromWhere
1108 ** Place in the pipe where the event needs to be generated.
1111 gckEVENT_FreeNonPagedMemory(
1114 IN gctPHYS_ADDR Physical
,
1115 IN gctPOINTER Logical
,
1116 IN gceKERNEL_WHERE FromWhere
1120 gcsHAL_INTERFACE iface
;
1122 gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
1124 Event
, Bytes
, Physical
, Logical
, FromWhere
);
1126 /* Verify the arguments. */
1127 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
1128 gcmkVERIFY_ARGUMENT(Physical
!= gcvNULL
);
1129 gcmkVERIFY_ARGUMENT(Logical
!= gcvNULL
);
1130 gcmkVERIFY_ARGUMENT(Bytes
> 0);
1132 /* Create an event. */
1133 iface
.command
= gcvHAL_FREE_NON_PAGED_MEMORY
;
1134 iface
.u
.FreeNonPagedMemory
.bytes
= Bytes
;
1135 iface
.u
.FreeNonPagedMemory
.physical
= Physical
;
1136 iface
.u
.FreeNonPagedMemory
.logical
= Logical
;
1138 /* Append it to the queue. */
1139 gcmkONERROR(gckEVENT_AddList(Event
, &iface
, FromWhere
, gcvFALSE
));
1143 return gcvSTATUS_OK
;
1146 /* Return the status. */
1151 /*******************************************************************************
1153 ** gckEVENT_FreeContigiuousMemory
1155 ** Schedule an event to free contiguous memory.
1160 ** Pointer to an gckEVENT object.
1163 ** Number of bytes of contiguous memory to free.
1165 ** gctPHYS_ADDR Physical
1166 ** Physical address of contiguous memory to free.
1168 ** gctPOINTER Logical
1169 ** Logical address of contiguous memory to free.
1171 ** gceKERNEL_WHERE FromWhere
1172 ** Place in the pipe where the event needs to be generated.
1175 gckEVENT_FreeContiguousMemory(
1178 IN gctPHYS_ADDR Physical
,
1179 IN gctPOINTER Logical
,
1180 IN gceKERNEL_WHERE FromWhere
1184 gcsHAL_INTERFACE iface
;
1186 gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
1188 Event
, Bytes
, Physical
, Logical
, FromWhere
);
1190 /* Verify the arguments. */
1191 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
1192 gcmkVERIFY_ARGUMENT(Physical
!= gcvNULL
);
1193 gcmkVERIFY_ARGUMENT(Logical
!= gcvNULL
);
1194 gcmkVERIFY_ARGUMENT(Bytes
> 0);
1196 /* Create an event. */
1197 iface
.command
= gcvHAL_FREE_CONTIGUOUS_MEMORY
;
1198 iface
.u
.FreeContiguousMemory
.bytes
= Bytes
;
1199 iface
.u
.FreeContiguousMemory
.physical
= Physical
;
1200 iface
.u
.FreeContiguousMemory
.logical
= Logical
;
1202 /* Append it to the queue. */
1203 gcmkONERROR(gckEVENT_AddList(Event
, &iface
, FromWhere
, gcvFALSE
));
1207 return gcvSTATUS_OK
;
1210 /* Return the status. */
1215 /*******************************************************************************
1219 ** Schedule an event to trigger a signal.
1224 ** Pointer to an gckEVENT object.
1227 ** Pointer to the signal to trigger.
1229 ** gceKERNEL_WHERE FromWhere
1230 ** Place in the pipe where the event needs to be generated.
1239 IN gctSIGNAL Signal
,
1240 IN gceKERNEL_WHERE FromWhere
1244 gcsHAL_INTERFACE iface
;
1246 gcmkHEADER_ARG("Event=0x%x Signal=0x%x FromWhere=%d",
1247 Event
, Signal
, FromWhere
);
1249 /* Verify the arguments. */
1250 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
1251 gcmkVERIFY_ARGUMENT(Signal
!= gcvNULL
);
1253 /* Mark the event as a signal. */
1254 iface
.command
= gcvHAL_SIGNAL
;
1255 iface
.u
.Signal
.signal
= Signal
;
1257 iface
.u
.Signal
.coid
= 0;
1258 iface
.u
.Signal
.rcvid
= 0;
1260 iface
.u
.Signal
.auxSignal
= gcvNULL
;
1261 iface
.u
.Signal
.process
= gcvNULL
;
1263 /* Append it to the queue. */
1264 gcmkONERROR(gckEVENT_AddList(Event
, &iface
, FromWhere
, gcvFALSE
));
1268 return gcvSTATUS_OK
;
1271 /* Return the status. */
1276 /*******************************************************************************
1280 ** Submit the current event queue to the GPU.
1285 ** Pointer to an gckEVENT object.
1288 ** Submit requires one vacant event; if Wait is set to not zero,
1289 ** and there are no vacant events at this time, the function will
1290 ** wait until an event becomes vacant so that submission of the
1291 ** queue is successful.
1293 ** gctBOOL FromPower
1294 ** Determines whether the call originates from inside the power
1295 ** management or not.
1305 IN gctBOOL FromPower
1310 gcsEVENT_QUEUE_PTR queue
;
1311 gctBOOL acquired
= gcvFALSE
;
1316 gckCOMMAND command
= gcvNULL
;
1317 gctBOOL commitEntered
= gcvFALSE
;
1320 gcmkHEADER_ARG("Event=0x%x Wait=%d", Event
, Wait
);
1323 /* Get gckCOMMAND object. */
1324 command
= Event
->kernel
->command
;
1327 /* Are there event queues? */
1328 if (Event
->queueHead
!= gcvNULL
)
1331 /* Acquire the command queue. */
1332 gcmkONERROR(gckCOMMAND_EnterCommit(command
, FromPower
));
1333 commitEntered
= gcvTRUE
;
1336 /* Process all queues. */
1337 while (Event
->queueHead
!= gcvNULL
)
1339 /* Acquire the list mutex. */
1340 gcmkONERROR(gckOS_AcquireMutex(Event
->os
,
1341 Event
->eventListMutex
,
1345 /* Get the current queue. */
1346 queue
= Event
->queueHead
;
1348 /* Allocate an event ID. */
1349 gcmkONERROR(gckEVENT_GetEvent(Event
, Wait
, &id
, queue
->source
));
1351 /* Copy event list to event ID queue. */
1352 Event
->queues
[id
].source
= queue
->source
;
1353 Event
->queues
[id
].head
= queue
->head
;
1355 /* Remove the top queue from the list. */
1356 if (Event
->queueHead
== Event
->queueTail
)
1358 Event
->queueHead
= gcvNULL
;
1359 Event
->queueTail
= gcvNULL
;
1363 Event
->queueHead
= Event
->queueHead
->next
;
1366 /* Free the queue. */
1367 gcmkONERROR(gckEVENT_FreeQueue(Event
, queue
));
1369 /* Release the list mutex. */
1370 gcmkONERROR(gckOS_ReleaseMutex(Event
->os
, Event
->eventListMutex
));
1371 acquired
= gcvFALSE
;
1373 gcmkONERROR(__RemoveRecordFromProcessDB(Event
,
1374 Event
->queues
[id
].head
));
1377 /* Notify immediately on infinite hardware. */
1378 gcmkONERROR(gckEVENT_Interrupt(Event
, 1 << id
));
1380 gcmkONERROR(gckEVENT_Notify(Event
, 0));
1382 /* Get the size of the hardware event. */
1383 gcmkONERROR(gckHARDWARE_Event(Event
->kernel
->hardware
,
1389 /* Reserve space in the command queue. */
1390 gcmkONERROR(gckCOMMAND_Reserve(command
,
1395 /* Set the hardware event in the command queue. */
1396 gcmkONERROR(gckHARDWARE_Event(Event
->kernel
->hardware
,
1399 Event
->queues
[id
].source
,
1402 /* Execute the hardware event. */
1403 gcmkONERROR(gckCOMMAND_Execute(command
, bytes
));
1408 /* Release the command queue. */
1409 gcmkONERROR(gckCOMMAND_ExitCommit(command
, FromPower
));
1410 commitEntered
= gcvFALSE
;
1416 return gcvSTATUS_OK
;
1422 /* Release the command queue mutex. */
1423 gcmkVERIFY_OK(gckCOMMAND_ExitCommit(command
, FromPower
));
1429 /* Need to unroll the mutex acquire. */
1430 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event
->os
, Event
->eventListMutex
));
1435 /* Need to unroll the event allocation. */
1436 Event
->queues
[id
].head
= gcvNULL
;
1439 /* Return the status. */
1444 /*******************************************************************************
1448 ** Commit an event queue from the user.
1453 ** Pointer to an gckEVENT object.
1455 ** gcsQUEUE_PTR Queue
1456 ** User event queue.
1465 IN gcsQUEUE_PTR Queue
1469 gcsQUEUE_PTR record
= gcvNULL
, next
;
1470 gctUINT32 processID
;
1471 gctBOOL needCopy
= gcvFALSE
;
1473 gcmkHEADER_ARG("Event=0x%x Queue=0x%x", Event
, Queue
);
1475 /* Verify the arguments. */
1476 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
1478 /* Get the current process ID. */
1479 gcmkONERROR(gckOS_GetProcessID(&processID
));
1481 /* Query if we need to copy the client data. */
1482 gcmkONERROR(gckOS_QueryNeedCopy(Event
->os
, processID
, &needCopy
));
1484 /* Loop while there are records in the queue. */
1485 while (Queue
!= gcvNULL
)
1491 /* Point to stack record. */
1494 /* Copy the data from the client. */
1495 gcmkONERROR(gckOS_CopyFromUserData(Event
->os
,
1498 gcmSIZEOF(gcsQUEUE
)));
1502 gctPOINTER pointer
= gcvNULL
;
1504 /* Map record into kernel memory. */
1505 gcmkONERROR(gckOS_MapUserPointer(Event
->os
,
1507 gcmSIZEOF(gcsQUEUE
),
1513 /* Append event record to event queue. */
1515 gckEVENT_AddList(Event
, &record
->iface
, gcvKERNEL_PIXEL
, gcvTRUE
));
1517 /* Next record in the queue. */
1518 next
= record
->next
;
1522 /* Unmap record from kernel memory. */
1524 gckOS_UnmapUserPointer(Event
->os
,
1526 gcmSIZEOF(gcsQUEUE
),
1527 (gctPOINTER
*) record
));
1534 /* Submit the event list. */
1535 gcmkONERROR(gckEVENT_Submit(Event
, gcvTRUE
, gcvFALSE
));
1539 return gcvSTATUS_OK
;
1542 if ((record
!= gcvNULL
) && !needCopy
)
1545 gcmkVERIFY_OK(gckOS_UnmapUserPointer(Event
->os
,
1547 gcmSIZEOF(gcsQUEUE
),
1548 (gctPOINTER
*) record
));
1551 /* Return the status. */
1556 /*******************************************************************************
1560 ** Schedule a composition event and start a composition.
1565 ** Pointer to an gckEVENT object.
1567 ** gcsHAL_COMPOSE_PTR Info
1568 ** Pointer to the composition structure.
1577 IN gcsHAL_COMPOSE_PTR Info
1581 gcsEVENT_PTR headRecord
;
1582 gcsEVENT_PTR tailRecord
;
1583 gcsEVENT_PTR tempRecord
;
1585 gctUINT32 processID
;
1587 gcmkHEADER_ARG("Event=0x%x Info=0x%x", Event
, Info
);
1589 /* Verify the arguments. */
1590 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
1591 gcmkVERIFY_ARGUMENT(Info
!= gcvNULL
);
1593 /* Allocate an event ID. */
1594 gcmkONERROR(gckEVENT_GetEvent(Event
, gcvTRUE
, &id
, gcvKERNEL_PIXEL
));
1596 /* Get process ID. */
1597 gcmkONERROR(gckOS_GetProcessID(&processID
));
1599 /* Allocate a record. */
1600 gcmkONERROR(gckEVENT_AllocateRecord(Event
, gcvTRUE
, &tempRecord
));
1601 headRecord
= tailRecord
= tempRecord
;
1603 /* Initialize the record. */
1604 tempRecord
->info
.command
= gcvHAL_SIGNAL
;
1605 tempRecord
->info
.u
.Signal
.process
= Info
->process
;
1607 tempRecord
->info
.u
.Signal
.coid
= Info
->coid
;
1608 tempRecord
->info
.u
.Signal
.rcvid
= Info
->rcvid
;
1610 tempRecord
->info
.u
.Signal
.signal
= Info
->signal
;
1611 tempRecord
->info
.u
.Signal
.auxSignal
= gcvNULL
;
1612 tempRecord
->next
= gcvNULL
;
1613 tempRecord
->processID
= processID
;
1615 /* Allocate another record for user signal #1. */
1616 if (Info
->userSignal1
!= gcvNULL
)
1618 /* Allocate a record. */
1619 gcmkONERROR(gckEVENT_AllocateRecord(Event
, gcvTRUE
, &tempRecord
));
1620 tailRecord
->next
= tempRecord
;
1621 tailRecord
= tempRecord
;
1623 /* Initialize the record. */
1624 tempRecord
->info
.command
= gcvHAL_SIGNAL
;
1625 tempRecord
->info
.u
.Signal
.process
= Info
->userProcess
;
1627 tempRecord
->info
.u
.Signal
.coid
= Info
->coid
;
1628 tempRecord
->info
.u
.Signal
.rcvid
= Info
->rcvid
;
1630 tempRecord
->info
.u
.Signal
.signal
= Info
->userSignal1
;
1631 tempRecord
->info
.u
.Signal
.auxSignal
= gcvNULL
;
1632 tempRecord
->next
= gcvNULL
;
1633 tempRecord
->processID
= processID
;
1636 /* Allocate another record for user signal #2. */
1637 if (Info
->userSignal2
!= gcvNULL
)
1639 /* Allocate a record. */
1640 gcmkONERROR(gckEVENT_AllocateRecord(Event
, gcvTRUE
, &tempRecord
));
1641 tailRecord
->next
= tempRecord
;
1642 tailRecord
= tempRecord
;
1644 /* Initialize the record. */
1645 tempRecord
->info
.command
= gcvHAL_SIGNAL
;
1646 tempRecord
->info
.u
.Signal
.process
= Info
->userProcess
;
1648 tempRecord
->info
.u
.Signal
.coid
= Info
->coid
;
1649 tempRecord
->info
.u
.Signal
.rcvid
= Info
->rcvid
;
1651 tempRecord
->info
.u
.Signal
.signal
= Info
->userSignal2
;
1652 tempRecord
->info
.u
.Signal
.auxSignal
= gcvNULL
;
1653 tempRecord
->next
= gcvNULL
;
1654 tempRecord
->processID
= processID
;
1657 /* Set the event list. */
1658 Event
->queues
[id
].head
= headRecord
;
1660 /* Start composition. */
1661 gcmkONERROR(gckHARDWARE_Compose(
1662 Event
->kernel
->hardware
, processID
,
1663 Info
->size
, Info
->physical
, Info
->logical
, id
1668 return gcvSTATUS_OK
;
1671 /* Return the status. */
1676 /*******************************************************************************
1678 ** gckEVENT_Interrupt
1680 ** Called by the interrupt service routine to store the triggered interrupt
1681 ** mask to be later processed by gckEVENT_Notify.
1686 ** Pointer to an gckEVENT object.
1689 ** Mask for the 32 interrupts.
1701 gcmkHEADER_ARG("Event=0x%x Data=0x%x", Event
, Data
);
1703 /* Verify the arguments. */
1704 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
1706 /* Combine current interrupt status with pending flags. */
1708 atomic_set(&Event
->pending
, Data
);
1712 gctUINT32 oldVal
,newVal
;
1714 oldVal
= Event
->pending
;
1715 newVal
= oldVal
| Data
;
1716 }while(atomic_cmpxchg((atomic_t
*)&Event
->pending
,oldVal
,newVal
)!=oldVal
);
1719 Event
->pending
|= Data
;
1725 return gcvSTATUS_OK
;
1728 /*******************************************************************************
1732 ** Process all triggered interrupts.
1737 ** Pointer to an gckEVENT object.
1749 gceSTATUS status
= gcvSTATUS_OK
;
1751 gcsEVENT_QUEUE
* queue
;
1753 gctBOOL acquired
= gcvFALSE
;
1755 gcuVIDMEM_NODE_PTR node
;
1758 gctBOOL suspended
= gcvFALSE
;
1760 gctBOOL empty
= gcvFALSE
, idle
= gcvFALSE
;
1762 gcmDEBUG_ONLY(gctINT eventNumber
= 0;)
1765 gcskSECURE_CACHE_PTR cache
;
1768 gcmkHEADER_ARG("Event=0x%x IDs=0x%x", Event
, IDs
);
1770 /* Verify the arguments. */
1771 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
1776 for (i
= 0; i
< gcmCOUNTOF(Event
->queues
); ++i
)
1778 if (Event
->queues
[i
].head
!= gcvNULL
)
1780 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE
, gcvZONE_EVENT
,
1781 "Queue(%d): stamp=%llu source=%d",
1783 Event
->queues
[i
].stamp
,
1784 Event
->queues
[i
].source
);
1792 /* Suspend interrupts. */
1793 gcmkONERROR(gckOS_SuspendInterruptEx(Event
->os
, Event
->kernel
->core
));
1794 suspended
= gcvTRUE
;
1796 /* Get current interrupts. */
1797 pending
= Event
->pending
;
1799 /* Resume interrupts. */
1800 gcmkONERROR(gckOS_ResumeInterruptEx(Event
->os
, Event
->kernel
->core
));
1801 suspended
= gcvFALSE
;
1805 /* No more pending interrupts - done. */
1810 gcvLEVEL_INFO
, gcvZONE_EVENT
,
1812 "Pending interrupts 0x%x",
1821 for (i
= 0; i
< gcmCOUNTOF(Event
->queues
); ++i
)
1823 if (Event
->queues
[i
].head
!= gcvNULL
)
1825 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE
, gcvZONE_EVENT
,
1826 "Queue(%d): stamp=%llu source=%d",
1828 Event
->queues
[i
].stamp
,
1829 Event
->queues
[i
].source
);
1835 /* Find the oldest pending interrupt. */
1836 for (i
= 0; i
< gcmCOUNTOF(Event
->queues
); ++i
)
1838 if ((Event
->queues
[i
].head
!= gcvNULL
)
1839 && (pending
& (1 << i
))
1842 if ((queue
== gcvNULL
)
1843 || (Event
->queues
[i
].stamp
< queue
->stamp
)
1846 queue
= &Event
->queues
[i
];
1848 gcmDEBUG_ONLY(eventNumber
= i
);
1853 if (queue
== gcvNULL
)
1856 gcvLEVEL_ERROR
, gcvZONE_EVENT
,
1858 "Interrupts 0x%x are not pending.",
1862 /* Suspend interrupts. */
1863 gcmkONERROR(gckOS_SuspendInterruptEx(Event
->os
, Event
->kernel
->core
));
1864 suspended
= gcvTRUE
;
1866 /* Mark pending interrupts as handled. */
1868 atomic_clr(&Event
->pending
, pending
);
1872 gctUINT32 oldVal
,newVal
;
1874 oldVal
= Event
->pending
;
1875 newVal
= oldVal
& (~pending
);
1876 }while(atomic_cmpxchg((atomic_t
*)&Event
->pending
,oldVal
,newVal
)!=oldVal
);
1879 Event
->pending
&= ~pending
;
1883 /* Resume interrupts. */
1884 gcmkONERROR(gckOS_ResumeInterruptEx(Event
->os
, Event
->kernel
->core
));
1885 suspended
= gcvFALSE
;
1890 /* Check whether there is a missed interrupt. */
1891 for (i
= 0; i
< gcmCOUNTOF(Event
->queues
); ++i
)
1893 if ((Event
->queues
[i
].head
!= gcvNULL
)
1894 && (Event
->queues
[i
].stamp
< queue
->stamp
)
1895 && (Event
->queues
[i
].source
== queue
->source
)
1900 gcmSIZEOF(i
) + gcmSIZEOF(Event
->queues
[i
].stamp
),
1901 "Event %d lost (stamp %llu)",
1902 i
, Event
->queues
[i
].stamp
1905 /* Use this event instead. */
1906 queue
= &Event
->queues
[i
];
1913 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
1915 gcvLEVEL_INFO
, gcvZONE_EVENT
,
1916 gcmSIZEOF(eventNumber
),
1917 "Processing interrupt %d",
1923 /* Walk all events for this interrupt. */
1926 gcsEVENT_PTR record
,record_next
;
1934 /* Grab the mutex queue. */
1935 gcmkONERROR(gckOS_AcquireMutex(Event
->os
,
1936 Event
->eventQueueMutex
,
1940 /* Grab the event head. */
1941 record
= queue
->head
;
1942 record_next
= gcvNULL
;
1943 if (record
!= gcvNULL
)
1945 record_next
= record
->next
;
1946 queue
->head
= record_next
;
1949 /* Release the mutex queue. */
1950 gcmkONERROR(gckOS_ReleaseMutex(Event
->os
, Event
->eventQueueMutex
));
1951 acquired
= gcvFALSE
;
1953 /* Dispatch on event type. */
1954 if (record
!= gcvNULL
)
1957 /* Assign record->processID as the pid for this galcore thread.
1958 * Used in OS calls like gckOS_UnlockMemory() which do not take a pid.
1960 drv_thread_specific_key_assign(record
->processID
, 0);
1964 /* Get the cache that belongs to this process. */
1965 gcmkONERROR(gckKERNEL_GetProcessDBCache(Event
->kernel
,
1971 gcvLEVEL_INFO
, gcvZONE_EVENT
,
1972 gcmSIZEOF(record
->info
.command
),
1973 "Processing event type: %d",
1974 record
->info
.command
1977 switch (record
->info
.command
)
1979 case gcvHAL_FREE_NON_PAGED_MEMORY
:
1980 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE
, gcvZONE_EVENT
,
1981 "gcvHAL_FREE_NON_PAGED_MEMORY: 0x%x",
1982 record
->info
.u
.FreeNonPagedMemory
.physical
);
1984 /* Free non-paged memory. */
1985 status
= gckOS_FreeNonPagedMemory(
1987 record
->info
.u
.FreeNonPagedMemory
.bytes
,
1988 record
->info
.u
.FreeNonPagedMemory
.physical
,
1989 record
->info
.u
.FreeNonPagedMemory
.logical
);
1991 if (gcmIS_SUCCESS(status
))
1994 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
1997 record
->event
.u
.FreeNonPagedMemory
.logical
,
1998 record
->event
.u
.FreeNonPagedMemory
.bytes
));
2003 case gcvHAL_FREE_CONTIGUOUS_MEMORY
:
2005 gcvLEVEL_VERBOSE
, gcvZONE_EVENT
,
2006 "gcvHAL_FREE_CONTIGUOUS_MEMORY: 0x%x",
2007 record
->info
.u
.FreeContiguousMemory
.physical
);
2009 /* Unmap the user memory. */
2010 status
= gckOS_FreeContiguous(
2012 record
->info
.u
.FreeContiguousMemory
.physical
,
2013 record
->info
.u
.FreeContiguousMemory
.logical
,
2014 record
->info
.u
.FreeContiguousMemory
.bytes
);
2016 if (gcmIS_SUCCESS(status
))
2019 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2022 event
->event
.u
.FreeContiguousMemory
.logical
,
2023 event
->event
.u
.FreeContiguousMemory
.bytes
));
2028 case gcvHAL_FREE_VIDEO_MEMORY
:
2029 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE
, gcvZONE_EVENT
,
2030 "gcvHAL_FREE_VIDEO_MEMORY: 0x%x",
2031 record
->info
.u
.FreeVideoMemory
.node
);
2034 node
= record
->info
.u
.FreeVideoMemory
.node
;
2035 #if gcdUSE_VIDMEM_PER_PID
2036 /* Check if the VidMem object still exists. */
2037 if (gckKERNEL_GetVideoMemoryPoolPid(record
->kernel
,
2040 gcvNULL
) == gcvSTATUS_NOT_FOUND
)
2042 /*printf("Vidmem not found for process:%d\n", queue->processID);*/
2043 status
= gcvSTATUS_OK
;
2047 if ((node
->VidMem
.memory
->object
.type
== gcvOBJ_VIDMEM
)
2048 && (node
->VidMem
.logical
!= gcvNULL
)
2052 gckKERNEL_UnmapVideoMemory(record
->kernel
,
2053 node
->VidMem
.logical
,
2055 node
->VidMem
.bytes
));
2056 node
->VidMem
.logical
= gcvNULL
;
2061 /* Free video memory. */
2063 gckVIDMEM_Free(record
->info
.u
.FreeVideoMemory
.node
);
2067 case gcvHAL_WRITE_DATA
:
2069 /* Convert physical into logical address. */
2071 gckOS_MapPhysical(Event
->os
,
2072 record
->info
.u
.WriteData
.address
,
2073 gcmSIZEOF(gctUINT32
),
2078 gckOS_WriteMemory(Event
->os
,
2080 record
->info
.u
.WriteData
.data
));
2082 /* Unmap the physical memory. */
2084 gckOS_UnmapPhysical(Event
->os
,
2086 gcmSIZEOF(gctUINT32
)));
2090 gckOS_WriteMemory(Event
->os
,
2092 record
->info
.u
.WriteData
.address
,
2093 record
->info
.u
.WriteData
.data
));
2097 case gcvHAL_UNLOCK_VIDEO_MEMORY
:
2098 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE
, gcvZONE_EVENT
,
2099 "gcvHAL_UNLOCK_VIDEO_MEMORY: 0x%x",
2100 record
->info
.u
.UnlockVideoMemory
.node
);
2102 /* Save node information before it disappears. */
2104 node
= event
->event
.u
.UnlockVideoMemory
.node
;
2105 if (node
->VidMem
.memory
->object
.type
== gcvOBJ_VIDMEM
)
2112 logical
= node
->Virtual
.logical
;
2113 bytes
= node
->Virtual
.bytes
;
2118 status
= gckVIDMEM_Unlock(
2120 record
->info
.u
.UnlockVideoMemory
.node
,
2121 record
->info
.u
.UnlockVideoMemory
.type
,
2125 if (gcmIS_SUCCESS(status
) && (logical
!= gcvNULL
))
2127 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2137 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE
, gcvZONE_EVENT
,
2138 "gcvHAL_SIGNAL: 0x%x",
2139 record
->info
.u
.Signal
.signal
);
2142 if ((record
->info
.u
.Signal
.coid
== 0)
2143 && (record
->info
.u
.Signal
.rcvid
== 0)
2146 /* Kernel signal. */
2148 gckOS_Signal(Event
->os
,
2149 record
->info
.u
.Signal
.signal
,
2156 gckOS_UserSignal(Event
->os
,
2157 record
->info
.u
.Signal
.signal
,
2158 record
->info
.u
.Signal
.rcvid
,
2159 record
->info
.u
.Signal
.coid
));
2163 if (record
->info
.u
.Signal
.process
== gcvNULL
)
2165 /* Kernel signal. */
2167 gckOS_Signal(Event
->os
,
2168 record
->info
.u
.Signal
.signal
,
2175 gckOS_UserSignal(Event
->os
,
2176 record
->info
.u
.Signal
.signal
,
2177 record
->info
.u
.Signal
.process
));
2180 gcmkASSERT(record
->info
.u
.Signal
.auxSignal
== gcvNULL
);
2184 case gcvHAL_UNMAP_USER_MEMORY
:
2185 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE
, gcvZONE_EVENT
,
2186 "gcvHAL_UNMAP_USER_MEMORY: 0x%x",
2187 record
->info
.u
.UnmapUserMemory
.info
);
2189 /* Unmap the user memory. */
2190 status
= gckOS_UnmapUserMemoryEx(
2192 Event
->kernel
->core
,
2193 record
->info
.u
.UnmapUserMemory
.memory
,
2194 record
->info
.u
.UnmapUserMemory
.size
,
2195 record
->info
.u
.UnmapUserMemory
.info
,
2196 record
->info
.u
.UnmapUserMemory
.address
);
2199 if (gcmIS_SUCCESS(status
))
2201 gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
2204 event
->event
.u
.UnmapUserMemory
.memory
,
2205 event
->event
.u
.UnmapUserMemory
.size
));
2208 gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
2210 record
->processID
, gcvDB_MAP_USER_MEMORY
,
2211 record
->info
.u
.UnmapUserMemory
.memory
));
2214 case gcvHAL_TIMESTAMP
:
2215 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE
, gcvZONE_EVENT
,
2216 "gcvHAL_TIMESTAMP: %d %d",
2217 record
->info
.u
.TimeStamp
.timer
,
2218 record
->info
.u
.TimeStamp
.request
);
2220 /* Process the timestamp. */
2221 switch (record
->info
.u
.TimeStamp
.request
)
2224 status
= gckOS_GetTime(&Event
->kernel
->timers
[
2225 record
->info
.u
.TimeStamp
.timer
].
2230 status
= gckOS_GetTime(&Event
->kernel
->timers
[
2231 record
->info
.u
.TimeStamp
.timer
].
2237 gcvLEVEL_ERROR
, gcvZONE_EVENT
,
2238 gcmSIZEOF(record
->info
.u
.TimeStamp
.request
),
2239 "Invalid timestamp request: %d",
2240 record
->info
.u
.TimeStamp
.request
2243 status
= gcvSTATUS_INVALID_ARGUMENT
;
2249 /* Invalid argument. */
2251 gcvLEVEL_ERROR
, gcvZONE_EVENT
,
2252 gcmSIZEOF(record
->info
.command
),
2253 "Unknown event type: %d",
2254 record
->info
.command
2257 status
= gcvSTATUS_INVALID_ARGUMENT
;
2261 /* Make sure there are no errors generated. */
2262 if (gcmIS_ERROR(status
))
2265 gcvLEVEL_WARNING
, gcvZONE_EVENT
,
2267 "Event produced status: %d(%s)",
2268 status
, gckOS_DebugStatus2Name(status
));
2271 /* Free the event. */
2272 gcmkVERIFY_OK(gckEVENT_FreeRecord(Event
, record
));
2275 //Can't use queue->head to check, as the value may be updated while it equals to NULL.
2276 //So use the shadow value to check.
2277 if(record_next
== gcvNULL
)
2282 /* Increase the number of free events. */
2283 gcmkONERROR(gckOS_AtomIncrement(Event
->os
, Event
->freeAtom
, &free
));
2285 gcmkTRACE_ZONE(gcvLEVEL_VERBOSE
, gcvZONE_EVENT
,
2286 "Handled interrupt 0x%x", mask
);
2288 /* Suspend interrupts. */
2289 gcmkONERROR(gckOS_SuspendInterruptEx(Event
->os
, Event
->kernel
->core
));
2290 suspended
= gcvTRUE
;
2292 /* Mark pending interrupt as handled. */
2295 gctUINT32 oldVal
,newVal
;
2297 oldVal
= Event
->pending
;
2298 newVal
= oldVal
& (~mask
);
2299 }while(atomic_cmpxchg((atomic_t
*)&Event
->pending
,oldVal
,newVal
)!=oldVal
);
2301 #elif defined __QNXNTO__
2302 atomic_clr(&Event
->pending
, mask
);
2304 Event
->pending
&= ~mask
;
2307 /* Resume interrupts. */
2308 gcmkONERROR(gckOS_ResumeInterruptEx(Event
->os
, Event
->kernel
->core
));
2309 suspended
= gcvFALSE
;
2314 /* Check whether the event queue is empty. */
2315 gcmkONERROR(gckEVENT_IsEmpty(Event
, &empty
));
2317 if (empty
&& (IDs
== 0))
2319 /* Query whether the hardware is idle. */
2320 gcmkONERROR(gckHARDWARE_QueryIdle(Event
->kernel
->hardware
, &idle
));
2324 /* Inform the system of idle GPU. */
2325 gcmkONERROR(gckOS_Broadcast(Event
->os
,
2326 Event
->kernel
->hardware
,
2327 gcvBROADCAST_GPU_IDLE
));
2334 return gcvSTATUS_OK
;
2339 /* Release mutex. */
2340 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event
->os
, Event
->eventQueueMutex
));
2345 /* Resume interrupts. */
2346 gcmkVERIFY_OK(gckOS_ResumeInterruptEx(Event
->os
, Event
->kernel
->core
));
2349 /* Return the status. */
2354 /*******************************************************************************
2355 ** gckEVENT_FreeProcess
2357 ** Free all events owned by a particular process ID.
2362 ** Pointer to an gckEVENT object.
2364 ** gctUINT32 ProcessID
2365 ** Process ID of the process to be freed up.
2372 gckEVENT_FreeProcess(
2374 IN gctUINT32 ProcessID
2378 gctBOOL acquired
= gcvFALSE
;
2379 gcsEVENT_PTR record
, next
;
2381 gcsEVENT_PTR deleteHead
, deleteTail
;
2382 gctBOOL empty
, idle
;
2384 gcmkHEADER_ARG("Event=0x%x ProcessID=%d", Event
, ProcessID
);
2386 /* Verify the arguments. */
2387 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
2389 /* Walk through all queues. */
2390 for (i
= 0; i
< gcmCOUNTOF(Event
->queues
); ++i
)
2392 if (Event
->queues
[i
].head
!= gcvNULL
)
2394 /* Grab the event queue mutex. */
2395 gcmkONERROR(gckOS_AcquireMutex(Event
->os
,
2396 Event
->eventQueueMutex
,
2400 /* Grab the mutex head. */
2401 record
= Event
->queues
[i
].head
;
2402 Event
->queues
[i
].head
= gcvNULL
;
2403 Event
->queues
[i
].tail
= gcvNULL
;
2404 deleteHead
= gcvNULL
;
2405 deleteTail
= gcvNULL
;
2407 while (record
!= gcvNULL
)
2409 next
= record
->next
;
2410 if (record
->processID
== ProcessID
)
2412 if (deleteHead
== gcvNULL
)
2414 deleteHead
= record
;
2418 deleteTail
->next
= record
;
2421 deleteTail
= record
;
2425 if (Event
->queues
[i
].head
== gcvNULL
)
2427 Event
->queues
[i
].head
= record
;
2431 Event
->queues
[i
].tail
->next
= record
;
2434 Event
->queues
[i
].tail
= record
;
2437 record
->next
= gcvNULL
;
2441 /* Release the mutex queue. */
2442 gcmkONERROR(gckOS_ReleaseMutex(Event
->os
, Event
->eventQueueMutex
));
2443 acquired
= gcvFALSE
;
2445 /* Loop through the entire list of events. */
2446 for (record
= deleteHead
; record
!= gcvNULL
; record
= next
)
2448 /* Get the next event record. */
2449 next
= record
->next
;
2451 /* Free the event record. */
2452 gcmkONERROR(gckEVENT_FreeRecord(Event
, record
));
2457 /*Check whether the event queue is empty.*/
2458 gcmkONERROR(_IsEmpty(Event
, &empty
));
2462 /* Query whether the hardware is idle. */
2463 gcmkONERROR(gckHARDWARE_QueryIdle(Event
->kernel
->hardware
, &idle
));
2467 /* Inform the system of idle GPU. */
2468 gcmkONERROR(gckOS_Broadcast(Event
->os
,
2469 Event
->kernel
->hardware
,
2470 gcvBROADCAST_GPU_IDLE
));
2476 return gcvSTATUS_OK
;
2479 /* Release the event queue mutex. */
2482 gcmkVERIFY_OK(gckOS_ReleaseMutex(Event
->os
, Event
->eventQueueMutex
));
2485 /* Return the status. */
2490 /*******************************************************************************
2493 ** Stop the hardware using the End event mechanism.
2498 ** Pointer to an gckEVENT object.
2500 ** gctUINT32 ProcessID
2501 ** Process ID Logical belongs.
2503 ** gctPHYS_ADDR Handle
2504 ** Physical address handle. If gcvNULL it is video memory.
2506 ** gctPOINTER Logical
2507 ** Logical address to flush.
2510 ** Pointer to the signal to trigger.
2519 IN gctUINT32 ProcessID
,
2520 IN gctPHYS_ADDR Handle
,
2521 IN gctPOINTER Logical
,
2522 IN gctSIGNAL Signal
,
2523 IN OUT gctSIZE_T
* waitSize
2527 /* gctSIZE_T waitSize;*/
2528 gcsEVENT_PTR record
;
2531 gcmkHEADER_ARG("Event=0x%x ProcessID=%u Handle=0x%x Logical=0x%x "
2533 Event
, ProcessID
, Handle
, Logical
, Signal
);
2535 /* Verify the arguments. */
2536 gcmkVERIFY_OBJECT(Event
, gcvOBJ_EVENT
);
2538 /* Submit the current event queue. */
2539 gcmkONERROR(gckEVENT_Submit(Event
, gcvTRUE
, gcvFALSE
));
2541 gcmkONERROR(gckEVENT_GetEvent(Event
, gcvTRUE
, &id
, gcvKERNEL_PIXEL
));
2543 /* Allocate a record. */
2544 gcmkONERROR(gckEVENT_AllocateRecord(Event
, gcvTRUE
, &record
));
2546 /* Initialize the record. */
2547 record
->next
= gcvNULL
;
2548 record
->processID
= ProcessID
;
2549 record
->info
.command
= gcvHAL_SIGNAL
;
2550 record
->info
.u
.Signal
.signal
= Signal
;
2552 record
->info
.u
.Signal
.coid
= 0;
2553 record
->info
.u
.Signal
.rcvid
= 0;
2555 record
->info
.u
.Signal
.auxSignal
= gcvNULL
;
2556 record
->info
.u
.Signal
.process
= gcvNULL
;
2558 /* Append the record. */
2559 Event
->queues
[id
].head
= record
;
2561 /* Replace last WAIT with END. */
2562 gcmkONERROR(gckHARDWARE_End(
2563 Event
->kernel
->hardware
, Logical
, waitSize
2566 #if gcdNONPAGED_MEMORY_CACHEABLE
2567 /* Flush the cache for the END. */
2568 gcmkONERROR(gckOS_CacheClean(
2578 /* Wait for the signal. */
2579 gcmkONERROR(gckOS_WaitSignal(Event
->os
, Signal
, gcvINFINITE
));
2583 return gcvSTATUS_OK
;
2587 /* Return the status. */