1 /****************************************************************************
3 * Copyright (C) 2005 - 2011 by Vivante Corp.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the license, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *****************************************************************************/
24 #include "gc_hal_kernel_precomp.h"
25 #include "gc_hal_kernel_context.h"
31 #define _GC_OBJ_ZONE gcvZONE_COMMAND
33 /* When enabled, extra messages needed by the dump parser are left out. */
34 #define gcdSIMPLE_COMMAND_DUMP 1
36 /******************************************************************************\
37 ********************************* Support Code *********************************
38 \******************************************************************************/
40 /*******************************************************************************
44 ** Allocate a new command queue.
49 ** Pointer to an gckCOMMAND object.
54 ** gckCOMMAND object has been updated with a new command queue.
58 IN OUT gckCOMMAND Command
62 gctINT currentIndex
, newIndex
;
64 gcmkHEADER_ARG("Command=0x%x", Command
);
66 /* Switch to the next command buffer. */
67 currentIndex
= Command
->index
;
68 newIndex
= (currentIndex
+ 1) % gcdCOMMAND_QUEUES
;
70 /* Wait for availability. */
71 #if gcdDUMP_COMMAND && !gcdSIMPLE_COMMAND_DUMP
72 gcmkPRINT("@[kernel.waitsignal]");
75 gcmkONERROR(gckOS_WaitSignal(
77 Command
->queues
[newIndex
].signal
,
81 #if gcmIS_DEBUG(gcdDEBUG_TRACE)
82 if (newIndex
< currentIndex
)
84 Command
->wrapCount
+= 1;
87 gcvLEVEL_INFO
, gcvZONE_COMMAND
,
89 "%s(%d): queue array wrapped around.\n",
90 __FUNCTION__
, __LINE__
95 gcvLEVEL_INFO
, gcvZONE_COMMAND
,
97 "%s(%d): total queue wrap arounds %d.\n",
98 __FUNCTION__
, __LINE__
, Command
->wrapCount
102 gcvLEVEL_INFO
, gcvZONE_COMMAND
,
104 "%s(%d): switched to queue %d.\n",
105 __FUNCTION__
, __LINE__
, newIndex
109 /* Update gckCOMMAND object with new command queue. */
110 Command
->index
= newIndex
;
111 Command
->newQueue
= gcvTRUE
;
112 Command
->logical
= Command
->queues
[newIndex
].logical
;
116 gckOS_GetPhysicalAddress(
119 (gctUINT32
*) &Command
->physical
122 if (currentIndex
!= -1)
124 /* Mark the command queue as available. */
125 gcmkONERROR(gckEVENT_Signal(
126 Command
->kernel
->eventObj
,
127 Command
->queues
[currentIndex
].signal
,
133 gcmkFOOTER_ARG("Command->index=%d", Command
->index
);
137 /* Return the status. */
143 _IncrementCommitAtom(
144 IN gckCOMMAND Command
,
149 gckHARDWARE hardware
;
151 gctBOOL powerAcquired
= gcvFALSE
;
153 gcmkHEADER_ARG("Command=0x%x", Command
);
155 /* Extract the gckHARDWARE and gckEVENT objects. */
156 hardware
= Command
->kernel
->hardware
;
157 gcmkVERIFY_OBJECT(hardware
, gcvOBJ_HARDWARE
);
159 /* Grab the power mutex. */
160 gcmkONERROR(gckOS_AcquireMutex(
161 Command
->os
, hardware
->powerMutex
, gcvINFINITE
163 powerAcquired
= gcvTRUE
;
165 /* Increment the commit atom. */
168 gcmkONERROR(gckOS_AtomIncrement(
169 Command
->os
, Command
->atomCommit
, &atomValue
174 gcmkONERROR(gckOS_AtomDecrement(
175 Command
->os
, Command
->atomCommit
, &atomValue
179 /* Release the power mutex. */
180 gcmkONERROR(gckOS_ReleaseMutex(
181 Command
->os
, hardware
->powerMutex
183 powerAcquired
= gcvFALSE
;
192 /* Release the power mutex. */
193 gcmkVERIFY_OK(gckOS_ReleaseMutex(
194 Command
->os
, hardware
->powerMutex
198 /* Return the status. */
206 IN gckCOMMAND Command
,
207 IN gctUINT32 ProcessID
,
208 IN gcoCMDBUF CommandBuffer
211 gceSTATUS status
= gcvSTATUS_OK
;
213 gctBOOL needCopy
= gcvFALSE
;
214 gcskSECURE_CACHE_PTR cache
;
215 gctUINT8_PTR commandBufferLogical
;
216 gctUINT8_PTR hintedData
;
217 gctUINT32_PTR hintArray
;
218 gctUINT i
, hintCount
;
221 "Command=0x%08X ProcessID=%d CommandBuffer=0x%08X",
222 Command
, ProcessID
, CommandBuffer
225 /* Verify the arguments. */
226 gcmkVERIFY_OBJECT(Command
, gcvOBJ_COMMAND
);
228 /* Reset state array pointer. */
231 /* Get the kernel object. */
232 kernel
= Command
->kernel
;
234 /* Get the cache form the database. */
235 gcmkONERROR(gckKERNEL_GetProcessDBCache(kernel
, ProcessID
, &cache
));
237 /* Determine the start of the command buffer. */
239 = (gctUINT8_PTR
) CommandBuffer
->logical
240 + CommandBuffer
->startOffset
;
242 /* Determine the number of records in the state array. */
243 hintCount
= CommandBuffer
->hintArrayTail
- CommandBuffer
->hintArray
;
245 /* Check wehther we need to copy the structures or not. */
246 gcmkONERROR(gckOS_QueryNeedCopy(Command
->os
, ProcessID
, &needCopy
));
248 /* Get access to the state array. */
253 if (Command
->hintArrayAllocated
&&
254 (Command
->hintArraySize
< CommandBuffer
->hintArraySize
))
256 gcmkONERROR(gcmkOS_SAFE_FREE(Command
->os
, Command
->hintArray
));
257 Command
->hintArraySize
= gcvFALSE
;
260 if (!Command
->hintArrayAllocated
)
262 gctPOINTER pointer
= gcvNULL
;
264 gcmkONERROR(gckOS_Allocate(
266 CommandBuffer
->hintArraySize
,
270 Command
->hintArray
= pointer
;
271 Command
->hintArrayAllocated
= gcvTRUE
;
272 Command
->hintArraySize
= CommandBuffer
->hintArraySize
;
275 hintArray
= Command
->hintArray
;
276 copySize
= hintCount
* gcmSIZEOF(gctUINT32
);
278 gcmkONERROR(gckOS_CopyFromUserData(
281 CommandBuffer
->hintArray
,
287 gctPOINTER pointer
= gcvNULL
;
289 gcmkONERROR(gckOS_MapUserPointer(
291 CommandBuffer
->hintArray
,
292 CommandBuffer
->hintArraySize
,
299 /* Scan through the buffer. */
300 for (i
= 0; i
< hintCount
; i
+= 1)
302 /* Determine the location of the hinted data. */
303 hintedData
= commandBufferLogical
+ hintArray
[i
];
305 /* Map handle into physical address. */
306 gcmkONERROR(gckKERNEL_MapLogicalToPhysical(
307 kernel
, cache
, (gctPOINTER
) hintedData
312 /* Get access to the state array. */
313 if (!needCopy
&& (hintArray
!= gcvNULL
))
315 gcmkVERIFY_OK(gckOS_UnmapUserPointer(
317 CommandBuffer
->hintArray
,
318 CommandBuffer
->hintArraySize
,
323 /* Return the status. */
330 /******************************************************************************\
331 ****************************** gckCOMMAND API Code ******************************
332 \******************************************************************************/
334 /*******************************************************************************
336 ** gckCOMMAND_Construct
338 ** Construct a new gckCOMMAND object.
343 ** Pointer to an gckKERNEL object.
347 ** gckCOMMAND * Command
348 ** Pointer to a variable that will hold the pointer to the gckCOMMAND
352 gckCOMMAND_Construct(
354 OUT gckCOMMAND
* Command
358 gckCOMMAND command
= gcvNULL
;
361 gctPOINTER pointer
= gcvNULL
;
363 gcmkHEADER_ARG("Kernel=0x%x", Kernel
);
365 /* Verify the arguments. */
366 gcmkVERIFY_OBJECT(Kernel
, gcvOBJ_KERNEL
);
367 gcmkVERIFY_ARGUMENT(Command
!= gcvNULL
);
369 /* Extract the gckOS object. */
372 /* Allocate the gckCOMMAND structure. */
373 gcmkONERROR(gckOS_Allocate(os
, gcmSIZEOF(struct _gckCOMMAND
), &pointer
));
376 /* Reset the entire object. */
377 gcmkONERROR(gckOS_ZeroMemory(command
, gcmSIZEOF(struct _gckCOMMAND
)));
379 /* Initialize the gckCOMMAND object.*/
380 command
->object
.type
= gcvOBJ_COMMAND
;
381 command
->kernel
= Kernel
;
384 /* Get the command buffer requirements. */
385 gcmkONERROR(gckHARDWARE_QueryCommandBuffer(
388 &command
->reservedHead
,
389 &command
->reservedTail
392 /* Create the command queue mutex. */
393 gcmkONERROR(gckOS_CreateMutex(os
, &command
->mutexQueue
));
395 /* Create the context switching mutex. */
396 gcmkONERROR(gckOS_CreateMutex(os
, &command
->mutexContext
));
398 /* Create the power management semaphore. */
399 gcmkONERROR(gckOS_CreateSemaphore(os
, &command
->powerSemaphore
));
401 /* Create the commit atom. */
402 gcmkONERROR(gckOS_AtomConstruct(os
, &command
->atomCommit
));
404 /* Get the page size from teh OS. */
405 gcmkONERROR(gckOS_GetPageSize(os
, &command
->pageSize
));
407 /* Get process ID. */
408 gcmkONERROR(gckOS_GetProcessID(&command
->kernelProcessID
));
410 /* Set hardware to pipe 0. */
411 command
->pipeSelect
= gcvPIPE_INVALID
;
413 /* Pre-allocate the command queues. */
414 for (i
= 0; i
< gcdCOMMAND_QUEUES
; ++i
)
416 gcmkONERROR(gckOS_AllocateNonPagedMemory(
420 &command
->queues
[i
].physical
,
421 &command
->queues
[i
].logical
424 gcmkONERROR(gckOS_CreateSignal(
425 os
, gcvFALSE
, &command
->queues
[i
].signal
428 gcmkONERROR(gckOS_Signal(
429 os
, command
->queues
[i
].signal
, gcvTRUE
433 /* No command queue in use yet. */
435 command
->logical
= gcvNULL
;
436 command
->newQueue
= gcvFALSE
;
438 /* Command is not yet running. */
439 command
->running
= gcvFALSE
;
441 /* Command queue is idle. */
442 command
->idle
= gcvTRUE
;
444 /* Commit stamp is zero. */
445 command
->commitStamp
= 0;
447 /* END event signal not created. */
448 command
->endEventSignal
= gcvNULL
;
450 /* Return pointer to the gckCOMMAND object. */
454 gcmkFOOTER_ARG("*Command=0x%x", *Command
);
459 if (command
!= gcvNULL
)
461 if (command
->atomCommit
!= gcvNULL
)
463 gcmkVERIFY_OK(gckOS_AtomDestroy(os
, command
->atomCommit
));
466 if (command
->powerSemaphore
!= gcvNULL
)
468 gcmkVERIFY_OK(gckOS_DestroySemaphore(os
, command
->powerSemaphore
));
471 if (command
->mutexContext
!= gcvNULL
)
473 gcmkVERIFY_OK(gckOS_DeleteMutex(os
, command
->mutexContext
));
476 if (command
->mutexQueue
!= gcvNULL
)
478 gcmkVERIFY_OK(gckOS_DeleteMutex(os
, command
->mutexQueue
));
481 for (i
= 0; i
< gcdCOMMAND_QUEUES
; ++i
)
483 if (command
->queues
[i
].signal
!= gcvNULL
)
485 gcmkVERIFY_OK(gckOS_DestroySignal(
486 os
, command
->queues
[i
].signal
490 if (command
->queues
[i
].logical
!= gcvNULL
)
492 gcmkVERIFY_OK(gckOS_FreeNonPagedMemory(
495 command
->queues
[i
].physical
,
496 command
->queues
[i
].logical
501 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os
, command
));
504 /* Return the status. */
509 /*******************************************************************************
511 ** gckCOMMAND_Destroy
513 ** Destroy an gckCOMMAND object.
517 ** gckCOMMAND Command
518 ** Pointer to an gckCOMMAND object to destroy.
526 IN gckCOMMAND Command
531 gcmkHEADER_ARG("Command=0x%x", Command
);
533 /* Verify the arguments. */
534 gcmkVERIFY_OBJECT(Command
, gcvOBJ_COMMAND
);
536 /* Stop the command queue. */
537 gcmkVERIFY_OK(gckCOMMAND_Stop(Command
));
539 for (i
= 0; i
< gcdCOMMAND_QUEUES
; ++i
)
541 gcmkASSERT(Command
->queues
[i
].signal
!= gcvNULL
);
542 gcmkVERIFY_OK(gckOS_DestroySignal(
543 Command
->os
, Command
->queues
[i
].signal
546 gcmkASSERT(Command
->queues
[i
].logical
!= gcvNULL
);
547 gcmkVERIFY_OK(gckOS_FreeNonPagedMemory(
550 Command
->queues
[i
].physical
,
551 Command
->queues
[i
].logical
555 /* END event signal. */
556 if (Command
->endEventSignal
!= gcvNULL
)
558 gcmkVERIFY_OK(gckOS_DestroySignal(
559 Command
->os
, Command
->endEventSignal
563 /* Delete the context switching mutex. */
564 gcmkVERIFY_OK(gckOS_DeleteMutex(Command
->os
, Command
->mutexContext
));
566 /* Delete the command queue mutex. */
567 gcmkVERIFY_OK(gckOS_DeleteMutex(Command
->os
, Command
->mutexQueue
));
569 /* Destroy the power management semaphore. */
570 gcmkVERIFY_OK(gckOS_DestroySemaphore(Command
->os
, Command
->powerSemaphore
));
572 /* Destroy the commit atom. */
573 gcmkVERIFY_OK(gckOS_AtomDestroy(Command
->os
, Command
->atomCommit
));
576 /* Free state array. */
577 if (Command
->hintArrayAllocated
)
579 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Command
->os
, Command
->hintArray
));
580 Command
->hintArrayAllocated
= gcvFALSE
;
584 /* Mark object as unknown. */
585 Command
->object
.type
= gcvOBJ_UNKNOWN
;
587 /* Free the gckCOMMAND object. */
588 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Command
->os
, Command
));
595 /*******************************************************************************
597 ** gckCOMMAND_EnterCommit
599 ** Acquire command queue synchronization objects.
603 ** gckCOMMAND Command
604 ** Pointer to an gckCOMMAND object to destroy.
607 ** Determines whether the call originates from inside the power
608 ** management or not.
615 gckCOMMAND_EnterCommit(
616 IN gckCOMMAND Command
,
621 gckHARDWARE hardware
;
622 gctBOOL atomIncremented
= gcvFALSE
;
623 gctBOOL semaAcquired
= gcvFALSE
;
625 gcmkHEADER_ARG("Command=0x%x", Command
);
627 /* Extract the gckHARDWARE and gckEVENT objects. */
628 hardware
= Command
->kernel
->hardware
;
629 gcmkVERIFY_OBJECT(hardware
, gcvOBJ_HARDWARE
);
633 /* Increment COMMIT atom to let power management know that a commit is
635 gcmkONERROR(_IncrementCommitAtom(Command
, gcvTRUE
));
636 atomIncremented
= gcvTRUE
;
638 /* Notify the system the GPU has a commit. */
639 gcmkONERROR(gckOS_Broadcast(Command
->os
,
641 gcvBROADCAST_GPU_COMMIT
));
643 /* Acquire the power management semaphore. */
644 gcmkONERROR(gckOS_AcquireSemaphore(Command
->os
,
645 Command
->powerSemaphore
));
646 semaAcquired
= gcvTRUE
;
649 /* Grab the conmmand queue mutex. */
650 gcmkONERROR(gckOS_AcquireMutex(Command
->os
,
661 /* Release the power management semaphore. */
662 gcmkVERIFY_OK(gckOS_ReleaseSemaphore(
663 Command
->os
, Command
->powerSemaphore
669 /* Decrement the commit atom. */
670 gcmkVERIFY_OK(_IncrementCommitAtom(
675 /* Return the status. */
680 /*******************************************************************************
682 ** gckCOMMAND_ExitCommit
684 ** Release command queue synchronization objects.
688 ** gckCOMMAND Command
689 ** Pointer to an gckCOMMAND object to destroy.
692 ** Determines whether the call originates from inside the power
693 ** management or not.
700 gckCOMMAND_ExitCommit(
701 IN gckCOMMAND Command
,
707 gcmkHEADER_ARG("Command=0x%x", Command
);
709 /* Release the power mutex. */
710 gcmkONERROR(gckOS_ReleaseMutex(Command
->os
, Command
->mutexQueue
));
714 /* Release the power management semaphore. */
715 gcmkONERROR(gckOS_ReleaseSemaphore(Command
->os
,
716 Command
->powerSemaphore
));
718 /* Decrement the commit atom. */
719 gcmkONERROR(_IncrementCommitAtom(Command
, gcvFALSE
));
727 /* Return the status. */
732 /*******************************************************************************
736 ** Start up the command queue.
740 ** gckCOMMAND Command
741 ** Pointer to an gckCOMMAND object to start.
749 IN gckCOMMAND Command
753 gckHARDWARE hardware
;
754 gctUINT32 waitOffset
;
755 gctSIZE_T waitLinkBytes
;
757 gcmkHEADER_ARG("Command=0x%x", Command
);
759 /* Verify the arguments. */
760 gcmkVERIFY_OBJECT(Command
, gcvOBJ_COMMAND
);
762 if (Command
->running
)
764 /* Command queue already running. */
769 /* Extract the gckHARDWARE object. */
770 hardware
= Command
->kernel
->hardware
;
771 gcmkVERIFY_OBJECT(hardware
, gcvOBJ_HARDWARE
);
773 if (Command
->logical
== gcvNULL
)
775 /* Start at beginning of a new queue. */
776 gcmkONERROR(_NewQueue(Command
));
779 /* Start at beginning of page. */
782 /* Set abvailable number of bytes for WAIT/LINK command sequence. */
783 waitLinkBytes
= Command
->pageSize
;
785 /* Append WAIT/LINK. */
786 gcmkONERROR(gckHARDWARE_WaitLink(
795 Command
->waitLogical
= (gctUINT8_PTR
) Command
->logical
+ waitOffset
;
796 Command
->waitPhysical
= (gctUINT8_PTR
) Command
->physical
+ waitOffset
;
798 #if gcdNONPAGED_MEMORY_CACHEABLE
799 /* Flush the cache for the wait/link. */
800 gcmkONERROR(gckOS_CacheClean(
802 Command
->kernelProcessID
,
811 Command
->offset
= waitLinkBytes
;
812 Command
->newQueue
= gcvFALSE
;
814 /* Enable command processor. */
816 gcmkONERROR(gckHARDWARE_Execute(
824 gcmkONERROR(gckHARDWARE_Execute(
831 /* Command queue is running. */
832 Command
->running
= gcvTRUE
;
839 /* Return the status. */
844 /*******************************************************************************
848 ** Stop the command queue.
852 ** gckCOMMAND Command
853 ** Pointer to an gckCOMMAND object to stop.
861 IN gckCOMMAND Command
864 gckHARDWARE hardware
;
868 gcmkHEADER_ARG("Command=0x%x", Command
);
870 /* Verify the arguments. */
871 gcmkVERIFY_OBJECT(Command
, gcvOBJ_COMMAND
);
873 if (!Command
->running
)
875 /* Command queue is not running. */
880 /* Extract the gckHARDWARE object. */
881 hardware
= Command
->kernel
->hardware
;
882 gcmkVERIFY_OBJECT(hardware
, gcvOBJ_HARDWARE
);
884 if (gckHARDWARE_IsFeatureAvailable(hardware
,
885 gcvFEATURE_END_EVENT
) == gcvSTATUS_TRUE
)
887 /* Allocate the signal. */
888 if (Command
->endEventSignal
== gcvNULL
)
890 gcmkONERROR(gckOS_CreateSignal(Command
->os
,
892 &Command
->endEventSignal
));
895 /* Append the END EVENT command to trigger the signal. */
896 gcmkONERROR(gckEVENT_Stop(Command
->kernel
->eventObj
,
897 Command
->kernelProcessID
,
898 Command
->waitPhysical
,
899 Command
->waitLogical
,
900 Command
->endEventSignal
,
901 &Command
->waitSize
));
905 /* Replace last WAIT with END. */
906 gcmkONERROR(gckHARDWARE_End(
907 hardware
, Command
->waitLogical
, &Command
->waitSize
910 /* Update queue tail pointer. */
911 gcmkONERROR(gckHARDWARE_UpdateQueueTail(Command
->kernel
->hardware
,
915 #if gcdNONPAGED_MEMORY_CACHEABLE
916 /* Flush the cache for the END. */
917 gcmkONERROR(gckOS_CacheClean(
919 Command
->kernelProcessID
,
921 Command
->waitPhysical
,
922 Command
->waitLogical
,
928 gcmkONERROR(gckHARDWARE_GetIdle(hardware
, gcvTRUE
, &idle
));
931 /* Command queue is no longer running. */
932 Command
->running
= gcvFALSE
;
939 /* Return the status. */
944 /*******************************************************************************
948 ** Commit a command buffer to the command queue.
952 ** gckCOMMAND Command
953 ** Pointer to a gckCOMMAND object.
955 ** gckCONTEXT Context
956 ** Pointer to a gckCONTEXT object.
958 ** gcoCMDBUF CommandBuffer
959 ** Pointer to a gcoCMDBUF object.
961 ** gcsSTATE_DELTA_PTR StateDelta
962 ** Pointer to the state delta.
964 ** gctUINT32 ProcessID
965 ** Current process ID.
973 IN gckCOMMAND Command
,
974 IN gckCONTEXT Context
,
975 IN gcoCMDBUF CommandBuffer
,
976 IN gcsSTATE_DELTA_PTR StateDelta
,
977 IN gcsQUEUE_PTR EventQueue
,
978 IN gctUINT32 ProcessID
982 /* Context switch required? */
983 if ((Context
!= gcvNULL
) && (Command
->currContext
!= Context
))
985 /* Yes, merge in the deltas. */
986 gckCONTEXT_Update(Context
, ProcessID
, StateDelta
);
988 /* Update the current context. */
989 Command
->currContext
= Context
;
992 /* Do nothing with infinite hardware. */
996 gckHARDWARE hardware
;
997 gcsCONTEXT_PTR contextBuffer
;
999 gctBOOL needCopy
= gcvFALSE
;
1001 struct _gcoCMDBUF _commandBufferObject
;
1002 gcoCMDBUF commandBufferObject
= gcvNULL
;
1003 gctBOOL commandBufferMapped
= gcvFALSE
;
1004 gctPHYS_ADDR commandBufferPhysical
;
1005 gctUINT8_PTR commandBufferLogical
;
1006 gctUINT8_PTR commandBufferLink
;
1007 gctUINT commandBufferSize
;
1009 gctBOOL commitEntered
= gcvFALSE
;
1010 gctBOOL contextAcquired
= gcvFALSE
;
1013 gctSIZE_T pipeBytes
;
1014 gctSIZE_T linkBytes
;
1018 gctPHYS_ADDR entryPhysical
;
1019 gctPOINTER entryLogical
;
1020 gctSIZE_T entryBytes
;
1022 gctPHYS_ADDR exitPhysical
;
1023 gctPOINTER exitLogical
;
1024 gctSIZE_T exitBytes
;
1026 gctPHYS_ADDR waitLinkPhysical
;
1027 gctPOINTER waitLinkLogical
;
1028 gctSIZE_T waitLinkBytes
;
1030 gctPHYS_ADDR waitPhysical
;
1031 gctPOINTER waitLogical
;
1032 gctUINT32 waitOffset
;
1035 gcsQUEUE _eventRecord
;
1036 gcsQUEUE_PTR eventRecord
= gcvNULL
;
1037 gcsQUEUE_PTR nextEventRecord
;
1040 gctPOINTER contextDumpLogical
= gcvNULL
;
1041 gctSIZE_T contextDumpBytes
= 0;
1043 gctPOINTER bufferDumpLogical
= gcvNULL
;
1044 gctSIZE_T bufferDumpBytes
= 0;
1047 gctPOINTER pointer
= gcvNULL
;
1050 "Command=0x%x CommandBuffer=0x%x ProcessID=%d",
1051 Command
, CommandBuffer
, ProcessID
1054 /* Verify the arguments. */
1055 gcmkVERIFY_OBJECT(Command
, gcvOBJ_COMMAND
);
1057 /* Acquire the command queue. */
1058 gcmkONERROR(gckCOMMAND_EnterCommit(Command
, gcvFALSE
));
1059 commitEntered
= gcvTRUE
;
1061 /* Acquire the context switching mutex. */
1062 gcmkONERROR(gckOS_AcquireMutex(
1063 Command
->os
, Command
->mutexContext
, gcvINFINITE
1065 contextAcquired
= gcvTRUE
;
1067 /* Extract the gckHARDWARE and gckEVENT objects. */
1068 hardware
= Command
->kernel
->hardware
;
1070 /* Check wehther we need to copy the structures or not. */
1071 gcmkONERROR(gckOS_QueryNeedCopy(Command
->os
, ProcessID
, &needCopy
));
1075 commandBufferObject
= &_commandBufferObject
;
1077 gcmkONERROR(gckOS_CopyFromUserData(
1079 commandBufferObject
,
1081 gcmSIZEOF(struct _gcoCMDBUF
)
1084 gcmkVERIFY_OBJECT(commandBufferObject
, gcvOBJ_COMMANDBUFFER
);
1088 gcmkONERROR(gckOS_MapUserPointer(
1091 gcmSIZEOF(struct _gcoCMDBUF
),
1095 commandBufferObject
= pointer
;
1097 gcmkVERIFY_OBJECT(commandBufferObject
, gcvOBJ_COMMANDBUFFER
);
1098 commandBufferMapped
= gcvTRUE
;
1101 /* Query the size of NOP command. */
1102 gcmkONERROR(gckHARDWARE_Nop(
1103 hardware
, gcvNULL
, &nopBytes
1106 /* Query the size of pipe select command sequence. */
1107 gcmkONERROR(gckHARDWARE_PipeSelect(
1108 hardware
, gcvNULL
, gcvPIPE_3D
, &pipeBytes
1111 /* Query the size of LINK command. */
1112 gcmkONERROR(gckHARDWARE_Link(
1113 hardware
, gcvNULL
, gcvNULL
, 0, &linkBytes
1116 /* Compute the command buffer entry and the size. */
1117 commandBufferLogical
1118 = (gctUINT8_PTR
) commandBufferObject
->logical
1119 + commandBufferObject
->startOffset
;
1121 gcmkONERROR(gckOS_GetPhysicalAddress(
1123 commandBufferLogical
,
1124 (gctUINT32_PTR
)&commandBufferPhysical
1128 = commandBufferObject
->offset
1129 + Command
->reservedTail
1130 - commandBufferObject
->startOffset
;
1132 /* Context switch required? */
1133 if (Context
== gcvNULL
)
1135 /* See if we have to switch pipes for the command buffer. */
1136 if (commandBufferObject
->entryPipe
== Command
->pipeSelect
)
1138 /* Skip pipe switching sequence. */
1143 /* The current hardware and the entry command buffer pipes
1144 ** are different, switch to the correct pipe. */
1145 gcmkONERROR(gckHARDWARE_PipeSelect(
1146 Command
->kernel
->hardware
,
1147 commandBufferLogical
,
1148 commandBufferObject
->entryPipe
,
1152 /* Do not skip pipe switching sequence. */
1156 /* Compute the entry. */
1157 entryPhysical
= (gctUINT8_PTR
) commandBufferPhysical
+ offset
;
1158 entryLogical
= commandBufferLogical
+ offset
;
1159 entryBytes
= commandBufferSize
- offset
;
1161 else if (Command
->currContext
!= Context
)
1163 /* Temporary disable context length oprimization. */
1164 Context
->dirty
= gcvTRUE
;
1166 /* Get the current context buffer. */
1167 contextBuffer
= Context
->buffer
;
1169 /* Yes, merge in the deltas. */
1170 gcmkONERROR(gckCONTEXT_Update(Context
, ProcessID
, StateDelta
));
1172 /* Determine context entry and exit points. */
1175 /* Reset 2D dirty flag. */
1176 Context
->dirty2D
= gcvFALSE
;
1178 if (Context
->dirty
|| commandBufferObject
->using3D
)
1180 /***************************************************************
1181 ** SWITCHING CONTEXT: 2D and 3D are used.
1184 /* Reset 3D dirty flag. */
1185 Context
->dirty3D
= gcvFALSE
;
1187 /* Compute the entry. */
1188 if (Command
->pipeSelect
== gcvPIPE_2D
)
1190 entryPhysical
= (gctUINT8_PTR
) contextBuffer
->physical
+ pipeBytes
;
1191 entryLogical
= (gctUINT8_PTR
) contextBuffer
->logical
+ pipeBytes
;
1192 entryBytes
= Context
->bufferSize
- pipeBytes
;
1196 entryPhysical
= (gctUINT8_PTR
) contextBuffer
->physical
;
1197 entryLogical
= (gctUINT8_PTR
) contextBuffer
->logical
;
1198 entryBytes
= Context
->bufferSize
;
1201 /* See if we have to switch pipes between the context
1202 and command buffers. */
1203 if (commandBufferObject
->entryPipe
== gcvPIPE_3D
)
1205 /* Skip pipe switching sequence. */
1210 /* The current hardware and the initial context pipes are
1211 different, switch to the correct pipe. */
1212 gcmkONERROR(gckHARDWARE_PipeSelect(
1213 Command
->kernel
->hardware
,
1214 commandBufferLogical
,
1215 commandBufferObject
->entryPipe
,
1219 /* Do not skip pipe switching sequence. */
1223 /* Ensure the NOP between 2D and 3D is in place so that the
1224 execution falls through from 2D to 3D. */
1225 gcmkONERROR(gckHARDWARE_Nop(
1227 contextBuffer
->link2D
,
1231 /* Generate a LINK from the context buffer to
1232 the command buffer. */
1233 gcmkONERROR(gckHARDWARE_Link(
1235 contextBuffer
->link3D
,
1236 commandBufferLogical
+ offset
,
1237 commandBufferSize
- offset
,
1241 /* Mark context as not dirty. */
1242 Context
->dirty
= gcvFALSE
;
1246 /***************************************************************
1247 ** SWITCHING CONTEXT: 2D only command buffer.
1250 /* Mark 3D as dirty. */
1251 Context
->dirty3D
= gcvTRUE
;
1253 /* Compute the entry. */
1254 if (Command
->pipeSelect
== gcvPIPE_2D
)
1256 entryPhysical
= (gctUINT8_PTR
) contextBuffer
->physical
+ pipeBytes
;
1257 entryLogical
= (gctUINT8_PTR
) contextBuffer
->logical
+ pipeBytes
;
1258 entryBytes
= Context
->entryOffset3D
- pipeBytes
;
1262 entryPhysical
= (gctUINT8_PTR
) contextBuffer
->physical
;
1263 entryLogical
= (gctUINT8_PTR
) contextBuffer
->logical
;
1264 entryBytes
= Context
->entryOffset3D
;
1267 /* Store the current context buffer. */
1268 Context
->dirtyBuffer
= contextBuffer
;
1270 /* See if we have to switch pipes between the context
1271 and command buffers. */
1272 if (commandBufferObject
->entryPipe
== gcvPIPE_2D
)
1274 /* Skip pipe switching sequence. */
1279 /* The current hardware and the initial context pipes are
1280 different, switch to the correct pipe. */
1281 gcmkONERROR(gckHARDWARE_PipeSelect(
1282 Command
->kernel
->hardware
,
1283 commandBufferLogical
,
1284 commandBufferObject
->entryPipe
,
1288 /* Do not skip pipe switching sequence. */
1292 /* 3D is not used, generate a LINK from the end of 2D part of
1293 the context buffer to the command buffer. */
1294 gcmkONERROR(gckHARDWARE_Link(
1296 contextBuffer
->link2D
,
1297 commandBufferLogical
+ offset
,
1298 commandBufferSize
- offset
,
1307 /* Mark 2D as dirty. */
1308 Context
->dirty2D
= gcvTRUE
;
1310 /* Store the current context buffer. */
1311 Context
->dirtyBuffer
= contextBuffer
;
1313 if (Context
->dirty
|| commandBufferObject
->using3D
)
1315 /***************************************************************
1316 ** SWITCHING CONTEXT: 3D only command buffer.
1319 /* Reset 3D dirty flag. */
1320 Context
->dirty3D
= gcvFALSE
;
1322 /* Determine context buffer entry offset. */
1323 offset
= (Command
->pipeSelect
== gcvPIPE_3D
)
1325 /* Skip pipe switching sequence. */
1326 ? Context
->entryOffset3D
+ pipeBytes
1328 /* Do not skip pipe switching sequence. */
1329 : Context
->entryOffset3D
;
1331 /* Compute the entry. */
1332 entryPhysical
= (gctUINT8_PTR
) contextBuffer
->physical
+ offset
;
1333 entryLogical
= (gctUINT8_PTR
) contextBuffer
->logical
+ offset
;
1334 entryBytes
= Context
->bufferSize
- offset
;
1336 /* See if we have to switch pipes between the context
1337 and command buffers. */
1338 if (commandBufferObject
->entryPipe
== gcvPIPE_3D
)
1340 /* Skip pipe switching sequence. */
1345 /* The current hardware and the initial context pipes are
1346 different, switch to the correct pipe. */
1347 gcmkONERROR(gckHARDWARE_PipeSelect(
1348 Command
->kernel
->hardware
,
1349 commandBufferLogical
,
1350 commandBufferObject
->entryPipe
,
1354 /* Do not skip pipe switching sequence. */
1358 /* Generate a LINK from the context buffer to
1359 the command buffer. */
1360 gcmkONERROR(gckHARDWARE_Link(
1362 contextBuffer
->link3D
,
1363 commandBufferLogical
+ offset
,
1364 commandBufferSize
- offset
,
1370 /***************************************************************
1371 ** SWITCHING CONTEXT: "XD" command buffer - neither 2D nor 3D.
1374 /* Mark 3D as dirty. */
1375 Context
->dirty3D
= gcvTRUE
;
1377 /* Compute the entry. */
1378 if (Command
->pipeSelect
== gcvPIPE_3D
)
1381 = (gctUINT8_PTR
) contextBuffer
->physical
1382 + Context
->entryOffsetXDFrom3D
;
1385 = (gctUINT8_PTR
) contextBuffer
->logical
1386 + Context
->entryOffsetXDFrom3D
;
1389 = Context
->bufferSize
1390 - Context
->entryOffsetXDFrom3D
;
1395 = (gctUINT8_PTR
) contextBuffer
->physical
1396 + Context
->entryOffsetXDFrom2D
;
1399 = (gctUINT8_PTR
) contextBuffer
->logical
1400 + Context
->entryOffsetXDFrom2D
;
1403 = Context
->totalSize
1404 - Context
->entryOffsetXDFrom2D
;
1407 /* See if we have to switch pipes between the context
1408 and command buffers. */
1409 if (commandBufferObject
->entryPipe
== gcvPIPE_3D
)
1411 /* Skip pipe switching sequence. */
1416 /* The current hardware and the initial context pipes are
1417 different, switch to the correct pipe. */
1418 gcmkONERROR(gckHARDWARE_PipeSelect(
1419 Command
->kernel
->hardware
,
1420 commandBufferLogical
,
1421 commandBufferObject
->entryPipe
,
1425 /* Do not skip pipe switching sequence. */
1429 /* Generate a LINK from the context buffer to
1430 the command buffer. */
1431 gcmkONERROR(gckHARDWARE_Link(
1433 contextBuffer
->link3D
,
1434 commandBufferLogical
+ offset
,
1435 commandBufferSize
- offset
,
1441 #if gcdNONPAGED_MEMORY_CACHEABLE
1442 /* Flush the context buffer cache. */
1443 gcmkONERROR(gckOS_CacheClean(
1445 Command
->kernelProcessID
,
1453 /* Update the current context. */
1454 Command
->currContext
= Context
;
1457 contextDumpLogical
= entryLogical
;
1458 contextDumpBytes
= entryBytes
;
1465 /* Determine context entry and exit points. */
1466 if (commandBufferObject
->using2D
&& Context
->dirty2D
)
1468 /* Reset 2D dirty flag. */
1469 Context
->dirty2D
= gcvFALSE
;
1471 /* Get the "dirty" context buffer. */
1472 contextBuffer
= Context
->dirtyBuffer
;
1474 if (commandBufferObject
->using3D
&& Context
->dirty3D
)
1476 /* Reset 3D dirty flag. */
1477 Context
->dirty3D
= gcvFALSE
;
1479 /* Compute the entry. */
1480 if (Command
->pipeSelect
== gcvPIPE_2D
)
1482 entryPhysical
= (gctUINT8_PTR
) contextBuffer
->physical
+ pipeBytes
;
1483 entryLogical
= (gctUINT8_PTR
) contextBuffer
->logical
+ pipeBytes
;
1484 entryBytes
= Context
->bufferSize
- pipeBytes
;
1488 entryPhysical
= (gctUINT8_PTR
) contextBuffer
->physical
;
1489 entryLogical
= (gctUINT8_PTR
) contextBuffer
->logical
;
1490 entryBytes
= Context
->bufferSize
;
1493 /* See if we have to switch pipes between the context
1494 and command buffers. */
1495 if (commandBufferObject
->entryPipe
== gcvPIPE_3D
)
1497 /* Skip pipe switching sequence. */
1502 /* The current hardware and the initial context pipes are
1503 different, switch to the correct pipe. */
1504 gcmkONERROR(gckHARDWARE_PipeSelect(
1505 Command
->kernel
->hardware
,
1506 commandBufferLogical
,
1507 commandBufferObject
->entryPipe
,
1511 /* Do not skip pipe switching sequence. */
1515 /* Ensure the NOP between 2D and 3D is in place so that the
1516 execution falls through from 2D to 3D. */
1517 gcmkONERROR(gckHARDWARE_Nop(
1519 contextBuffer
->link2D
,
1523 /* Generate a LINK from the context buffer to
1524 the command buffer. */
1525 gcmkONERROR(gckHARDWARE_Link(
1527 contextBuffer
->link3D
,
1528 commandBufferLogical
+ offset
,
1529 commandBufferSize
- offset
,
1535 /* Compute the entry. */
1536 if (Command
->pipeSelect
== gcvPIPE_2D
)
1538 entryPhysical
= (gctUINT8_PTR
) contextBuffer
->physical
+ pipeBytes
;
1539 entryLogical
= (gctUINT8_PTR
) contextBuffer
->logical
+ pipeBytes
;
1540 entryBytes
= Context
->entryOffset3D
- pipeBytes
;
1544 entryPhysical
= (gctUINT8_PTR
) contextBuffer
->physical
;
1545 entryLogical
= (gctUINT8_PTR
) contextBuffer
->logical
;
1546 entryBytes
= Context
->entryOffset3D
;
1549 /* See if we have to switch pipes between the context
1550 and command buffers. */
1551 if (commandBufferObject
->entryPipe
== gcvPIPE_2D
)
1553 /* Skip pipe switching sequence. */
1558 /* The current hardware and the initial context pipes are
1559 different, switch to the correct pipe. */
1560 gcmkONERROR(gckHARDWARE_PipeSelect(
1561 Command
->kernel
->hardware
,
1562 commandBufferLogical
,
1563 commandBufferObject
->entryPipe
,
1567 /* Do not skip pipe switching sequence. */
1571 /* 3D is not used, generate a LINK from the end of 2D part of
1572 the context buffer to the command buffer. */
1573 gcmkONERROR(gckHARDWARE_Link(
1575 contextBuffer
->link2D
,
1576 commandBufferLogical
+ offset
,
1577 commandBufferSize
- offset
,
1584 if (commandBufferObject
->using3D
&& Context
->dirty3D
)
1586 /* Reset 3D dirty flag. */
1587 Context
->dirty3D
= gcvFALSE
;
1589 /* Get the "dirty" context buffer. */
1590 contextBuffer
= Context
->dirtyBuffer
;
1592 /* Determine context buffer entry offset. */
1593 offset
= (Command
->pipeSelect
== gcvPIPE_3D
)
1595 /* Skip pipe switching sequence. */
1596 ? Context
->entryOffset3D
+ pipeBytes
1598 /* Do not skip pipe switching sequence. */
1599 : Context
->entryOffset3D
;
1601 /* Compute the entry. */
1602 entryPhysical
= (gctUINT8_PTR
) contextBuffer
->physical
+ offset
;
1603 entryLogical
= (gctUINT8_PTR
) contextBuffer
->logical
+ offset
;
1604 entryBytes
= Context
->bufferSize
- offset
;
1606 /* See if we have to switch pipes between the context
1607 and command buffers. */
1608 if (commandBufferObject
->entryPipe
== gcvPIPE_3D
)
1610 /* Skip pipe switching sequence. */
1615 /* The current hardware and the initial context pipes are
1616 different, switch to the correct pipe. */
1617 gcmkONERROR(gckHARDWARE_PipeSelect(
1618 Command
->kernel
->hardware
,
1619 commandBufferLogical
,
1620 commandBufferObject
->entryPipe
,
1624 /* Do not skip pipe switching sequence. */
1628 /* Generate a LINK from the context buffer to
1629 the command buffer. */
1630 gcmkONERROR(gckHARDWARE_Link(
1632 contextBuffer
->link3D
,
1633 commandBufferLogical
+ offset
,
1634 commandBufferSize
- offset
,
1640 /* See if we have to switch pipes for the command buffer. */
1641 if (commandBufferObject
->entryPipe
== Command
->pipeSelect
)
1643 /* Skip pipe switching sequence. */
1648 /* The current hardware and the entry command buffer pipes
1649 ** are different, switch to the correct pipe. */
1650 gcmkONERROR(gckHARDWARE_PipeSelect(
1651 Command
->kernel
->hardware
,
1652 commandBufferLogical
,
1653 commandBufferObject
->entryPipe
,
1657 /* Do not skip pipe switching sequence. */
1661 /* Compute the entry. */
1662 entryPhysical
= (gctUINT8_PTR
) commandBufferPhysical
+ offset
;
1663 entryLogical
= commandBufferLogical
+ offset
;
1664 entryBytes
= commandBufferSize
- offset
;
1670 bufferDumpLogical
= commandBufferLogical
+ offset
;
1671 bufferDumpBytes
= commandBufferSize
- offset
;
1675 /* Process user hints. */
1676 gcmkONERROR(_ProcessHints(Command
, ProcessID
, commandBufferObject
));
1679 /* Get the current offset. */
1680 offset
= Command
->offset
;
1682 /* Compute number of bytes left in current kernel command queue. */
1683 bytes
= Command
->pageSize
- offset
;
1685 /* Query the size of WAIT/LINK command sequence. */
1686 gcmkONERROR(gckHARDWARE_WaitLink(
1695 /* Is there enough space in the current command queue? */
1696 if (bytes
< waitLinkBytes
)
1698 /* No, create a new one. */
1699 gcmkONERROR(_NewQueue(Command
));
1701 /* Get the new current offset. */
1702 offset
= Command
->offset
;
1704 /* Recompute the number of bytes in the new kernel command queue. */
1705 bytes
= Command
->pageSize
- offset
;
1706 gcmkASSERT(bytes
>= waitLinkBytes
);
1709 /* Compute the location if WAIT/LINK command sequence. */
1710 waitLinkPhysical
= (gctUINT8_PTR
) Command
->physical
+ offset
;
1711 waitLinkLogical
= (gctUINT8_PTR
) Command
->logical
+ offset
;
1713 /* Determine the location to jump to for the command buffer being
1715 if (Command
->newQueue
)
1717 /* New command queue, jump to the beginning of it. */
1718 exitPhysical
= Command
->physical
;
1719 exitLogical
= Command
->logical
;
1720 exitBytes
= Command
->offset
+ waitLinkBytes
;
1724 /* Still within the preexisting command queue, jump to the new
1725 WAIT/LINK command sequence. */
1726 exitPhysical
= waitLinkPhysical
;
1727 exitLogical
= waitLinkLogical
;
1728 exitBytes
= waitLinkBytes
;
1731 /* Add a new WAIT/LINK command sequence. When the command buffer which is
1732 currently being scheduled is fully executed by the GPU, the FE will
1733 jump to this WAIT/LINK sequence. */
1734 gcmkONERROR(gckHARDWARE_WaitLink(
1743 /* Compute the location if WAIT command. */
1744 waitPhysical
= (gctUINT8_PTR
) waitLinkPhysical
+ waitOffset
;
1745 waitLogical
= (gctUINT8_PTR
) waitLinkLogical
+ waitOffset
;
1747 #if gcdNONPAGED_MEMORY_CACHEABLE
1748 /* Flush the command queue cache. */
1749 gcmkONERROR(gckOS_CacheClean(
1751 Command
->kernelProcessID
,
1759 /* Determine the location of the LINK command in the command buffer. */
1761 = (gctUINT8_PTR
) commandBufferObject
->logical
1762 + commandBufferObject
->offset
;
1764 /* Generate a LINK from the end of the command buffer being scheduled
1765 back to the kernel command queue. */
1766 gcmkONERROR(gckHARDWARE_Link(
1774 #if gcdNONPAGED_MEMORY_CACHEABLE
1775 /* Flush the command buffer cache. */
1776 gcmkONERROR(gckOS_CacheClean(
1780 commandBufferPhysical
,
1781 commandBufferLogical
,
1786 /* Generate a LINK from the previous WAIT/LINK command sequence to the
1787 entry determined above (either the context or the command buffer).
1788 This LINK replaces the WAIT instruction from the previous WAIT/LINK
1789 pair, therefore we use WAIT metrics for generation of this LINK.
1790 This action will execute the entire sequence. */
1791 gcmkONERROR(gckHARDWARE_Link(
1793 Command
->waitLogical
,
1799 #if gcdNONPAGED_MEMORY_CACHEABLE
1800 /* Flush the cache for the link. */
1801 gcmkONERROR(gckOS_CacheClean(
1803 Command
->kernelProcessID
,
1805 Command
->waitPhysical
,
1806 Command
->waitLogical
,
1813 Command
->waitLogical
,
1815 gceDUMP_BUFFER_LINK
,
1823 gceDUMP_BUFFER_CONTEXT
,
1831 gceDUMP_BUFFER_USER
,
1839 gceDUMP_BUFFER_WAITLINK
,
1843 /* Update the current pipe. */
1844 Command
->pipeSelect
= commandBufferObject
->exitPipe
;
1846 /* Update command queue offset. */
1847 Command
->offset
+= waitLinkBytes
;
1848 Command
->newQueue
= gcvFALSE
;
1850 /* Update address of last WAIT. */
1851 Command
->waitPhysical
= waitPhysical
;
1852 Command
->waitLogical
= waitLogical
;
1853 Command
->waitSize
= waitSize
;
1855 /* Update queue tail pointer. */
1856 gcmkONERROR(gckHARDWARE_UpdateQueueTail(
1857 hardware
, Command
->logical
, Command
->offset
1860 #if gcdDUMP_COMMAND && !gcdSIMPLE_COMMAND_DUMP
1861 gcmkPRINT("@[kernel.commit]");
1864 /* Release the context switching mutex. */
1865 gcmkONERROR(gckOS_ReleaseMutex(Command
->os
, Command
->mutexContext
));
1866 contextAcquired
= gcvFALSE
;
1868 /* Release the command queue. */
1869 gcmkONERROR(gckCOMMAND_ExitCommit(Command
, gcvFALSE
));
1870 commitEntered
= gcvFALSE
;
1872 /* Loop while there are records in the queue. */
1873 while (EventQueue
!= gcvNULL
)
1877 /* Point to stack record. */
1878 eventRecord
= &_eventRecord
;
1880 /* Copy the data from the client. */
1881 gcmkONERROR(gckOS_CopyFromUserData(
1882 Command
->os
, eventRecord
, EventQueue
, gcmSIZEOF(gcsQUEUE
)
1887 /* Map record into kernel memory. */
1888 gcmkONERROR(gckOS_MapUserPointer(Command
->os
,
1890 gcmSIZEOF(gcsQUEUE
),
1893 eventRecord
= pointer
;
1896 /* Append event record to event queue. */
1897 gcmkONERROR(gckEVENT_AddList(
1898 Command
->kernel
->eventObj
, &eventRecord
->iface
, gcvKERNEL_PIXEL
, gcvTRUE
1901 /* Next record in the queue. */
1902 nextEventRecord
= eventRecord
->next
;
1906 /* Unmap record from kernel memory. */
1907 gcmkONERROR(gckOS_UnmapUserPointer(
1908 Command
->os
, EventQueue
, gcmSIZEOF(gcsQUEUE
), (gctPOINTER
*) eventRecord
1911 eventRecord
= gcvNULL
;
1914 EventQueue
= nextEventRecord
;
1917 /* Submit events. */
1918 gcmkONERROR(gckEVENT_Submit(Command
->kernel
->eventObj
, gcvTRUE
, gcvFALSE
));
1920 /* Unmap the command buffer pointer. */
1921 if (commandBufferMapped
)
1923 gcmkONERROR(gckOS_UnmapUserPointer(
1926 gcmSIZEOF(struct _gcoCMDBUF
),
1930 commandBufferMapped
= gcvFALSE
;
1933 /* Return status. */
1935 return gcvSTATUS_OK
;
1938 if ((eventRecord
!= gcvNULL
) && !needCopy
)
1941 gcmkVERIFY_OK(gckOS_UnmapUserPointer(
1944 gcmSIZEOF(gcsQUEUE
),
1945 (gctPOINTER
*) eventRecord
1949 if (contextAcquired
)
1951 /* Release the context switching mutex. */
1952 gcmkVERIFY_OK(gckOS_ReleaseMutex(Command
->os
, Command
->mutexContext
));
1957 /* Release the command queue mutex. */
1958 gcmkVERIFY_OK(gckCOMMAND_ExitCommit(Command
, gcvFALSE
));
1961 /* Unmap the command buffer pointer. */
1962 if (commandBufferMapped
)
1964 gcmkVERIFY_OK(gckOS_UnmapUserPointer(
1967 gcmSIZEOF(struct _gcoCMDBUF
),
1972 /* Return status. */
1978 /*******************************************************************************
1980 ** gckCOMMAND_Reserve
1982 ** Reserve space in the command queue. Also acquire the command queue mutex.
1986 ** gckCOMMAND Command
1987 ** Pointer to an gckCOMMAND object.
1989 ** gctSIZE_T RequestedBytes
1990 ** Number of bytes previously reserved.
1994 ** gctPOINTER * Buffer
1995 ** Pointer to a variable that will receive the address of the reserved
1998 ** gctSIZE_T * BufferSize
1999 ** Pointer to a variable that will receive the number of bytes
2000 ** available in the command queue.
2004 IN gckCOMMAND Command
,
2005 IN gctSIZE_T RequestedBytes
,
2006 OUT gctPOINTER
* Buffer
,
2007 OUT gctSIZE_T
* BufferSize
2012 gctSIZE_T requiredBytes
;
2013 gctUINT32 requestedAligned
;
2015 gcmkHEADER_ARG("Command=0x%x RequestedBytes=%lu", Command
, RequestedBytes
);
2017 /* Verify the arguments. */
2018 gcmkVERIFY_OBJECT(Command
, gcvOBJ_COMMAND
);
2020 /* Compute aligned number of reuested bytes. */
2021 requestedAligned
= gcmALIGN(RequestedBytes
, Command
->alignment
);
2023 /* Another WAIT/LINK command sequence will have to be appended after
2024 the requested area being reserved. Compute the number of bytes
2025 required for WAIT/LINK at the location after the reserved area. */
2026 gcmkONERROR(gckHARDWARE_WaitLink(
2027 Command
->kernel
->hardware
,
2029 Command
->offset
+ requestedAligned
,
2035 /* Compute total number of bytes required. */
2036 requiredBytes
+= requestedAligned
;
2038 /* Compute number of bytes available in command queue. */
2039 bytes
= Command
->pageSize
- Command
->offset
;
2041 /* Is there enough space in the current command queue? */
2042 if (bytes
< requiredBytes
)
2044 /* Create a new command queue. */
2045 gcmkONERROR(_NewQueue(Command
));
2047 /* Recompute the number of bytes in the new kernel command queue. */
2048 bytes
= Command
->pageSize
- Command
->offset
;
2050 /* Still not enough space? */
2051 if (bytes
< requiredBytes
)
2053 /* Rare case, not enough room in command queue. */
2054 gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL
);
2058 /* Return pointer to empty slot command queue. */
2059 *Buffer
= (gctUINT8
*) Command
->logical
+ Command
->offset
;
2061 /* Return number of bytes left in command queue. */
2062 *BufferSize
= bytes
;
2065 gcmkFOOTER_ARG("*Buffer=0x%x *BufferSize=%lu", *Buffer
, *BufferSize
);
2066 return gcvSTATUS_OK
;
2069 /* Return status. */
2074 /*******************************************************************************
2076 ** gckCOMMAND_Execute
2078 ** Execute a previously reserved command queue by appending a WAIT/LINK command
2079 ** sequence after it and modifying the last WAIT into a LINK command. The
2080 ** command FIFO mutex will be released whether this function succeeds or not.
2084 ** gckCOMMAND Command
2085 ** Pointer to an gckCOMMAND object.
2087 ** gctSIZE_T RequestedBytes
2088 ** Number of bytes previously reserved.
2096 IN gckCOMMAND Command
,
2097 IN gctSIZE_T RequestedBytes
2102 gctPHYS_ADDR waitLinkPhysical
;
2103 gctUINT8_PTR waitLinkLogical
;
2104 gctUINT32 waitLinkOffset
;
2105 gctSIZE_T waitLinkBytes
;
2107 gctPHYS_ADDR waitPhysical
;
2108 gctPOINTER waitLogical
;
2109 gctUINT32 waitOffset
;
2110 gctSIZE_T waitBytes
;
2112 gctPHYS_ADDR execPhysical
;
2113 gctPOINTER execLogical
;
2114 gctSIZE_T execBytes
;
2116 gcmkHEADER_ARG("Command=0x%x RequestedBytes=%lu", Command
, RequestedBytes
);
2118 /* Verify the arguments. */
2119 gcmkVERIFY_OBJECT(Command
, gcvOBJ_COMMAND
);
2121 /* Compute offset for WAIT/LINK. */
2122 waitLinkOffset
= Command
->offset
+ RequestedBytes
;
2124 /* Compute number of bytes left in command queue. */
2125 waitLinkBytes
= Command
->pageSize
- waitLinkOffset
;
2127 /* Compute the location if WAIT/LINK command sequence. */
2128 waitLinkPhysical
= (gctUINT8_PTR
) Command
->physical
+ waitLinkOffset
;
2129 waitLinkLogical
= (gctUINT8_PTR
) Command
->logical
+ waitLinkOffset
;
2131 /* Append WAIT/LINK in command queue. */
2132 gcmkONERROR(gckHARDWARE_WaitLink(
2133 Command
->kernel
->hardware
,
2141 /* Compute the location if WAIT command. */
2142 waitPhysical
= (gctUINT8_PTR
) waitLinkPhysical
+ waitOffset
;
2143 waitLogical
= waitLinkLogical
+ waitOffset
;
2145 /* Determine the location to jump to for the command buffer being
2147 if (Command
->newQueue
)
2149 /* New command queue, jump to the beginning of it. */
2150 execPhysical
= Command
->physical
;
2151 execLogical
= Command
->logical
;
2152 execBytes
= waitLinkOffset
+ waitLinkBytes
;
2156 /* Still within the preexisting command queue, jump directly to the
2158 execPhysical
= (gctUINT8
*) Command
->physical
+ Command
->offset
;
2159 execLogical
= (gctUINT8
*) Command
->logical
+ Command
->offset
;
2160 execBytes
= RequestedBytes
+ waitLinkBytes
;
2163 #if gcdNONPAGED_MEMORY_CACHEABLE
2164 /* Flush the cache. */
2165 gcmkONERROR(gckOS_CacheClean(
2167 Command
->kernelProcessID
,
2175 /* Convert the last WAIT into a LINK. */
2176 gcmkONERROR(gckHARDWARE_Link(
2177 Command
->kernel
->hardware
,
2178 Command
->waitLogical
,
2184 #if gcdNONPAGED_MEMORY_CACHEABLE
2185 /* Flush the cache. */
2186 gcmkONERROR(gckOS_CacheClean(
2188 Command
->kernelProcessID
,
2190 Command
->waitPhysical
,
2191 Command
->waitLogical
,
2198 Command
->waitLogical
,
2200 gceDUMP_BUFFER_LINK
,
2208 gceDUMP_BUFFER_KERNEL
,
2212 /* Update the pointer to the last WAIT. */
2213 Command
->waitPhysical
= waitPhysical
;
2214 Command
->waitLogical
= waitLogical
;
2215 Command
->waitSize
= waitBytes
;
2217 /* Update the command queue. */
2218 Command
->offset
+= RequestedBytes
+ waitLinkBytes
;
2219 Command
->newQueue
= gcvFALSE
;
2221 /* Update queue tail pointer. */
2222 gcmkONERROR(gckHARDWARE_UpdateQueueTail(
2223 Command
->kernel
->hardware
, Command
->logical
, Command
->offset
2226 #if gcdDUMP_COMMAND && !gcdSIMPLE_COMMAND_DUMP
2227 gcmkPRINT("@[kernel.execute]");
2232 return gcvSTATUS_OK
;
2235 /* Return the status. */
2240 /*******************************************************************************
2244 ** The calling thread will be suspended until the command queue has been
2249 ** gckCOMMAND Command
2250 ** Pointer to an gckCOMMAND object.
2252 ** gctBOOL FromPower
2253 ** Determines whether the call originates from inside the power
2254 ** management or not.
2262 IN gckCOMMAND Command
,
2263 IN gctBOOL FromPower
2267 /* Do nothing with infinite hardware. */
2268 return gcvSTATUS_OK
;
2271 gckHARDWARE hardware
;
2272 gckEVENT eventObject
;
2274 gctSIGNAL signal
= gcvNULL
;
2277 gcmkHEADER_ARG("Command=0x%x", Command
);
2279 /* Verify the arguments. */
2280 gcmkVERIFY_OBJECT(Command
, gcvOBJ_COMMAND
);
2282 /* Extract the gckOS object pointer. */
2284 gcmkVERIFY_OBJECT(os
, gcvOBJ_OS
);
2286 /* Extract the gckHARDWARE object pointer. */
2287 hardware
= Command
->kernel
->hardware
;
2288 gcmkVERIFY_OBJECT(hardware
, gcvOBJ_HARDWARE
);
2290 /* Extract the gckEVENT object pointer. */
2291 eventObject
= Command
->kernel
->eventObj
;
2292 gcmkVERIFY_OBJECT(eventObject
, gcvOBJ_EVENT
);
2294 /* Allocate the signal. */
2295 gcmkONERROR(gckOS_CreateSignal(os
, gcvTRUE
, &signal
));
2297 /* Append the EVENT command to trigger the signal. */
2298 gcmkONERROR(gckEVENT_Signal(eventObject
, signal
, gcvKERNEL_PIXEL
));
2300 /* Submit the event queue. */
2301 gcmkONERROR(gckEVENT_Submit(eventObject
, gcvTRUE
, FromPower
));
2303 #if gcdDUMP_COMMAND && !gcdSIMPLE_COMMAND_DUMP
2304 gcmkPRINT("@[kernel.stall]");
2307 if (status
== gcvSTATUS_CHIP_NOT_READY
)
2315 /* Wait for the signal. */
2316 status
= gckOS_WaitSignal(os
, signal
, gcdGPU_ADVANCETIMER
);
2318 if (status
== gcvSTATUS_TIMEOUT
)
2320 #if gcmIS_DEBUG(gcdDEBUG_CODE)
2323 /* Read idle register. */
2324 gcmkVERIFY_OK(gckHARDWARE_GetIdle(
2325 hardware
, gcvFALSE
, &idle
2330 "%s(%d): idle=%08x",
2331 __FUNCTION__
, __LINE__
, idle
2334 gcmkONERROR(gckOS_MemoryBarrier(os
, gcvNULL
));
2337 gctUINT32 reg_cmdbuf_fetch
;
2340 gcmkVERIFY_OK(gckOS_ReadRegisterEx(
2341 Command
->kernel
->hardware
->os
, Command
->kernel
->core
, 0x0664, ®_cmdbuf_fetch
2344 if (idle
== 0x7FFFFFFE)
2347 * GPU is idle so there should not be pending interrupts.
2348 * Just double check.
2350 * Note that reading interrupt register clears it.
2351 * That's why we don't read it in all cases.
2353 gcmkVERIFY_OK(gckOS_ReadRegisterEx(
2354 Command
->kernel
->hardware
->os
, Command
->kernel
->core
, 0x10, ®_intr
2358 _SLOG_SETCODE(1, 0),
2360 "GALcore: Stall timeout (idle = 0x%X, command buffer fetch = 0x%X, interrupt = 0x%X)",
2361 idle
, reg_cmdbuf_fetch
, reg_intr
2367 _SLOG_SETCODE(1, 0),
2369 "GALcore: Stall timeout (idle = 0x%X, command buffer fetch = 0x%X)",
2370 idle
, reg_cmdbuf_fetch
2375 /* Advance timer. */
2376 timer
+= gcdGPU_ADVANCETIMER
;
2379 while (gcmIS_ERROR(status
)
2381 && (timer
< Command
->kernel
->timeOut
)
2385 /* Bail out on timeout. */
2386 if (gcmIS_ERROR(status
))
2388 /* Broadcast the stuck GPU. */
2389 gcmkONERROR(gckOS_Broadcast(
2390 os
, hardware
, gcvBROADCAST_GPU_STUCK
2393 gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING
);
2396 /* Delete the signal. */
2397 gcmkVERIFY_OK(gckOS_DestroySignal(os
, signal
));
2401 return gcvSTATUS_OK
;
2404 if (signal
!= gcvNULL
)
2406 /* Free the signal. */
2407 gcmkVERIFY_OK(gckOS_DestroySignal(os
, signal
));
2410 /* Return the status. */
2416 /*******************************************************************************
2418 ** gckCOMMAND_Attach
2420 ** Attach user process.
2424 ** gckCOMMAND Command
2425 ** Pointer to a gckCOMMAND object.
2427 ** gctUINT32 ProcessID
2428 ** Current process ID.
2432 ** gckCONTEXT * Context
2433 ** Pointer to a variable that will receive a pointer to a new
2434 ** gckCONTEXT object.
2436 ** gctSIZE_T * StateCount
2437 ** Pointer to a variable that will receive the number of states
2438 ** in the context buffer.
2442 IN gckCOMMAND Command
,
2443 OUT gckCONTEXT
* Context
,
2444 OUT gctSIZE_T
* StateCount
,
2445 IN gctUINT32 ProcessID
2449 gctBOOL acquired
= gcvFALSE
;
2451 gcmkHEADER_ARG("Command=0x%x", Command
);
2453 /* Verify the arguments. */
2454 gcmkVERIFY_OBJECT(Command
, gcvOBJ_COMMAND
);
2456 /* Acquire the context switching mutex. */
2457 gcmkONERROR(gckOS_AcquireMutex(
2458 Command
->os
, Command
->mutexContext
, gcvINFINITE
2462 /* Construct a gckCONTEXT object. */
2463 gcmkONERROR(gckCONTEXT_Construct(
2465 Command
->kernel
->hardware
,
2470 /* Return the number of states in the context. */
2471 * StateCount
= (* Context
)->stateCount
;
2473 /* Release the context switching mutex. */
2474 gcmkONERROR(gckOS_ReleaseMutex(Command
->os
, Command
->mutexContext
));
2475 acquired
= gcvFALSE
;
2478 gcmkFOOTER_ARG("*Context=0x%x", *Context
);
2479 return gcvSTATUS_OK
;
2482 /* Release mutex. */
2485 /* Release the context switching mutex. */
2486 gcmkVERIFY_OK(gckOS_ReleaseMutex(Command
->os
, Command
->mutexContext
));
2487 acquired
= gcvFALSE
;
2490 /* Return the status. */
2495 /*******************************************************************************
2497 ** gckCOMMAND_Detach
2499 ** Detach user process.
2503 ** gckCOMMAND Command
2504 ** Pointer to a gckCOMMAND object.
2506 ** gckCONTEXT Context
2507 ** Pointer to a gckCONTEXT object to be destroyed.
2515 IN gckCOMMAND Command
,
2516 IN gckCONTEXT Context
2520 gctBOOL acquired
= gcvFALSE
;
2522 gcmkHEADER_ARG("Command=0x%x Context=0x%x", Command
, Context
);
2524 /* Verify the arguments. */
2525 gcmkVERIFY_OBJECT(Command
, gcvOBJ_COMMAND
);
2527 /* Acquire the context switching mutex. */
2528 gcmkONERROR(gckOS_AcquireMutex(
2529 Command
->os
, Command
->mutexContext
, gcvINFINITE
2533 /* Construct a gckCONTEXT object. */
2534 gcmkONERROR(gckCONTEXT_Destroy(Context
));
2536 /* Release the context switching mutex. */
2537 gcmkONERROR(gckOS_ReleaseMutex(Command
->os
, Command
->mutexContext
));
2538 acquired
= gcvFALSE
;
2540 /* Return the status. */
2542 return gcvSTATUS_OK
;
2545 /* Release mutex. */
2548 /* Release the context switching mutex. */
2549 gcmkVERIFY_OK(gckOS_ReleaseMutex(Command
->os
, Command
->mutexContext
));
2550 acquired
= gcvFALSE
;
2553 /* Return the status. */