ENGR00156850 gpu-viv: add gpu-viv driver source
[wandboard.git] / drivers / mxc / gpu-viv / hal / kernel / gc_hal_kernel_command_vg.c
blob68b2d60298c1865099c1a3cc841760f705acaf9b
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"
26 #if gcdENABLE_VG
28 #include "gc_hal_kernel_hardware_command_vg.h"
30 #define _GC_OBJ_ZONE gcvZONE_COMMAND
32 /******************************************************************************\
33 *********************************** Debugging **********************************
34 \******************************************************************************/
36 #define gcvDISABLE_TIMEOUT 1
37 #define gcvDUMP_COMMAND_BUFFER 0
38 #define gcvDUMP_COMMAND_LINES 0
41 #if gcvDEBUG || defined(EMULATOR) || gcvDISABLE_TIMEOUT
42 # define gcvQUEUE_TIMEOUT ~0
43 #else
44 # define gcvQUEUE_TIMEOUT 10
45 #endif
48 /******************************************************************************\
49 ********************************** Definitions *********************************
50 \******************************************************************************/
52 /* Minimum buffer size. */
53 #define gcvMINUMUM_BUFFER \
54 gcmSIZEOF(gcsKERNEL_QUEUE_HEADER) + \
55 gcmSIZEOF(gcsKERNEL_CMDQUEUE) * 2
57 #define gcmDECLARE_INTERRUPT_HANDLER(Block, Number) \
58 static gceSTATUS \
59 _EventHandler_##Block##_##Number( \
60 IN gckVGKERNEL Kernel \
63 #define gcmDEFINE_INTERRUPT_HANDLER(Block, Number) \
64 gcmDECLARE_INTERRUPT_HANDLER(Block, Number) \
65 { \
66 return _EventHandler_Block( \
67 Kernel, \
68 &Kernel->command->taskTable[gcvBLOCK_##Block], \
69 gcvFALSE \
70 ); \
73 #define gcmDEFINE_INTERRUPT_HANDLER_ENTRY(Block, Number) \
74 { gcvBLOCK_##Block, _EventHandler_##Block##_##Number }
76 /* Block interrupt handling table entry. */
77 typedef struct _gcsBLOCK_INTERRUPT_HANDLER * gcsBLOCK_INTERRUPT_HANDLER_PTR;
78 typedef struct _gcsBLOCK_INTERRUPT_HANDLER
80 gceBLOCK block;
81 gctINTERRUPT_HANDLER handler;
83 gcsBLOCK_INTERRUPT_HANDLER;
85 /* Queue control functions. */
86 typedef struct _gcsQUEUE_UPDATE_CONTROL * gcsQUEUE_UPDATE_CONTROL_PTR;
87 typedef struct _gcsQUEUE_UPDATE_CONTROL
89 gctOBJECT_HANDLER execute;
90 gctOBJECT_HANDLER update;
91 gctOBJECT_HANDLER lastExecute;
92 gctOBJECT_HANDLER lastUpdate;
94 gcsQUEUE_UPDATE_CONTROL;
97 /******************************************************************************\
98 ********************************* Support Code *********************************
99 \******************************************************************************/
101 static gceSTATUS
102 _WaitForIdle(
103 IN gckVGCOMMAND Command,
104 IN gcsKERNEL_QUEUE_HEADER_PTR Queue
107 gceSTATUS status = gcvSTATUS_OK;
108 gctUINT32 idle;
109 gctUINT timeout = 0;
111 /* Loop while not idle. */
112 while (Queue->pending)
114 /* Did we reach the timeout limit? */
115 if (timeout == gcvQUEUE_TIMEOUT)
117 /* Hardware is probably dead... */
118 return gcvSTATUS_TIMEOUT;
121 /* Sleep for 100ms. */
122 gcmkERR_BREAK(gckOS_Delay(Command->os, 100));
124 /* Not the first loop? */
125 if (timeout > 0)
127 /* Read IDLE register. */
128 gcmkVERIFY_OK(gckVGHARDWARE_GetIdle(Command->hardware, &idle));
130 gcmkTRACE_ZONE(
131 gcvLEVEL_ERROR, gcvZONE_COMMAND,
132 "%s: timeout, IDLE=%08X\n",
133 __FUNCTION__, idle
137 /* Increment the timeout counter. */
138 timeout += 1;
141 /* Return status. */
142 return status;
145 static gctINT32
146 _GetNextInterrupt(
147 IN gckVGCOMMAND Command,
148 IN gceBLOCK Block
151 gctUINT index;
152 gcsBLOCK_TASK_ENTRY_PTR entry;
153 gctINT32 interrupt;
155 /* Get the block entry. */
156 entry = &Command->taskTable[Block];
158 /* Make sure we have initialized interrupts. */
159 gcmkASSERT(entry->interruptCount > 0);
161 /* Decrement the interrupt usage semaphore. */
162 gcmkVERIFY_OK(gckOS_DecrementSemaphore(
163 Command->os, entry->interruptSemaphore
166 /* Get the value index. */
167 index = entry->interruptIndex;
169 /* Get the interrupt value. */
170 interrupt = entry->interruptArray[index];
172 /* Must be a valid value. */
173 gcmkASSERT((interrupt >= 0) && (interrupt <= 31));
175 /* Advance the index to the next value. */
176 index += 1;
178 /* Set the new index. */
179 entry->interruptIndex = (index == entry->interruptCount)
181 : index;
183 /* Return interrupt value. */
184 return interrupt;
188 /******************************************************************************\
189 ***************************** Task Storage Management **************************
190 \******************************************************************************/
192 /* Minimum task buffer size. */
193 #define gcvMIN_TASK_BUFFER \
195 gcmSIZEOF(gcsTASK_CONTAINER) + 128 \
198 /* Free list terminator. */
199 #define gcvFREE_TASK_TERMINATOR \
201 (gcsTASK_CONTAINER_PTR) gcmINT2PTR(~0) \
205 /*----------------------------------------------------------------------------*/
206 /*------------------- Allocated Task Buffer List Management ------------------*/
208 static void
209 _InsertTaskBuffer(
210 IN gcsTASK_CONTAINER_PTR AddAfter,
211 IN gcsTASK_CONTAINER_PTR Buffer
214 gcsTASK_CONTAINER_PTR addBefore;
216 /* Cannot add before the first buffer. */
217 gcmkASSERT(AddAfter != gcvNULL);
219 /* Create a shortcut to the next buffer. */
220 addBefore = AddAfter->allocNext;
222 /* Initialize the links. */
223 Buffer->allocPrev = AddAfter;
224 Buffer->allocNext = addBefore;
226 /* Link to the previous buffer. */
227 AddAfter->allocNext = Buffer;
229 /* Link to the next buffer. */
230 if (addBefore != gcvNULL)
232 addBefore->allocPrev = Buffer;
236 static void
237 _RemoveTaskBuffer(
238 IN gcsTASK_CONTAINER_PTR Buffer
241 gcsTASK_CONTAINER_PTR prev;
242 gcsTASK_CONTAINER_PTR next;
244 /* Cannot remove the first buffer. */
245 gcmkASSERT(Buffer->allocPrev != gcvNULL);
247 /* Create shortcuts to the previous and next buffers. */
248 prev = Buffer->allocPrev;
249 next = Buffer->allocNext;
251 /* Tail buffer? */
252 if (next == gcvNULL)
254 /* Remove from the list. */
255 prev->allocNext = gcvNULL;
258 /* Buffer from the middle. */
259 else
261 prev->allocNext = next;
262 next->allocPrev = prev;
267 /*----------------------------------------------------------------------------*/
268 /*--------------------- Free Task Buffer List Management ---------------------*/
270 static void
271 _AppendToFreeList(
272 IN gckVGCOMMAND Command,
273 IN gcsTASK_CONTAINER_PTR Buffer
276 /* Cannot be a part of the free list already. */
277 gcmkASSERT(Buffer->freePrev == gcvNULL);
278 gcmkASSERT(Buffer->freeNext == gcvNULL);
280 /* First buffer to add? */
281 if (Command->taskFreeHead == gcvNULL)
283 /* Terminate the links. */
284 Buffer->freePrev = gcvFREE_TASK_TERMINATOR;
285 Buffer->freeNext = gcvFREE_TASK_TERMINATOR;
287 /* Initialize the list pointer. */
288 Command->taskFreeHead = Command->taskFreeTail = Buffer;
291 /* Not the first, add after the tail. */
292 else
294 /* Initialize the new tail buffer. */
295 Buffer->freePrev = Command->taskFreeTail;
296 Buffer->freeNext = gcvFREE_TASK_TERMINATOR;
298 /* Add after the tail. */
299 Command->taskFreeTail->freeNext = Buffer;
300 Command->taskFreeTail = Buffer;
304 static void
305 _RemoveFromFreeList(
306 IN gckVGCOMMAND Command,
307 IN gcsTASK_CONTAINER_PTR Buffer
310 /* Has to be a part of the free list. */
311 gcmkASSERT(Buffer->freePrev != gcvNULL);
312 gcmkASSERT(Buffer->freeNext != gcvNULL);
314 /* Head buffer? */
315 if (Buffer->freePrev == gcvFREE_TASK_TERMINATOR)
317 /* Tail buffer as well? */
318 if (Buffer->freeNext == gcvFREE_TASK_TERMINATOR)
320 /* Reset the list pointer. */
321 Command->taskFreeHead = Command->taskFreeTail = gcvNULL;
324 /* No, just the head. */
325 else
327 /* Update the head. */
328 Command->taskFreeHead = Buffer->freeNext;
330 /* Terminate the next buffer. */
331 Command->taskFreeHead->freePrev = gcvFREE_TASK_TERMINATOR;
335 /* Not the head. */
336 else
338 /* Tail buffer? */
339 if (Buffer->freeNext == gcvFREE_TASK_TERMINATOR)
341 /* Update the tail. */
342 Command->taskFreeTail = Buffer->freePrev;
344 /* Terminate the previous buffer. */
345 Command->taskFreeTail->freeNext = gcvFREE_TASK_TERMINATOR;
348 /* A buffer in the middle. */
349 else
351 /* Remove the buffer from the list. */
352 Buffer->freePrev->freeNext = Buffer->freeNext;
353 Buffer->freeNext->freePrev = Buffer->freePrev;
357 /* Reset free list pointers. */
358 Buffer->freePrev = gcvNULL;
359 Buffer->freeNext = gcvNULL;
363 /*----------------------------------------------------------------------------*/
364 /*-------------------------- Task Buffer Allocation --------------------------*/
366 static void
367 _SplitTaskBuffer(
368 IN gckVGCOMMAND Command,
369 IN gcsTASK_CONTAINER_PTR Buffer,
370 IN gctUINT Size
373 /* Determine the size of the new buffer. */
374 gctINT splitBufferSize = Buffer->size - Size;
375 gcmkASSERT(splitBufferSize >= 0);
377 /* Is the split buffer big enough to become a separate buffer? */
378 if (splitBufferSize >= gcvMIN_TASK_BUFFER)
380 /* Place the new path data. */
381 gcsTASK_CONTAINER_PTR splitBuffer = (gcsTASK_CONTAINER_PTR)
383 (gctUINT8_PTR) Buffer + Size
386 /* Set the trimmed buffer size. */
387 Buffer->size = Size;
389 /* Initialize the split buffer. */
390 splitBuffer->referenceCount = 0;
391 splitBuffer->size = splitBufferSize;
392 splitBuffer->freePrev = gcvNULL;
393 splitBuffer->freeNext = gcvNULL;
395 /* Link in. */
396 _InsertTaskBuffer(Buffer, splitBuffer);
397 _AppendToFreeList(Command, splitBuffer);
401 static gceSTATUS
402 _AllocateTaskContainer(
403 IN gckVGCOMMAND Command,
404 IN gctUINT Size,
405 OUT gcsTASK_CONTAINER_PTR * Buffer
408 gceSTATUS status;
410 gcmkHEADER_ARG("Command=0x%x Size=0x%x, Buffer ==0x%x", Command, Size, Buffer);
412 /* Verify arguments. */
413 gcmkVERIFY_ARGUMENT(Buffer != gcvNULL);
417 gcsTASK_STORAGE_PTR storage;
418 gcsTASK_CONTAINER_PTR buffer;
420 /* Adjust the size. */
421 Size += gcmSIZEOF(gcsTASK_CONTAINER);
423 /* Adjust the allocation size if not big enough. */
424 if (Size > Command->taskStorageUsable)
426 Command->taskStorageGranularity
427 = gcmALIGN(Size + gcmSIZEOF(gcsTASK_STORAGE), 1024);
429 Command->taskStorageUsable
430 = Command->taskStorageGranularity - gcmSIZEOF(gcsTASK_STORAGE);
433 /* Is there a free buffer available? */
434 else if (Command->taskFreeHead != gcvNULL)
436 /* Set the initial free buffer. */
437 gcsTASK_CONTAINER_PTR buffer = Command->taskFreeHead;
441 /* Is the buffer big enough? */
442 if (buffer->size >= Size)
444 /* Remove the buffer from the free list. */
445 _RemoveFromFreeList(Command, buffer);
447 /* Split the buffer. */
448 _SplitTaskBuffer(Command, buffer, Size);
450 /* Set the result. */
451 * Buffer = buffer;
453 /* Success. */
454 return gcvSTATUS_OK;
457 /* Get the next free buffer. */
458 buffer = buffer->freeNext;
460 while (buffer != gcvFREE_TASK_TERMINATOR);
463 /* Allocate a container. */
464 gcmkERR_BREAK(gckOS_Allocate(
465 Command->os,
466 Command->taskStorageGranularity,
467 (gctPOINTER *) &storage
470 /* Link in the storage buffer. */
471 storage->next = Command->taskStorage;
472 Command->taskStorage = storage;
474 /* Place the task buffer. */
475 buffer = (gcsTASK_CONTAINER_PTR) (storage + 1);
477 /* Determine the size of the buffer. */
478 buffer->size
479 = Command->taskStorageGranularity
480 - gcmSIZEOF(gcsTASK_STORAGE);
482 /* Initialize the task buffer. */
483 buffer->referenceCount = 0;
484 buffer->allocPrev = gcvNULL;
485 buffer->allocNext = gcvNULL;
486 buffer->freePrev = gcvNULL;
487 buffer->freeNext = gcvNULL;
489 /* Split the buffer. */
490 _SplitTaskBuffer(Command, buffer, Size);
492 /* Set the result. */
493 * Buffer = buffer;
495 /* Success. */
496 return gcvSTATUS_OK;
498 while (gcvFALSE);
500 gcmkFOOTER();
501 /* Return status. */
502 return status;
505 static void
506 _FreeTaskContainer(
507 IN gckVGCOMMAND Command,
508 IN gcsTASK_CONTAINER_PTR Buffer
511 gcsTASK_CONTAINER_PTR prev;
512 gcsTASK_CONTAINER_PTR next;
513 gcsTASK_CONTAINER_PTR merged;
515 gctSIZE_T mergedSize;
517 /* Verify arguments. */
518 gcmkASSERT(Buffer != gcvNULL);
519 gcmkASSERT(Buffer->freePrev == gcvNULL);
520 gcmkASSERT(Buffer->freeNext == gcvNULL);
522 /* Get shortcuts to the previous and next path data buffers. */
523 prev = Buffer->allocPrev;
524 next = Buffer->allocNext;
526 /* Is the previous path data buffer already free? */
527 if (prev && prev->freeNext)
529 /* The previous path data buffer is the one that remains. */
530 merged = prev;
532 /* Is the next path data buffer already free? */
533 if (next && next->freeNext)
535 /* Merge all three path data buffers into the previous. */
536 mergedSize = prev->size + Buffer->size + next->size;
538 /* Remove the next path data buffer. */
539 _RemoveFromFreeList(Command, next);
540 _RemoveTaskBuffer(next);
542 else
544 /* Merge the current path data buffer into the previous. */
545 mergedSize = prev->size + Buffer->size;
548 /* Delete the current path data buffer. */
549 _RemoveTaskBuffer(Buffer);
551 /* Set new size. */
552 merged->size = mergedSize;
554 else
556 /* The current path data buffer is the one that remains. */
557 merged = Buffer;
559 /* Is the next buffer already free? */
560 if (next && next->freeNext)
562 /* Merge the next into the current. */
563 mergedSize = Buffer->size + next->size;
565 /* Remove the next buffer. */
566 _RemoveFromFreeList(Command, next);
567 _RemoveTaskBuffer(next);
569 /* Set new size. */
570 merged->size = mergedSize;
573 /* Add the current buffer into the free list. */
574 _AppendToFreeList(Command, merged);
579 /******************************************************************************\
580 ********************************* Task Scheduling ******************************
581 \******************************************************************************/
583 static gceSTATUS
584 _ScheduleTasks(
585 IN gckVGCOMMAND Command,
586 IN gcsTASK_MASTER_TABLE_PTR TaskTable,
587 IN gctUINT8_PTR PreviousEnd
590 gceSTATUS status;
594 gctINT block;
595 gcsTASK_CONTAINER_PTR container;
596 gcsTASK_MASTER_ENTRY_PTR userTaskEntry;
597 gcsBLOCK_TASK_ENTRY_PTR kernelTaskEntry;
598 gcsTASK_PTR userTask;
599 gctUINT8_PTR kernelTask;
600 gctINT32 interrupt;
601 gctUINT8_PTR eventCommand;
603 /* Nothing to schedule? */
604 if (TaskTable->size == 0)
606 status = gcvSTATUS_OK;
607 break;
610 /* Acquire the mutex. */
611 gcmkERR_BREAK(gckOS_AcquireMutex(
612 Command->os,
613 Command->taskMutex,
614 gcvINFINITE
617 gcmkTRACE_ZONE(
618 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
619 "%s(%d)\n",
620 __FUNCTION__, __LINE__
625 gcmkTRACE_ZONE(
626 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
627 " number of tasks scheduled = %d\n"
628 " size of event data in bytes = %d\n",
629 TaskTable->count,
630 TaskTable->size
633 /* Allocate task buffer. */
634 gcmkERR_BREAK(_AllocateTaskContainer(
635 Command,
636 TaskTable->size,
637 &container
640 /* Determine the task data pointer. */
641 kernelTask = (gctUINT8_PTR) (container + 1);
643 /* Initialize the reference count. */
644 container->referenceCount = TaskTable->count;
646 /* Process tasks. */
647 for (block = gcvBLOCK_COUNT - 1; block >= 0; block -= 1)
649 /* Get the current user table entry. */
650 userTaskEntry = &TaskTable->table[block];
652 /* Are there tasks scheduled? */
653 if (userTaskEntry->head == gcvNULL)
655 /* No, skip to the next block. */
656 continue;
659 gcmkTRACE_ZONE(
660 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
661 " processing tasks for block %d\n",
662 block
665 /* Get the current kernel table entry. */
666 kernelTaskEntry = &Command->taskTable[block];
668 /* Are there tasks for the current block scheduled? */
669 if (kernelTaskEntry->container == gcvNULL)
671 gcmkTRACE_ZONE(
672 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
673 " first task container for the block added\n",
674 block
677 /* Nothing yet, set the container buffer pointer. */
678 kernelTaskEntry->container = container;
679 kernelTaskEntry->task = (gcsTASK_HEADER_PTR) kernelTask;
682 /* Yes, append to the end. */
683 else
685 kernelTaskEntry->link->cotainer = container;
686 kernelTaskEntry->link->task = (gcsTASK_HEADER_PTR) kernelTask;
689 /* Set initial task. */
690 userTask = userTaskEntry->head;
692 gcmkTRACE_ZONE(
693 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
694 " copying user tasks over to the kernel\n"
697 /* Copy tasks. */
700 gcmkTRACE_ZONE(
701 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
702 " task ID = %d, size = %d\n",
703 ((gcsTASK_HEADER_PTR) (userTask + 1))->id,
704 userTask->size
707 /* Copy the task data. */
708 gcmkVERIFY_OK(gckOS_MemCopy(
709 kernelTask, userTask + 1, userTask->size
712 /* Advance to the next task. */
713 kernelTask += userTask->size;
714 userTask = userTask->next;
716 while (userTask != gcvNULL);
718 /* Update link pointer in the header. */
719 kernelTaskEntry->link = (gcsTASK_LINK_PTR) kernelTask;
721 /* Initialize link task. */
722 kernelTaskEntry->link->id = gcvTASK_LINK;
723 kernelTaskEntry->link->cotainer = gcvNULL;
724 kernelTaskEntry->link->task = gcvNULL;
726 /* Advance the task data pointer. */
727 kernelTask += gcmSIZEOF(gcsTASK_LINK);
730 while (gcvFALSE);
732 /* Release the mutex. */
733 gcmkERR_BREAK(gckOS_ReleaseMutex(
734 Command->os,
735 Command->taskMutex
738 /* Assign interrupts to the blocks. */
739 eventCommand = PreviousEnd;
741 for (block = gcvBLOCK_COUNT - 1; block >= 0; block -= 1)
743 /* Get the current user table entry. */
744 userTaskEntry = &TaskTable->table[block];
746 /* Are there tasks scheduled? */
747 if (userTaskEntry->head == gcvNULL)
749 /* No, skip to the next block. */
750 continue;
753 /* Get the interrupt number. */
754 interrupt = _GetNextInterrupt(Command, block);
756 gcmkTRACE_ZONE(
757 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
758 "%s(%d): block = %d interrupt = %d\n",
759 __FUNCTION__, __LINE__,
760 block, interrupt
763 /* Determine the command position. */
764 eventCommand -= Command->info.eventCommandSize;
766 /* Append an EVENT command. */
767 gcmkERR_BREAK(gckVGCOMMAND_EventCommand(
768 Command, eventCommand, block, interrupt, gcvNULL
772 while (gcvFALSE);
774 /* Return status. */
775 return status;
779 /******************************************************************************\
780 ******************************** Memory Management *****************************
781 \******************************************************************************/
783 static gceSTATUS
784 _HardwareToKernel(
785 IN gckOS Os,
786 IN gcuVIDMEM_NODE_PTR Node,
787 IN gctUINT32 Address,
788 OUT gctPOINTER * KernelPointer
791 gceSTATUS status;
792 gckVIDMEM memory;
793 gctUINT32 offset;
795 /* Assume a non-virtual node and get the pool manager object. */
796 memory = Node->VidMem.memory;
798 /* Determine the header offset within the pool it is allocated in. */
799 offset = Address - memory->baseAddress;
801 /* Translate the offset into the kernel side pointer. */
802 status = gckOS_GetKernelLogicalEx(
804 gcvCORE_VG,
805 offset,
806 KernelPointer
809 /* Return status. */
810 return status;
813 static gceSTATUS
814 _ConvertUserCommandBufferPointer(
815 IN gckVGCOMMAND Command,
816 IN gcsCMDBUFFER_PTR UserCommandBuffer,
817 OUT gcsCMDBUFFER_PTR * KernelCommandBuffer
820 gceSTATUS status, last;
821 gcsCMDBUFFER_PTR mappedUserCommandBuffer = gcvNULL;
825 gctUINT32 headerAddress;
827 /* Map the command buffer structure into the kernel space. */
828 gcmkERR_BREAK(gckOS_MapUserPointer(
829 Command->os,
830 UserCommandBuffer,
831 gcmSIZEOF(gcsCMDBUFFER),
832 (gctPOINTER *) &mappedUserCommandBuffer
835 /* Determine the address of the header. */
836 headerAddress
837 = mappedUserCommandBuffer->address
838 - mappedUserCommandBuffer->bufferOffset;
840 /* Translate the logical address to the kernel space. */
841 gcmkERR_BREAK(_HardwareToKernel(
842 Command->os,
843 mappedUserCommandBuffer->node,
844 headerAddress,
845 (gctPOINTER *) KernelCommandBuffer
848 while (gcvFALSE);
850 /* Unmap the user command buffer. */
851 if (mappedUserCommandBuffer != gcvNULL)
853 gcmkCHECK_STATUS(gckOS_UnmapUserPointer(
854 Command->os,
855 UserCommandBuffer,
856 gcmSIZEOF(gcsCMDBUFFER),
857 mappedUserCommandBuffer
861 /* Return status. */
862 return status;
865 static gceSTATUS
866 _AllocateLinear(
867 IN gckVGCOMMAND Command,
868 IN gctUINT Size,
869 IN gctUINT Alignment,
870 OUT gcuVIDMEM_NODE_PTR * Node,
871 OUT gctUINT32 * Address,
872 OUT gctPOINTER * Logical
875 gceSTATUS status, last;
876 gcuVIDMEM_NODE_PTR node = gcvNULL;
877 gctUINT32 address = (gctUINT32)~0;
881 gcePOOL pool;
882 gctPOINTER logical;
884 /* Allocate from the system pool. */
885 pool = gcvPOOL_SYSTEM;
887 /* Allocate memory. */
888 gcmkERR_BREAK(gckKERNEL_AllocateLinearMemory(
889 Command->kernel->kernel, &pool,
890 Size, Alignment,
891 gcvSURF_TYPE_UNKNOWN,
892 &node
895 /* Do not accept virtual pools for now because we don't handle the
896 kernel pointer translation at the moment. */
897 if (pool == gcvPOOL_VIRTUAL)
899 status = gcvSTATUS_OUT_OF_MEMORY;
900 break;
903 /* Lock the command buffer. */
904 gcmkERR_BREAK(gckVIDMEM_Lock(
905 Command->kernel->kernel,
906 node,
907 gcvFALSE,
908 &address
911 /* Translate the logical address to the kernel space. */
912 gcmkERR_BREAK(_HardwareToKernel(
913 Command->os,
914 node,
915 address,
916 &logical
919 /* Set return values. */
920 * Node = node;
921 * Address = address;
922 * Logical = logical;
924 /* Success. */
925 return gcvSTATUS_OK;
927 while (gcvFALSE);
929 /* Roll back. */
930 if (node != gcvNULL)
932 /* Unlock the command buffer. */
933 if (address != ~0)
935 gcmkCHECK_STATUS(gckVIDMEM_Unlock(
936 Command->kernel->kernel, node, gcvSURF_TYPE_UNKNOWN, gcvNULL
940 /* Free the command buffer. */
941 gcmkCHECK_STATUS(gckVIDMEM_Free(
942 node
946 /* Return status. */
947 return status;
950 static gceSTATUS
951 _FreeLinear(
952 IN gckVGKERNEL Kernel,
953 IN gcuVIDMEM_NODE_PTR Node
956 gceSTATUS status;
960 /* Unlock the linear buffer. */
961 gcmkERR_BREAK(gckVIDMEM_Unlock(Kernel->kernel, Node, gcvSURF_TYPE_UNKNOWN, gcvNULL));
963 /* Free the linear buffer. */
964 gcmkERR_BREAK(gckVIDMEM_Free(Node));
966 while (gcvFALSE);
968 /* Return status. */
969 return status;
972 gceSTATUS
973 _AllocateCommandBuffer(
974 IN gckVGCOMMAND Command,
975 IN gctSIZE_T Size,
976 OUT gcsCMDBUFFER_PTR * CommandBuffer
979 gceSTATUS status, last;
980 gcuVIDMEM_NODE_PTR node = gcvNULL;
984 gctUINT alignedHeaderSize;
985 gctUINT requestedSize;
986 gctUINT allocationSize;
987 gctUINT32 address = 0;
988 gcsCMDBUFFER_PTR commandBuffer;
989 gctUINT8_PTR endCommand;
991 /* Determine the aligned header size. */
992 alignedHeaderSize
993 = gcmALIGN(gcmSIZEOF(gcsCMDBUFFER), Command->info.addressAlignment);
995 /* Align the requested size. */
996 requestedSize
997 = gcmALIGN(Size, Command->info.commandAlignment);
999 /* Determine the size of the buffer to allocate. */
1000 allocationSize
1001 = alignedHeaderSize
1002 + requestedSize
1003 + Command->info.staticTailSize;
1005 /* Allocate the command buffer. */
1006 gcmkERR_BREAK(_AllocateLinear(
1007 Command,
1008 allocationSize,
1009 Command->info.addressAlignment,
1010 &node,
1011 &address,
1012 (gctPOINTER *) &commandBuffer
1015 /* Initialize the structure. */
1016 commandBuffer->completion = gcvVACANT_BUFFER;
1017 commandBuffer->node = node;
1018 commandBuffer->address = address + alignedHeaderSize;
1019 commandBuffer->bufferOffset = alignedHeaderSize;
1020 commandBuffer->size = requestedSize;
1021 commandBuffer->offset = requestedSize;
1022 commandBuffer->nextAllocated = gcvNULL;
1023 commandBuffer->nextSubBuffer = gcvNULL;
1025 /* Determine the data count. */
1026 commandBuffer->dataCount
1027 = (requestedSize + Command->info.staticTailSize)
1028 / Command->info.commandAlignment;
1030 /* Determine the location of the END command. */
1031 endCommand
1032 = (gctUINT8_PTR) commandBuffer
1033 + alignedHeaderSize
1034 + requestedSize;
1036 /* Append an END command. */
1037 gcmkERR_BREAK(gckVGCOMMAND_EndCommand(
1038 Command,
1039 endCommand,
1040 Command->info.feBufferInt,
1041 gcvNULL
1044 /* Set the return pointer. */
1045 * CommandBuffer = commandBuffer;
1047 /* Success. */
1048 return gcvSTATUS_OK;
1050 while (gcvFALSE);
1052 /* Roll back. */
1053 if (node != gcvNULL)
1055 /* Free the command buffer. */
1056 gcmkCHECK_STATUS(_FreeLinear(Command->kernel, node));
1059 /* Return status. */
1060 return status;
1063 static gceSTATUS
1064 _FreeCommandBuffer(
1065 IN gckVGKERNEL Kernel,
1066 IN gcsCMDBUFFER_PTR CommandBuffer
1069 gceSTATUS status;
1071 /* Free the buffer. */
1072 status = _FreeLinear(Kernel, CommandBuffer->node);
1074 /* Return status. */
1075 return status;
1079 /******************************************************************************\
1080 ****************************** TS Overflow Handler *****************************
1081 \******************************************************************************/
1083 static gceSTATUS
1084 _EventHandler_TSOverflow(
1085 IN gckVGKERNEL Kernel
1088 gcmkTRACE(
1089 gcvLEVEL_ERROR,
1090 "%s(%d): **** TS OVERFLOW ENCOUNTERED ****\n",
1091 __FUNCTION__, __LINE__
1094 return gcvSTATUS_OK;
1098 /******************************************************************************\
1099 ****************************** Bus Error Handler *******************************
1100 \******************************************************************************/
1102 static gceSTATUS
1103 _EventHandler_BusError(
1104 IN gckVGKERNEL Kernel
1107 gcmkTRACE(
1108 gcvLEVEL_ERROR,
1109 "%s(%d): **** BUS ERROR ENCOUNTERED ****\n",
1110 __FUNCTION__, __LINE__
1113 return gcvSTATUS_OK;
1117 /******************************************************************************\
1118 ******************************** Task Routines *********************************
1119 \******************************************************************************/
1121 typedef gceSTATUS (* gctTASKROUTINE) (
1122 gckVGCOMMAND Command,
1123 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1126 static gceSTATUS
1127 _TaskLink(
1128 gckVGCOMMAND Command,
1129 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1132 static gceSTATUS
1133 _TaskCluster(
1134 gckVGCOMMAND Command,
1135 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1138 static gceSTATUS
1139 _TaskIncrement(
1140 gckVGCOMMAND Command,
1141 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1144 static gceSTATUS
1145 _TaskDecrement(
1146 gckVGCOMMAND Command,
1147 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1150 static gceSTATUS
1151 _TaskSignal(
1152 gckVGCOMMAND Command,
1153 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1156 static gceSTATUS
1157 _TaskLockdown(
1158 gckVGCOMMAND Command,
1159 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1162 static gceSTATUS
1163 _TaskUnlockVideoMemory(
1164 gckVGCOMMAND Command,
1165 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1168 static gceSTATUS
1169 _TaskFreeVideoMemory(
1170 gckVGCOMMAND Command,
1171 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1174 static gceSTATUS
1175 _TaskFreeContiguousMemory(
1176 gckVGCOMMAND Command,
1177 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1180 static gceSTATUS
1181 _TaskUnmapUserMemory(
1182 gckVGCOMMAND Command,
1183 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1186 static gceSTATUS
1187 _TaskUnmapMemory(
1188 gckVGCOMMAND Command,
1189 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1192 static gctTASKROUTINE _taskRoutine[] =
1194 _TaskLink, /* gcvTASK_LINK */
1195 _TaskCluster, /* gcvTASK_CLUSTER */
1196 _TaskIncrement, /* gcvTASK_INCREMENT */
1197 _TaskDecrement, /* gcvTASK_DECREMENT */
1198 _TaskSignal, /* gcvTASK_SIGNAL */
1199 _TaskLockdown, /* gcvTASK_LOCKDOWN */
1200 _TaskUnlockVideoMemory, /* gcvTASK_UNLOCK_VIDEO_MEMORY */
1201 _TaskFreeVideoMemory, /* gcvTASK_FREE_VIDEO_MEMORY */
1202 _TaskFreeContiguousMemory, /* gcvTASK_FREE_CONTIGUOUS_MEMORY */
1203 _TaskUnmapUserMemory, /* gcvTASK_UNMAP_USER_MEMORY */
1204 _TaskUnmapMemory, /* gcvTASK_UNMAP_MEMORY */
1207 static gceSTATUS
1208 _TaskLink(
1209 gckVGCOMMAND Command,
1210 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1213 /* Cast the task pointer. */
1214 gcsTASK_LINK_PTR task = (gcsTASK_LINK_PTR) TaskHeader->task;
1216 /* Save the pointer to the container. */
1217 gcsTASK_CONTAINER_PTR container = TaskHeader->container;
1219 /* No more tasks in the list? */
1220 if (task->task == gcvNULL)
1222 /* Reset the entry. */
1223 TaskHeader->container = gcvNULL;
1224 TaskHeader->task = gcvNULL;
1225 TaskHeader->link = gcvNULL;
1227 else
1229 /* Update the entry. */
1230 TaskHeader->container = task->cotainer;
1231 TaskHeader->task = task->task;
1234 /* Decrement the task buffer reference. */
1235 gcmkASSERT(container->referenceCount >= 0);
1236 if (container->referenceCount == 0)
1238 /* Free the container. */
1239 _FreeTaskContainer(Command, container);
1242 /* Success. */
1243 return gcvSTATUS_OK;
1246 static gceSTATUS
1247 _TaskCluster(
1248 gckVGCOMMAND Command,
1249 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1252 gceSTATUS status = gcvSTATUS_OK;
1254 /* Cast the task pointer. */
1255 gcsTASK_CLUSTER_PTR cluster = (gcsTASK_CLUSTER_PTR) TaskHeader->task;
1257 /* Get the number of tasks. */
1258 gctUINT taskCount = cluster->taskCount;
1260 /* Advance to the next task. */
1261 TaskHeader->task = (gcsTASK_HEADER_PTR) (cluster + 1);
1263 /* Perform all tasks in the cluster. */
1264 while (taskCount)
1266 /* Perform the current task. */
1267 gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id](
1268 Command,
1269 TaskHeader
1272 /* Update the task count. */
1273 taskCount -= 1;
1276 /* Return status. */
1277 return status;
1280 static gceSTATUS
1281 _TaskIncrement(
1282 gckVGCOMMAND Command,
1283 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1286 gceSTATUS status;
1290 /* Cast the task pointer. */
1291 gcsTASK_INCREMENT_PTR task = (gcsTASK_INCREMENT_PTR) TaskHeader->task;
1293 /* Convert physical into logical address. */
1294 gctUINT32_PTR logical;
1295 gcmkERR_BREAK(gckOS_MapPhysical(
1296 Command->os,
1297 task->address,
1298 gcmSIZEOF(gctUINT32),
1299 (gctPOINTER *) &logical
1302 /* Increment data. */
1303 (* logical) += 1;
1305 /* Unmap the physical memory. */
1306 gcmkERR_BREAK(gckOS_UnmapPhysical(
1307 Command->os,
1308 logical,
1309 gcmSIZEOF(gctUINT32)
1312 /* Update the reference counter. */
1313 TaskHeader->container->referenceCount -= 1;
1315 /* Update the task pointer. */
1316 TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
1318 while (gcvFALSE);
1320 /* Return status. */
1321 return status;
1324 static gceSTATUS
1325 _TaskDecrement(
1326 gckVGCOMMAND Command,
1327 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1330 gceSTATUS status;
1334 /* Cast the task pointer. */
1335 gcsTASK_DECREMENT_PTR task = (gcsTASK_DECREMENT_PTR) TaskHeader->task;
1337 /* Convert physical into logical address. */
1338 gctUINT32_PTR logical;
1339 gcmkERR_BREAK(gckOS_MapPhysical(
1340 Command->os,
1341 task->address,
1342 gcmSIZEOF(gctUINT32),
1343 (gctPOINTER *) &logical
1346 /* Decrement data. */
1347 (* logical) -= 1;
1349 /* Unmap the physical memory. */
1350 gcmkERR_BREAK(gckOS_UnmapPhysical(
1351 Command->os,
1352 logical,
1353 gcmSIZEOF(gctUINT32)
1356 /* Update the reference counter. */
1357 TaskHeader->container->referenceCount -= 1;
1359 /* Update the task pointer. */
1360 TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
1362 while (gcvFALSE);
1364 /* Return status. */
1365 return status;
1368 static gceSTATUS
1369 _TaskSignal(
1370 gckVGCOMMAND Command,
1371 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1374 gceSTATUS status;
1378 /* Cast the task pointer. */
1379 gcsTASK_SIGNAL_PTR task = (gcsTASK_SIGNAL_PTR) TaskHeader->task;
1381 /* Map the signal into kernel space. */
1382 gcmkERR_BREAK(gckOS_UserSignal(
1383 Command->os, task->signal, task->process
1385 /* Update the reference counter. */
1386 TaskHeader->container->referenceCount -= 1;
1388 /* Update the task pointer. */
1389 TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
1391 while (gcvFALSE);
1393 /* Return status. */
1394 return status;
1397 static gceSTATUS
1398 _TaskLockdown(
1399 gckVGCOMMAND Command,
1400 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1403 gceSTATUS status;
1404 gctUINT32_PTR userCounter = gcvNULL;
1405 gctUINT32_PTR kernelCounter = gcvNULL;
1406 gctSIGNAL signal = gcvNULL;
1410 /* Cast the task pointer. */
1411 gcsTASK_LOCKDOWN_PTR task = (gcsTASK_LOCKDOWN_PTR) TaskHeader->task;
1413 /* Convert physical addresses into logical. */
1414 gcmkERR_BREAK(gckOS_MapPhysical(
1415 Command->os,
1416 task->userCounter,
1417 gcmSIZEOF(gctUINT32),
1418 (gctPOINTER *) &userCounter
1421 gcmkERR_BREAK(gckOS_MapPhysical(
1422 Command->os,
1423 task->kernelCounter,
1424 gcmSIZEOF(gctUINT32),
1425 (gctPOINTER *) &kernelCounter
1428 /* Update the kernel counter. */
1429 (* kernelCounter) += 1;
1431 /* Are the counters equal? */
1432 if ((* userCounter) == (* kernelCounter))
1434 /* Map the signal into kernel space. */
1435 gcmkERR_BREAK(gckOS_MapSignal(
1436 Command->os, task->signal, task->process, &signal
1439 if (signal == gcvNULL)
1441 /* Signal. */
1442 gcmkERR_BREAK(gckOS_Signal(
1443 Command->os, task->signal, gcvTRUE
1446 else
1448 /* Signal. */
1449 gcmkERR_BREAK(gckOS_Signal(
1450 Command->os, signal, gcvTRUE
1455 /* Update the reference counter. */
1456 TaskHeader->container->referenceCount -= 1;
1458 /* Update the task pointer. */
1459 TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
1461 while (gcvFALSE);
1463 /* Destroy the mapped signal. */
1464 if (signal != gcvNULL)
1466 gcmkVERIFY_OK(gckOS_DestroySignal(
1467 Command->os, signal
1471 /* Unmap the physical memory. */
1472 if (kernelCounter != gcvNULL)
1474 gcmkVERIFY_OK(gckOS_UnmapPhysical(
1475 Command->os,
1476 kernelCounter,
1477 gcmSIZEOF(gctUINT32)
1481 if (userCounter != gcvNULL)
1483 gcmkVERIFY_OK(gckOS_UnmapPhysical(
1484 Command->os,
1485 userCounter,
1486 gcmSIZEOF(gctUINT32)
1490 /* Return status. */
1491 return status;
1494 static gceSTATUS
1495 _TaskUnlockVideoMemory(
1496 gckVGCOMMAND Command,
1497 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1500 gceSTATUS status;
1504 /* Cast the task pointer. */
1505 gcsTASK_UNLOCK_VIDEO_MEMORY_PTR task
1506 = (gcsTASK_UNLOCK_VIDEO_MEMORY_PTR) TaskHeader->task;
1508 /* Unlock video memory. */
1509 gcmkERR_BREAK(gckVIDMEM_Unlock(
1510 Command->kernel->kernel,
1511 task->node,
1512 gcvSURF_TYPE_UNKNOWN,
1513 gcvNULL));
1515 /* Update the reference counter. */
1516 TaskHeader->container->referenceCount -= 1;
1518 /* Update the task pointer. */
1519 TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
1521 while (gcvFALSE);
1523 /* Return status. */
1524 return status;
1527 static gceSTATUS
1528 _TaskFreeVideoMemory(
1529 gckVGCOMMAND Command,
1530 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1533 gceSTATUS status;
1537 /* Cast the task pointer. */
1538 gcsTASK_FREE_VIDEO_MEMORY_PTR task
1539 = (gcsTASK_FREE_VIDEO_MEMORY_PTR) TaskHeader->task;
1541 /* Free video memory. */
1542 gcmkERR_BREAK(gckVIDMEM_Free(task->node));
1544 /* Update the reference counter. */
1545 TaskHeader->container->referenceCount -= 1;
1547 /* Update the task pointer. */
1548 TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
1550 while (gcvFALSE);
1552 /* Return status. */
1553 return status;
1556 static gceSTATUS
1557 _TaskFreeContiguousMemory(
1558 gckVGCOMMAND Command,
1559 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1562 gceSTATUS status;
1566 /* Cast the task pointer. */
1567 gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR task
1568 = (gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR) TaskHeader->task;
1570 /* Free contiguous memory. */
1571 gcmkERR_BREAK(gckOS_FreeContiguous(
1572 Command->os, task->physical, task->logical, task->bytes
1575 /* Update the reference counter. */
1576 TaskHeader->container->referenceCount -= 1;
1578 /* Update the task pointer. */
1579 TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
1581 while (gcvFALSE);
1583 /* Return status. */
1584 return status;
1587 static gceSTATUS
1588 _TaskUnmapUserMemory(
1589 gckVGCOMMAND Command,
1590 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1593 gceSTATUS status;
1597 /* Cast the task pointer. */
1598 gcsTASK_UNMAP_USER_MEMORY_PTR task
1599 = (gcsTASK_UNMAP_USER_MEMORY_PTR) TaskHeader->task;
1601 /* Unmap the user memory. */
1602 gcmkERR_BREAK(gckOS_UnmapUserMemoryEx(
1603 Command->os, gcvCORE_VG, task->memory, task->size, task->info, task->address
1606 /* Update the reference counter. */
1607 TaskHeader->container->referenceCount -= 1;
1609 /* Update the task pointer. */
1610 TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
1612 while (gcvFALSE);
1614 /* Return status. */
1615 return status;
1618 static gceSTATUS
1619 _TaskUnmapMemory(
1620 gckVGCOMMAND Command,
1621 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1624 gceSTATUS status;
1628 /* Cast the task pointer. */
1629 gcsTASK_UNMAP_MEMORY_PTR task
1630 = (gcsTASK_UNMAP_MEMORY_PTR) TaskHeader->task;
1632 /* Unmap memory. */
1633 gcmkERR_BREAK(gckKERNEL_UnmapMemory(
1634 Command->kernel->kernel, task->physical, task->bytes, task->logical
1637 /* Update the reference counter. */
1638 TaskHeader->container->referenceCount -= 1;
1640 /* Update the task pointer. */
1641 TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
1643 while (gcvFALSE);
1645 /* Return status. */
1646 return status;
1650 /******************************************************************************\
1651 ************ Hardware Block Interrupt Handlers For Scheduled Events ************
1652 \******************************************************************************/
1654 static gceSTATUS
1655 _EventHandler_Block(
1656 IN gckVGKERNEL Kernel,
1657 IN gcsBLOCK_TASK_ENTRY_PTR TaskHeader,
1658 IN gctBOOL ProcessAll
1661 gceSTATUS status, last;
1663 gcmkHEADER_ARG("Kernel=0x%x TaskHeader=0x%x ProcessAll=0x%x", Kernel, TaskHeader, ProcessAll);
1664 /* Verify the arguments. */
1665 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1669 gckVGCOMMAND command;
1671 /* Get the command buffer object. */
1672 command = Kernel->command;
1674 /* Increment the interrupt usage semaphore. */
1675 gcmkERR_BREAK(gckOS_IncrementSemaphore(
1676 command->os, TaskHeader->interruptSemaphore
1679 /* Acquire the mutex. */
1680 gcmkERR_BREAK(gckOS_AcquireMutex(
1681 command->os,
1682 command->taskMutex,
1683 gcvINFINITE
1686 /* Verify inputs. */
1687 gcmkASSERT(TaskHeader != gcvNULL);
1688 gcmkASSERT(TaskHeader->container != gcvNULL);
1689 gcmkASSERT(TaskHeader->task != gcvNULL);
1690 gcmkASSERT(TaskHeader->link != gcvNULL);
1692 /* Process tasks. */
1695 /* Process the current task. */
1696 gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id](
1697 command,
1698 TaskHeader
1701 /* Is the next task is LINK? */
1702 if (TaskHeader->task->id == gcvTASK_LINK)
1704 gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id](
1705 command,
1706 TaskHeader
1709 /* Done. */
1710 break;
1713 while (ProcessAll);
1715 /* Release the mutex. */
1716 gcmkCHECK_STATUS(gckOS_ReleaseMutex(
1717 command->os,
1718 command->taskMutex
1721 while (gcvFALSE);
1723 gcmkFOOTER();
1724 /* Return status. */
1725 return status;
1728 gcmDECLARE_INTERRUPT_HANDLER(COMMAND, 0)
1730 gceSTATUS status, last;
1732 gcmkHEADER_ARG("Kernel=0x%x ", Kernel);
1734 /* Verify the arguments. */
1735 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1739 gckVGCOMMAND command;
1740 gcsKERNEL_QUEUE_HEADER_PTR mergeQueue;
1741 gcsKERNEL_QUEUE_HEADER_PTR queueTail;
1742 gcsKERNEL_CMDQUEUE_PTR entry;
1743 gctUINT entryCount;
1745 /* Get the command buffer object. */
1746 command = Kernel->command;
1748 /* Acquire the mutex. */
1749 gcmkERR_BREAK(gckOS_AcquireMutex(
1750 command->os,
1751 command->queueMutex,
1752 gcvINFINITE
1755 /* Get the current queue. */
1756 queueTail = command->queueTail;
1758 /* Get the current queue entry. */
1759 entry = queueTail->currentEntry;
1761 /* Get the number of entries in the queue. */
1762 entryCount = queueTail->pending;
1764 /* Process all entries. */
1765 while (gcvTRUE)
1767 /* Call post-execution function. */
1768 status = entry->handler(Kernel, entry);
1770 /* Failed? */
1771 if (gcmkIS_ERROR(status))
1773 gcmkTRACE_ZONE(
1774 gcvLEVEL_ERROR,
1775 gcvZONE_COMMAND,
1776 "[%s] line %d: post action failed.\n",
1777 __FUNCTION__, __LINE__
1781 /* Executed the next buffer? */
1782 if (status == gcvSTATUS_EXECUTED)
1784 /* Update the queue. */
1785 queueTail->pending = entryCount;
1786 queueTail->currentEntry = entry;
1788 /* Success. */
1789 status = gcvSTATUS_OK;
1791 /* Break out of the loop. */
1792 break;
1795 /* Advance to the next entry. */
1796 entry += 1;
1797 entryCount -= 1;
1799 /* Last entry? */
1800 if (entryCount == 0)
1802 /* Reset the queue to idle. */
1803 queueTail->pending = 0;
1805 /* Get a shortcut to the queue to merge with. */
1806 mergeQueue = command->mergeQueue;
1808 /* Merge the queues if necessary. */
1809 if (mergeQueue != queueTail)
1811 gcmkASSERT(mergeQueue < queueTail);
1812 gcmkASSERT(mergeQueue->next == queueTail);
1814 mergeQueue->size
1815 += gcmSIZEOF(gcsKERNEL_QUEUE_HEADER)
1816 + queueTail->size;
1818 mergeQueue->next = queueTail->next;
1821 /* Advance to the next queue. */
1822 queueTail = queueTail->next;
1824 /* Did it wrap around? */
1825 if (command->queue == queueTail)
1827 /* Reset merge queue. */
1828 command->mergeQueue = queueTail;
1831 /* Set new queue. */
1832 command->queueTail = queueTail;
1834 /* Is the next queue scheduled? */
1835 if (queueTail->pending > 0)
1837 gcsCMDBUFFER_PTR commandBuffer;
1839 /* The first entry must be a command buffer. */
1840 commandBuffer = queueTail->currentEntry->commandBuffer;
1842 /* Start the command processor. */
1843 status = gckVGHARDWARE_Execute(
1844 command->hardware,
1845 commandBuffer->address,
1846 commandBuffer->dataCount
1849 /* Failed? */
1850 if (gcmkIS_ERROR(status))
1852 gcmkTRACE_ZONE(
1853 gcvLEVEL_ERROR,
1854 gcvZONE_COMMAND,
1855 "[%s] line %d: failed to start the next queue.\n",
1856 __FUNCTION__, __LINE__
1861 /* Break out of the loop. */
1862 break;
1866 /* Release the mutex. */
1867 gcmkCHECK_STATUS(gckOS_ReleaseMutex(
1868 command->os,
1869 command->queueMutex
1872 while (gcvFALSE);
1874 gcmkFOOTER();
1875 /* Return status. */
1876 return status;
1879 /* Define standard block interrupt handlers. */
1880 gcmDEFINE_INTERRUPT_HANDLER(TESSELLATOR, 0)
1881 gcmDEFINE_INTERRUPT_HANDLER(VG, 0)
1882 gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 0)
1883 gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 1)
1884 gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 2)
1885 gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 3)
1886 gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 4)
1887 gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 5)
1888 gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 6)
1889 gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 7)
1890 gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 8)
1891 gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 9)
1893 /* The entries in the array are arranged by event priority. */
1894 static gcsBLOCK_INTERRUPT_HANDLER _blockHandlers[] =
1896 gcmDEFINE_INTERRUPT_HANDLER_ENTRY(TESSELLATOR, 0),
1897 gcmDEFINE_INTERRUPT_HANDLER_ENTRY(VG, 0),
1898 gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 0),
1899 gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 1),
1900 gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 2),
1901 gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 3),
1902 gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 4),
1903 gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 5),
1904 gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 6),
1905 gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 7),
1906 gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 8),
1907 gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 9),
1908 gcmDEFINE_INTERRUPT_HANDLER_ENTRY(COMMAND, 0),
1912 /******************************************************************************\
1913 ************************* Static Command Buffer Handlers ***********************
1914 \******************************************************************************/
1916 static gceSTATUS
1917 _UpdateStaticCommandBuffer(
1918 IN gckVGKERNEL Kernel,
1919 IN gcsKERNEL_CMDQUEUE_PTR Entry
1922 gcmkTRACE_ZONE(
1923 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
1924 "%s(%d)\n",
1925 __FUNCTION__, __LINE__
1928 /* Success. */
1929 return gcvSTATUS_OK;
1932 static gceSTATUS
1933 _ExecuteStaticCommandBuffer(
1934 IN gckVGKERNEL Kernel,
1935 IN gcsKERNEL_CMDQUEUE_PTR Entry
1938 gceSTATUS status;
1942 gcsCMDBUFFER_PTR commandBuffer;
1944 /* Cast the command buffer header. */
1945 commandBuffer = Entry->commandBuffer;
1947 /* Set to update the command buffer next time. */
1948 Entry->handler = _UpdateStaticCommandBuffer;
1950 gcmkTRACE_ZONE(
1951 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
1952 "%s(%d): executing next buffer @ 0x%08X, data count = %d\n",
1953 __FUNCTION__, __LINE__,
1954 commandBuffer->address,
1955 commandBuffer->dataCount
1958 /* Start the command processor. */
1959 gcmkERR_BREAK(gckVGHARDWARE_Execute(
1960 Kernel->hardware,
1961 commandBuffer->address,
1962 commandBuffer->dataCount
1965 /* Success. */
1966 return gcvSTATUS_EXECUTED;
1968 while (gcvFALSE);
1970 /* Return status. */
1971 return status;
1974 static gceSTATUS
1975 _UpdateLastStaticCommandBuffer(
1976 IN gckVGKERNEL Kernel,
1977 IN gcsKERNEL_CMDQUEUE_PTR Entry
1980 #if gcvDEBUG || gcdFORCE_MESSAGES
1981 /* Get the command buffer header. */
1982 gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
1984 /* Validate the command buffer. */
1985 gcmkASSERT(commandBuffer->completion != gcvNULL);
1986 gcmkASSERT(commandBuffer->completion != gcvVACANT_BUFFER);
1988 #endif
1990 gcmkTRACE_ZONE(
1991 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
1992 "%s(%d): processing all tasks scheduled for FE.\n",
1993 __FUNCTION__, __LINE__
1996 /* Perform scheduled tasks. */
1997 return _EventHandler_Block(
1998 Kernel,
1999 &Kernel->command->taskTable[gcvBLOCK_COMMAND],
2000 gcvTRUE
2004 static gceSTATUS
2005 _ExecuteLastStaticCommandBuffer(
2006 IN gckVGKERNEL Kernel,
2007 IN gcsKERNEL_CMDQUEUE_PTR Entry
2010 gceSTATUS status;
2014 /* Cast the command buffer header. */
2015 gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
2017 /* Set to update the command buffer next time. */
2018 Entry->handler = _UpdateLastStaticCommandBuffer;
2020 gcmkTRACE_ZONE(
2021 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
2022 "%s(%d): executing next buffer @ 0x%08X, data count = %d\n",
2023 __FUNCTION__, __LINE__,
2024 commandBuffer->address,
2025 commandBuffer->dataCount
2028 /* Start the command processor. */
2029 gcmkERR_BREAK(gckVGHARDWARE_Execute(
2030 Kernel->hardware,
2031 commandBuffer->address,
2032 commandBuffer->dataCount
2035 /* Success. */
2036 return gcvSTATUS_EXECUTED;
2038 while (gcvFALSE);
2040 /* Return status. */
2041 return status;
2045 /******************************************************************************\
2046 ************************* Dynamic Command Buffer Handlers **********************
2047 \******************************************************************************/
2049 static gceSTATUS
2050 _UpdateDynamicCommandBuffer(
2051 IN gckVGKERNEL Kernel,
2052 IN gcsKERNEL_CMDQUEUE_PTR Entry
2055 gcmkTRACE_ZONE(
2056 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
2057 "%s(%d)\n",
2058 __FUNCTION__, __LINE__
2061 /* Success. */
2062 return gcvSTATUS_OK;
2065 static gceSTATUS
2066 _ExecuteDynamicCommandBuffer(
2067 IN gckVGKERNEL Kernel,
2068 IN gcsKERNEL_CMDQUEUE_PTR Entry
2071 gceSTATUS status;
2075 /* Cast the command buffer header. */
2076 gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
2078 /* Set to update the command buffer next time. */
2079 Entry->handler = _UpdateDynamicCommandBuffer;
2081 gcmkTRACE_ZONE(
2082 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
2083 "%s(%d): executing next buffer @ 0x%08X, data count = %d\n",
2084 __FUNCTION__, __LINE__,
2085 commandBuffer->address,
2086 commandBuffer->dataCount
2089 /* Start the command processor. */
2090 gcmkERR_BREAK(gckVGHARDWARE_Execute(
2091 Kernel->hardware,
2092 commandBuffer->address,
2093 commandBuffer->dataCount
2096 /* Success. */
2097 return gcvSTATUS_EXECUTED;
2099 while (gcvFALSE);
2101 /* Return status. */
2102 return status;
2105 static gceSTATUS
2106 _UpdateLastDynamicCommandBuffer(
2107 IN gckVGKERNEL Kernel,
2108 IN gcsKERNEL_CMDQUEUE_PTR Entry
2111 #if gcvDEBUG || gcdFORCE_MESSAGES
2112 /* Get the command buffer header. */
2113 gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
2115 /* Validate the command buffer. */
2116 gcmkASSERT(commandBuffer->completion != gcvNULL);
2117 gcmkASSERT(commandBuffer->completion != gcvVACANT_BUFFER);
2119 #endif
2121 gcmkTRACE_ZONE(
2122 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
2123 "%s(%d): processing all tasks scheduled for FE.\n",
2124 __FUNCTION__, __LINE__
2127 /* Perform scheduled tasks. */
2128 return _EventHandler_Block(
2129 Kernel,
2130 &Kernel->command->taskTable[gcvBLOCK_COMMAND],
2131 gcvTRUE
2135 static gceSTATUS
2136 _ExecuteLastDynamicCommandBuffer(
2137 IN gckVGKERNEL Kernel,
2138 IN gcsKERNEL_CMDQUEUE_PTR Entry
2141 gceSTATUS status;
2145 /* Cast the command buffer header. */
2146 gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
2148 /* Set to update the command buffer next time. */
2149 Entry->handler = _UpdateLastDynamicCommandBuffer;
2151 gcmkTRACE_ZONE(
2152 gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
2153 "%s(%d): executing next buffer @ 0x%08X, data count = %d\n",
2154 __FUNCTION__, __LINE__,
2155 commandBuffer->address,
2156 commandBuffer->dataCount
2159 /* Start the command processor. */
2160 gcmkERR_BREAK(gckVGHARDWARE_Execute(
2161 Kernel->hardware,
2162 commandBuffer->address,
2163 commandBuffer->dataCount
2166 /* Success. */
2167 return gcvSTATUS_EXECUTED;
2169 while (gcvFALSE);
2171 /* Return status. */
2172 return status;
2176 /******************************************************************************\
2177 ********************************* Other Handlers *******************************
2178 \******************************************************************************/
2180 static gceSTATUS
2181 _FreeKernelCommandBuffer(
2182 IN gckVGKERNEL Kernel,
2183 IN gcsKERNEL_CMDQUEUE_PTR Entry
2186 gceSTATUS status;
2188 /* Free the command buffer. */
2189 status = _FreeCommandBuffer(Kernel, Entry->commandBuffer);
2191 /* Return status. */
2192 return status;
2196 /******************************************************************************\
2197 ******************************* Queue Management *******************************
2198 \******************************************************************************/
2200 #if gcvDUMP_COMMAND_BUFFER
2201 static void
2202 _DumpCommandQueue(
2203 IN gckVGCOMMAND Command,
2204 IN gcsKERNEL_QUEUE_HEADER_PTR QueueHeader,
2205 IN gctUINT EntryCount
2208 gcsKERNEL_CMDQUEUE_PTR entry;
2209 gctUINT queueIndex;
2211 #if defined(gcvCOMMAND_BUFFER_NAME)
2212 static gctUINT arrayCount = 0;
2213 #endif
2215 /* Is dumpinng enabled? */
2216 if (!Commad->enableDumping)
2218 return;
2221 #if !defined(gcvCOMMAND_BUFFER_NAME)
2222 gcmkTRACE_ZONE(
2223 gcvLEVEL_INFO, gcvZONE_COMMAND,
2224 "COMMAND QUEUE DUMP: %d entries\n", EntryCount
2226 #endif
2228 /* Get the pointer to the first entry. */
2229 entry = QueueHeader->currentEntry;
2231 /* Iterate through the queue. */
2232 for (queueIndex = 0; queueIndex < EntryCount; queueIndex += 1)
2234 gcsCMDBUFFER_PTR buffer;
2235 gctUINT bufferCount;
2236 gctUINT bufferIndex;
2237 gctUINT i, count;
2238 gctUINT size;
2239 gctUINT32_PTR data;
2241 #if gcvDUMP_COMMAND_LINES
2242 gctUINT lineNumber;
2243 #endif
2245 #if !defined(gcvCOMMAND_BUFFER_NAME)
2246 gcmkTRACE_ZONE(
2247 gcvLEVEL_INFO, gcvZONE_COMMAND,
2248 "ENTRY %d\n", queueIndex
2250 #endif
2252 /* Reset the count. */
2253 bufferCount = 0;
2255 /* Set the initial buffer. */
2256 buffer = entry->commandBuffer;
2258 /* Loop through all subbuffers. */
2259 while (buffer)
2261 /* Update the count. */
2262 bufferCount += 1;
2264 /* Advance to the next subbuffer. */
2265 buffer = buffer->nextSubBuffer;
2268 #if !defined(gcvCOMMAND_BUFFER_NAME)
2269 if (bufferCount > 1)
2271 gcmkTRACE_ZONE(
2272 gcvLEVEL_INFO,
2273 gcvZONE_COMMAND,
2274 " COMMAND BUFFER SET: %d buffers.\n",
2275 bufferCount
2278 #endif
2280 /* Reset the buffer index. */
2281 bufferIndex = 0;
2283 /* Set the initial buffer. */
2284 buffer = entry->commandBuffer;
2286 /* Loop through all subbuffers. */
2287 while (buffer)
2289 /* Determine the size of the buffer. */
2290 size = buffer->dataCount * Command->info.commandAlignment;
2292 #if !defined(gcvCOMMAND_BUFFER_NAME)
2293 /* A single buffer? */
2294 if (bufferCount == 1)
2296 gcmkTRACE_ZONE(
2297 gcvLEVEL_INFO,
2298 gcvZONE_COMMAND,
2299 " COMMAND BUFFER: count=%d (0x%X), size=%d bytes @ %08X.\n",
2300 buffer->dataCount,
2301 buffer->dataCount,
2302 size,
2303 buffer->address
2306 else
2308 gcmkTRACE_ZONE(
2309 gcvLEVEL_INFO,
2310 gcvZONE_COMMAND,
2311 " COMMAND BUFFER %d: count=%d (0x%X), size=%d bytes @ %08X\n",
2312 bufferIndex,
2313 buffer->dataCount,
2314 buffer->dataCount,
2315 size,
2316 buffer->address
2319 #endif
2321 /* Determine the number of double words to print. */
2322 count = size / 4;
2324 /* Determine the buffer location. */
2325 data = (gctUINT32_PTR)
2327 (gctUINT8_PTR) buffer + buffer->bufferOffset
2330 #if defined(gcvCOMMAND_BUFFER_NAME)
2331 gcmkTRACE_ZONE(
2332 gcvLEVEL_INFO,
2333 gcvZONE_COMMAND,
2334 "unsigned int _" gcvCOMMAND_BUFFER_NAME "_%d[] =\n",
2335 arrayCount
2338 gcmkTRACE_ZONE(
2339 gcvLEVEL_INFO,
2340 gcvZONE_COMMAND,
2341 "{\n"
2344 arrayCount += 1;
2345 #endif
2347 #if gcvDUMP_COMMAND_LINES
2348 /* Reset the line number. */
2349 lineNumber = 0;
2350 #endif
2352 #if defined(gcvCOMMAND_BUFFER_NAME)
2353 count -= 2;
2354 #endif
2356 for (i = 0; i < count; i += 1)
2358 if ((i % 8) == 0)
2360 #if defined(gcvCOMMAND_BUFFER_NAME)
2361 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "\t");
2362 #else
2363 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, " ");
2364 #endif
2367 #if gcvDUMP_COMMAND_LINES
2368 if (lineNumber == gcvDUMP_COMMAND_LINES)
2370 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, " . . . . . . . . .\n");
2371 break;
2373 #endif
2374 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "0x%08X", data[i]);
2376 if (i + 1 == count)
2378 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "\n");
2380 #if gcvDUMP_COMMAND_LINES
2381 lineNumber += 1;
2382 #endif
2384 else
2386 if (((i + 1) % 8) == 0)
2388 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, ",\n");
2390 #if gcvDUMP_COMMAND_LINES
2391 lineNumber += 1;
2392 #endif
2394 else
2396 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, ", ");
2401 #if defined(gcvCOMMAND_BUFFER_NAME)
2402 gcmkTRACE_ZONE(
2403 gcvLEVEL_INFO,
2404 gcvZONE_COMMAND,
2405 "};\n\n"
2407 #endif
2409 /* Advance to the next subbuffer. */
2410 buffer = buffer->nextSubBuffer;
2411 bufferIndex += 1;
2414 /* Advance to the next entry. */
2415 entry += 1;
2418 #endif
2420 static gceSTATUS
2421 _LockCurrentQueue(
2422 IN gckVGCOMMAND Command,
2423 OUT gcsKERNEL_CMDQUEUE_PTR * Entries,
2424 OUT gctUINT_PTR EntryCount
2427 gceSTATUS status;
2431 gcsKERNEL_QUEUE_HEADER_PTR queueHead;
2433 /* Get a shortcut to the head of the queue. */
2434 queueHead = Command->queueHead;
2436 /* Is the head buffer still being worked on? */
2437 if (queueHead->pending)
2439 /* Increment overflow count. */
2440 Command->queueOverflow += 1;
2442 /* Wait until the head becomes idle. */
2443 gcmkERR_BREAK(_WaitForIdle(Command, queueHead));
2446 /* Acquire the mutex. */
2447 gcmkERR_BREAK(gckOS_AcquireMutex(
2448 Command->os,
2449 Command->queueMutex,
2450 gcvINFINITE
2453 /* Determine the first queue entry. */
2454 queueHead->currentEntry = (gcsKERNEL_CMDQUEUE_PTR)
2456 (gctUINT8_PTR) queueHead + gcmSIZEOF(gcsKERNEL_QUEUE_HEADER)
2459 /* Set the pointer to the first entry. */
2460 * Entries = queueHead->currentEntry;
2462 /* Determine the number of available entries. */
2463 * EntryCount = queueHead->size / gcmSIZEOF(gcsKERNEL_CMDQUEUE);
2465 /* Success. */
2466 return gcvSTATUS_OK;
2468 while (gcvFALSE);
2470 /* Return status. */
2471 return status;
2474 static gceSTATUS
2475 _UnlockCurrentQueue(
2476 IN gckVGCOMMAND Command,
2477 IN gctUINT EntryCount
2480 gceSTATUS status;
2484 #if !gcdENABLE_INFINITE_SPEED_HW
2485 gcsKERNEL_QUEUE_HEADER_PTR queueTail;
2486 gcsKERNEL_QUEUE_HEADER_PTR queueHead;
2487 gcsKERNEL_QUEUE_HEADER_PTR queueNext;
2488 gctUINT queueSize;
2489 gctUINT newSize;
2490 gctUINT unusedSize;
2492 /* Get shortcut to the head and to the tail of the queue. */
2493 queueTail = Command->queueTail;
2494 queueHead = Command->queueHead;
2496 /* Dump the command buffer. */
2497 #if gcvDUMP_COMMAND_BUFFER
2498 _DumpCommandQueue(Command, queueHead, EntryCount);
2499 #endif
2501 /* Get a shortcut to the current queue size. */
2502 queueSize = queueHead->size;
2504 /* Determine the new queue size. */
2505 newSize = EntryCount * gcmSIZEOF(gcsKERNEL_CMDQUEUE);
2506 gcmkASSERT(newSize <= queueSize);
2508 /* Determine the size of the unused area. */
2509 unusedSize = queueSize - newSize;
2511 /* Is the unused area big enough to become a buffer? */
2512 if (unusedSize >= gcvMINUMUM_BUFFER)
2514 gcsKERNEL_QUEUE_HEADER_PTR nextHead;
2516 /* Place the new header. */
2517 nextHead = (gcsKERNEL_QUEUE_HEADER_PTR)
2519 (gctUINT8_PTR) queueHead
2520 + gcmSIZEOF(gcsKERNEL_QUEUE_HEADER)
2521 + newSize
2524 /* Initialize the buffer. */
2525 nextHead->size = unusedSize - gcmSIZEOF(gcsKERNEL_QUEUE_HEADER);
2526 nextHead->pending = 0;
2528 /* Link the buffer in. */
2529 nextHead->next = queueHead->next;
2530 queueHead->next = nextHead;
2531 queueNext = nextHead;
2533 /* Update the size of the current buffer. */
2534 queueHead->size = newSize;
2537 /* Not big enough. */
2538 else
2540 /* Determine the next queue. */
2541 queueNext = queueHead->next;
2544 /* Mark the buffer as busy. */
2545 queueHead->pending = EntryCount;
2547 /* Advance to the next buffer. */
2548 Command->queueHead = queueNext;
2550 /* Start the command processor if the queue was empty. */
2551 if (queueTail == queueHead)
2553 gcsCMDBUFFER_PTR commandBuffer;
2555 /* The first entry must be a command buffer. */
2556 commandBuffer = queueTail->currentEntry->commandBuffer;
2558 /* Start the command processor. */
2559 gcmkERR_BREAK(gckVGHARDWARE_Execute(
2560 Command->hardware,
2561 commandBuffer->address,
2562 commandBuffer->dataCount
2566 /* The queue was not empty. */
2567 else
2569 /* Advance the merge buffer if needed. */
2570 if (queueHead == Command->mergeQueue)
2572 Command->mergeQueue = queueNext;
2575 #endif
2577 /* Release the mutex. */
2578 gcmkERR_BREAK(gckOS_ReleaseMutex(
2579 Command->os,
2580 Command->queueMutex
2583 /* Success. */
2584 return gcvSTATUS_OK;
2586 while (gcvFALSE);
2588 /* Return status. */
2589 return status;
2593 /******************************************************************************\
2594 ****************************** gckVGCOMMAND API Code *****************************
2595 \******************************************************************************/
2597 gceSTATUS
2598 gckVGCOMMAND_Construct(
2599 IN gckVGKERNEL Kernel,
2600 IN gctUINT TaskGranularity,
2601 IN gctUINT QueueSize,
2602 OUT gckVGCOMMAND * Command
2605 gceSTATUS status, last;
2606 gckVGCOMMAND command = gcvNULL;
2607 gcsKERNEL_QUEUE_HEADER_PTR queue;
2608 gctUINT i, j;
2610 gcmkHEADER_ARG("Kernel=0x%x TaskGranularity=0x%x QueueSize=0x%x Command=0x%x",
2611 Kernel, TaskGranularity, QueueSize, Command);
2612 /* Verify the arguments. */
2613 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
2614 gcmkVERIFY_ARGUMENT(QueueSize >= gcvMINUMUM_BUFFER);
2615 gcmkVERIFY_ARGUMENT(Command != gcvNULL);
2619 /***********************************************************************
2620 ** Generic object initialization.
2623 /* Allocate the gckVGCOMMAND structure. */
2624 gcmkERR_BREAK(gckOS_Allocate(
2625 Kernel->os,
2626 gcmSIZEOF(struct _gckVGCOMMAND),
2627 (gctPOINTER *) &command
2630 /* Initialize the object. */
2631 command->object.type = gcvOBJ_COMMAND;
2633 /* Set the object pointers. */
2634 command->kernel = Kernel;
2635 command->os = Kernel->os;
2636 command->hardware = Kernel->hardware;
2638 /* Reset pointers. */
2639 command->queue = gcvNULL;
2640 command->queueMutex = gcvNULL;
2641 command->taskMutex = gcvNULL;
2642 command->commitMutex = gcvNULL;
2644 /* Reset context states. */
2645 command->contextCounter = 0;
2646 command->currentContext = 0;
2648 /* Enable command buffer dumping. */
2649 command->enableDumping = gcvTRUE;
2651 /* Set features. */
2652 command->fe20 = Kernel->hardware->fe20;
2653 command->vg20 = Kernel->hardware->vg20;
2654 command->vg21 = Kernel->hardware->vg21;
2656 /* Reset task table .*/
2657 gcmkVERIFY_OK(gckOS_ZeroMemory(
2658 command->taskTable, gcmSIZEOF(command->taskTable)
2661 /* Query command buffer attributes. */
2662 gcmkERR_BREAK(gckVGCOMMAND_InitializeInfo(command));
2664 /* Create the control mutexes. */
2665 gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->queueMutex));
2666 gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->taskMutex));
2667 gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->commitMutex));
2670 /***********************************************************************
2671 ** Command queue initialization.
2674 /* Allocate the command queue. */
2675 gcmkERR_BREAK(gckOS_Allocate(
2676 Kernel->os,
2677 QueueSize,
2678 (gctPOINTER *) &command->queue
2681 /* Initialize the command queue. */
2682 queue = command->queue;
2684 queue->size = QueueSize - gcmSIZEOF(gcsKERNEL_QUEUE_HEADER);
2685 queue->pending = 0;
2686 queue->next = queue;
2688 command->queueHead =
2689 command->queueTail =
2690 command->mergeQueue = command->queue;
2692 command->queueOverflow = 0;
2695 /***********************************************************************
2696 ** Enable TS overflow interrupt.
2699 gcmkERR_BREAK(gckVGINTERRUPT_Enable(
2700 Kernel->interrupt,
2701 &command->info.tsOverflowInt,
2702 _EventHandler_TSOverflow
2705 /* Mask out the interrupt. */
2706 Kernel->hardware->eventMask &= ~(1 << command->info.tsOverflowInt);
2709 /***********************************************************************
2710 ** Enable Bus Error interrupt.
2713 /* Hardwired to bit 31. */
2714 command->busErrorInt = 31;
2716 /* Enable the interrupt. */
2717 gcmkERR_BREAK(gckVGINTERRUPT_Enable(
2718 Kernel->interrupt,
2719 &command->busErrorInt,
2720 _EventHandler_BusError
2724 /***********************************************************************
2725 ** Task management initialization.
2728 command->taskStorage = gcvNULL;
2729 command->taskStorageGranularity = TaskGranularity;
2730 command->taskStorageUsable = TaskGranularity - gcmSIZEOF(gcsTASK_STORAGE);
2732 command->taskFreeHead = gcvNULL;
2733 command->taskFreeTail = gcvNULL;
2735 /* Enable block handlers. */
2736 for (i = 0; i < gcmCOUNTOF(_blockHandlers); i += 1)
2738 /* Get the target hardware block. */
2739 gceBLOCK block = _blockHandlers[i].block;
2741 /* Get the interrupt array entry. */
2742 gcsBLOCK_TASK_ENTRY_PTR entry = &command->taskTable[block];
2744 /* Determine the interrupt value index. */
2745 gctUINT index = entry->interruptCount;
2747 /* Create the block semaphore. */
2748 if (entry->interruptSemaphore == gcvNULL)
2750 gcmkERR_BREAK(gckOS_CreateSemaphoreVG(
2751 command->os, &entry->interruptSemaphore
2755 /* Enable auto-detection. */
2756 entry->interruptArray[index] = -1;
2758 /* Enable interrupt for the block. */
2759 gcmkERR_BREAK(gckVGINTERRUPT_Enable(
2760 Kernel->interrupt,
2761 &entry->interruptArray[index],
2762 _blockHandlers[i].handler
2765 /* Update the number of registered interrupts. */
2766 entry->interruptCount += 1;
2768 /* Inrement the semaphore to allow the usage of the registered
2769 interrupt. */
2770 gcmkERR_BREAK(gckOS_IncrementSemaphore(
2771 command->os, entry->interruptSemaphore
2776 /* Error? */
2777 if (gcmkIS_ERROR(status))
2779 break;
2782 /* Get the FE interrupt. */
2783 command->info.feBufferInt
2784 = command->taskTable[gcvBLOCK_COMMAND].interruptArray[0];
2786 /* Return gckVGCOMMAND object pointer. */
2787 *Command = command;
2789 /* Success. */
2790 return gcvSTATUS_OK;
2792 while (gcvFALSE);
2794 /* Roll back. */
2795 if (command != gcvNULL)
2797 /* Disable block handlers. */
2798 for (i = 0; i < gcvBLOCK_COUNT; i += 1)
2800 /* Get the task table entry. */
2801 gcsBLOCK_TASK_ENTRY_PTR entry = &command->taskTable[i];
2803 /* Destroy the semaphore. */
2804 if (entry->interruptSemaphore != gcvNULL)
2806 gcmkCHECK_STATUS(gckOS_DestroySemaphore(
2807 command->os, entry->interruptSemaphore
2811 /* Disable all enabled interrupts. */
2812 for (j = 0; j < entry->interruptCount; j += 1)
2814 /* Must be a valid value. */
2815 gcmkASSERT(entry->interruptArray[j] >= 0);
2816 gcmkASSERT(entry->interruptArray[j] <= 31);
2818 /* Disable the interrupt. */
2819 gcmkCHECK_STATUS(gckVGINTERRUPT_Disable(
2820 Kernel->interrupt,
2821 entry->interruptArray[j]
2826 /* Disable the bus error interrupt. */
2827 gcmkCHECK_STATUS(gckVGINTERRUPT_Disable(
2828 Kernel->interrupt,
2829 command->busErrorInt
2832 /* Disable TS overflow interrupt. */
2833 if (command->info.tsOverflowInt != -1)
2835 gcmkCHECK_STATUS(gckVGINTERRUPT_Disable(
2836 Kernel->interrupt,
2837 command->info.tsOverflowInt
2841 /* Delete the commit mutex. */
2842 if (command->commitMutex != gcvNULL)
2844 gcmkCHECK_STATUS(gckOS_DeleteMutex(
2845 Kernel->os, command->commitMutex
2849 /* Delete the command queue mutex. */
2850 if (command->taskMutex != gcvNULL)
2852 gcmkCHECK_STATUS(gckOS_DeleteMutex(
2853 Kernel->os, command->taskMutex
2857 /* Delete the command queue mutex. */
2858 if (command->queueMutex != gcvNULL)
2860 gcmkCHECK_STATUS(gckOS_DeleteMutex(
2861 Kernel->os, command->queueMutex
2865 /* Delete the command queue. */
2866 if (command->queue != gcvNULL)
2868 gcmkCHECK_STATUS(gckOS_Free(
2869 Kernel->os, command->queue
2873 /* Free the gckVGCOMMAND structure. */
2874 gcmkCHECK_STATUS(gckOS_Free(
2875 Kernel->os, command
2879 gcmkFOOTER();
2880 /* Return the error. */
2881 return status;
2884 gceSTATUS
2885 gckVGCOMMAND_Destroy(
2886 OUT gckVGCOMMAND Command
2889 gceSTATUS status = gcvSTATUS_OK;
2891 gcmkHEADER_ARG("Command=0x%x", Command);
2893 /* Verify the arguments. */
2894 gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
2898 gctUINT i;
2899 gcsTASK_STORAGE_PTR nextStorage;
2901 if (Command->queueHead != gcvNULL)
2903 /* Wait until the head becomes idle. */
2904 gcmkERR_BREAK(_WaitForIdle(Command, Command->queueHead));
2907 /* Disable block handlers. */
2908 for (i = 0; i < gcvBLOCK_COUNT; i += 1)
2910 /* Get the interrupt array entry. */
2911 gcsBLOCK_TASK_ENTRY_PTR entry = &Command->taskTable[i];
2913 /* Determine the index of the last interrupt in the array. */
2914 gctINT index = entry->interruptCount - 1;
2916 /* Destroy the semaphore. */
2917 if (entry->interruptSemaphore != gcvNULL)
2919 gcmkERR_BREAK(gckOS_DestroySemaphore(
2920 Command->os, entry->interruptSemaphore
2924 /* Disable all enabled interrupts. */
2925 while (index >= 0)
2927 /* Must be a valid value. */
2928 gcmkASSERT(entry->interruptArray[index] >= 0);
2929 gcmkASSERT(entry->interruptArray[index] <= 31);
2931 /* Disable the interrupt. */
2932 gcmkERR_BREAK(gckVGINTERRUPT_Disable(
2933 Command->kernel->interrupt,
2934 entry->interruptArray[index]
2937 /* Update to the next interrupt. */
2938 index -= 1;
2939 entry->interruptCount -= 1;
2942 /* Error? */
2943 if (gcmkIS_ERROR(status))
2945 break;
2949 /* Error? */
2950 if (gcmkIS_ERROR(status))
2952 break;
2955 /* Disable the bus error interrupt. */
2956 gcmkERR_BREAK(gckVGINTERRUPT_Disable(
2957 Command->kernel->interrupt,
2958 Command->busErrorInt
2961 /* Disable TS overflow interrupt. */
2962 if (Command->info.tsOverflowInt != -1)
2964 gcmkERR_BREAK(gckVGINTERRUPT_Disable(
2965 Command->kernel->interrupt,
2966 Command->info.tsOverflowInt
2969 Command->info.tsOverflowInt = -1;
2972 /* Delete the commit mutex. */
2973 if (Command->commitMutex != gcvNULL)
2975 gcmkERR_BREAK(gckOS_DeleteMutex(
2976 Command->os, Command->commitMutex
2979 Command->commitMutex = gcvNULL;
2982 /* Delete the command queue mutex. */
2983 if (Command->taskMutex != gcvNULL)
2985 gcmkERR_BREAK(gckOS_DeleteMutex(
2986 Command->os, Command->taskMutex
2989 Command->taskMutex = gcvNULL;
2992 /* Delete the command queue mutex. */
2993 if (Command->queueMutex != gcvNULL)
2995 gcmkERR_BREAK(gckOS_DeleteMutex(
2996 Command->os, Command->queueMutex
2999 Command->queueMutex = gcvNULL;
3002 if (Command->queue != gcvNULL)
3004 /* Delete the command queue. */
3005 gcmkERR_BREAK(gckOS_Free(
3006 Command->os, Command->queue
3010 /* Destroy all allocated buffers. */
3011 while (Command->taskStorage)
3013 /* Copy the buffer pointer. */
3014 nextStorage = Command->taskStorage->next;
3016 /* Free the current container. */
3017 gcmkERR_BREAK(gckOS_Free(
3018 Command->os, Command->taskStorage
3021 /* Advance to the next one. */
3022 Command->taskStorage = nextStorage;
3025 /* Error? */
3026 if (gcmkIS_ERROR(status))
3028 break;
3031 /* Mark the object as unknown. */
3032 Command->object.type = gcvOBJ_UNKNOWN;
3034 /* Free the gckVGCOMMAND structure. */
3035 gcmkERR_BREAK(gckOS_Free(Command->os, Command));
3037 /* Success. */
3038 return gcvSTATUS_OK;
3040 while (gcvFALSE);
3042 /* Restore the object type if failed. */
3043 Command->object.type = gcvOBJ_COMMAND;
3045 gcmkFOOTER();
3046 /* Return the error. */
3047 return status;
3050 gceSTATUS
3051 gckVGCOMMAND_QueryCommandBuffer(
3052 IN gckVGCOMMAND Command,
3053 OUT gcsCOMMAND_BUFFER_INFO_PTR Information
3056 gcmkHEADER_ARG("Command=0x%x Information=0x%x", Command, Information);
3057 /* Verify the arguments. */
3058 gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
3059 gcmkVERIFY_ARGUMENT(Information != gcvNULL);
3061 /* Copy the information. */
3062 gcmkVERIFY_OK(gckOS_MemCopy(
3063 Information, &Command->info, sizeof(gcsCOMMAND_BUFFER_INFO)
3066 gcmkFOOTER_NO();
3067 /* Success. */
3068 return gcvSTATUS_OK;
3071 gceSTATUS
3072 gckVGCOMMAND_Allocate(
3073 IN gckVGCOMMAND Command,
3074 IN gctSIZE_T Size,
3075 OUT gcsCMDBUFFER_PTR * CommandBuffer,
3076 OUT gctPOINTER * Data
3079 gceSTATUS status;
3081 gcmkHEADER_ARG("Command=0x%x Size=0x%x CommandBuffer=0x%x Data=0x%x",
3082 Command, Size, CommandBuffer, Data);
3084 /* Verify the arguments. */
3085 gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
3086 gcmkVERIFY_ARGUMENT(Data != gcvNULL);
3090 /* Allocate the buffer. */
3091 gcmkERR_BREAK(_AllocateCommandBuffer(Command, Size, CommandBuffer));
3093 /* Determine the data pointer. */
3094 * Data = (gctUINT8_PTR) CommandBuffer + (* CommandBuffer)->bufferOffset;
3096 while (gcvFALSE);
3098 gcmkFOOTER();
3099 /* Return status. */
3100 return status;
3103 gceSTATUS
3104 gckVGCOMMAND_Free(
3105 IN gckVGCOMMAND Command,
3106 IN gcsCMDBUFFER_PTR CommandBuffer
3109 gceSTATUS status;
3111 gcmkHEADER_ARG("Command=0x%x CommandBuffer=0x%x",
3112 Command, CommandBuffer);
3114 /* Verify the arguments. */
3115 gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
3116 gcmkVERIFY_ARGUMENT(CommandBuffer != gcvNULL);
3118 /* Free command buffer. */
3119 status = _FreeCommandBuffer(Command->kernel, CommandBuffer);
3121 gcmkFOOTER();
3122 /* Return status. */
3123 return status;
3126 gceSTATUS
3127 gckVGCOMMAND_Execute(
3128 IN gckVGCOMMAND Command,
3129 IN gcsCMDBUFFER_PTR CommandBuffer
3132 gceSTATUS status;
3134 gcmkHEADER_ARG("Command=0x%x CommandBuffer=0x%x",
3135 Command, CommandBuffer);
3137 /* Verify the arguments. */
3138 gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
3139 gcmkVERIFY_ARGUMENT(CommandBuffer != gcvNULL);
3143 gctUINT queueLength;
3144 gcsKERNEL_CMDQUEUE_PTR kernelEntry;
3146 /* Lock the current queue. */
3147 gcmkERR_BREAK(_LockCurrentQueue(
3148 Command, &kernelEntry, &queueLength
3151 /* Set the buffer. */
3152 kernelEntry->commandBuffer = CommandBuffer;
3153 kernelEntry->handler = _FreeKernelCommandBuffer;
3155 /* Lock the current queue. */
3156 gcmkERR_BREAK(_UnlockCurrentQueue(
3157 Command, 1
3160 while (gcvFALSE);
3162 gcmkFOOTER();
3163 /* Return status. */
3164 return status;
3167 gceSTATUS
3168 gckVGCOMMAND_Commit(
3169 IN gckVGCOMMAND Command,
3170 IN gcsVGCONTEXT_PTR Context,
3171 IN gcsVGCMDQUEUE_PTR Queue,
3172 IN gctUINT EntryCount,
3173 IN gcsTASK_MASTER_TABLE_PTR TaskTable
3177 The first buffer is executed through a direct gckVGHARDWARE_Execute call,
3178 therefore only an update is needed after the execution is over. All
3179 consequent buffers need to be executed upon the first update call from
3180 the FE interrupt handler.
3183 static gcsQUEUE_UPDATE_CONTROL _dynamicBuffer[] =
3186 _UpdateDynamicCommandBuffer,
3187 _UpdateDynamicCommandBuffer,
3188 _UpdateLastDynamicCommandBuffer,
3189 _UpdateLastDynamicCommandBuffer
3192 _ExecuteDynamicCommandBuffer,
3193 _UpdateDynamicCommandBuffer,
3194 _ExecuteLastDynamicCommandBuffer,
3195 _UpdateLastDynamicCommandBuffer
3199 static gcsQUEUE_UPDATE_CONTROL _staticBuffer[] =
3202 _UpdateStaticCommandBuffer,
3203 _UpdateStaticCommandBuffer,
3204 _UpdateLastStaticCommandBuffer,
3205 _UpdateLastStaticCommandBuffer
3208 _ExecuteStaticCommandBuffer,
3209 _UpdateStaticCommandBuffer,
3210 _ExecuteLastStaticCommandBuffer,
3211 _UpdateLastStaticCommandBuffer
3215 gceSTATUS status, last;
3217 gcmkHEADER_ARG("Command=0x%x Context=0x%x Queue=0x%x EntryCount=0x%x TaskTable=0x%x",
3218 Command, Context, Queue, EntryCount, TaskTable);
3220 /* Verify the arguments. */
3221 gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
3222 gcmkVERIFY_ARGUMENT(Context != gcvNULL);
3223 gcmkVERIFY_ARGUMENT(Queue != gcvNULL);
3224 gcmkVERIFY_ARGUMENT(EntryCount > 1);
3228 gctBOOL haveFETasks;
3229 gctUINT queueSize;
3230 gcsVGCMDQUEUE_PTR mappedQueue;
3231 gcsVGCMDQUEUE_PTR userEntry;
3232 gcsKERNEL_CMDQUEUE_PTR kernelEntry;
3233 gcsQUEUE_UPDATE_CONTROL_PTR queueControl;
3234 gctUINT currentLength;
3235 gctUINT queueLength;
3236 gctUINT entriesQueued;
3237 gctUINT8_PTR previousEnd;
3238 gctBOOL previousDynamic;
3239 gctBOOL previousExecuted;
3240 gctUINT controlIndex;
3242 /* Acquire the mutex. */
3243 gcmkERR_BREAK(gckOS_AcquireMutex(
3244 Command->os,
3245 Command->commitMutex,
3246 gcvINFINITE
3251 /* Assign a context ID if not yet assigned. */
3252 if (Context->id == 0)
3254 /* Assign the next context number. */
3255 Context->id = ++ Command->contextCounter;
3257 /* See if we overflowed. */
3258 if (Command->contextCounter == 0)
3260 /* We actually did overflow, wow... */
3261 status = gcvSTATUS_OUT_OF_RESOURCES;
3262 break;
3266 /* The first entry in the queue is always the context buffer.
3267 Verify whether the user context is the same as the current
3268 context and if that's the case, skip the first entry. */
3269 if (Context->id == Command->currentContext)
3271 /* Same context as before, skip the first entry. */
3272 EntryCount -= 1;
3273 Queue += 1;
3275 /* Set the signal to avoid user waiting. */
3276 gcmkERR_BREAK(gckOS_UserSignal(
3277 Command->os, Context->signal, Context->process
3280 else
3282 /* Different user context - keep the first entry.
3283 Set the user context as the current one. */
3284 Command->currentContext = Context->id;
3287 /* Reset pointers. */
3288 queueControl = gcvNULL;
3289 previousEnd = gcvNULL;
3291 /* Determine whether there are FE tasks to be performed. */
3292 haveFETasks = (TaskTable->table[gcvBLOCK_COMMAND].head != gcvNULL);
3294 /* Determine the size of the queue. */
3295 queueSize = EntryCount * gcmSIZEOF(gcsVGCMDQUEUE);
3297 /* Map the command queue into the kernel space. */
3298 gcmkERR_BREAK(gckOS_MapUserPointer(
3299 Command->os,
3300 Queue,
3301 queueSize,
3302 (gctPOINTER *) &mappedQueue
3305 /* Set the first entry. */
3306 userEntry = mappedQueue;
3308 /* Process the command queue. */
3309 while (EntryCount)
3311 /* Lock the current queue. */
3312 gcmkERR_BREAK(_LockCurrentQueue(
3313 Command, &kernelEntry, &queueLength
3316 /* Determine the number of entries to process. */
3317 currentLength = (queueLength < EntryCount)
3318 ? queueLength
3319 : EntryCount;
3321 /* Update the number of the entries left to process. */
3322 EntryCount -= currentLength;
3324 /* Reset previous flags. */
3325 previousDynamic = gcvFALSE;
3326 previousExecuted = gcvFALSE;
3328 /* Set the initial control index. */
3329 controlIndex = 0;
3331 /* Process entries. */
3332 for (entriesQueued = 0; entriesQueued < currentLength; entriesQueued += 1)
3334 /* Get the kernel pointer to the command buffer header. */
3335 gcsCMDBUFFER_PTR commandBuffer;
3336 gcmkERR_BREAK(_ConvertUserCommandBufferPointer(
3337 Command,
3338 userEntry->commandBuffer,
3339 &commandBuffer
3342 /* Is it a dynamic command buffer? */
3343 if (userEntry->dynamic)
3345 /* Select dynamic buffer control functions. */
3346 queueControl = &_dynamicBuffer[controlIndex];
3349 /* No, a static command buffer. */
3350 else
3352 /* Select static buffer control functions. */
3353 queueControl = &_staticBuffer[controlIndex];
3356 /* Set the command buffer pointer to the entry. */
3357 kernelEntry->commandBuffer = commandBuffer;
3359 /* If the previous entry was a dynamic command buffer,
3360 link it to the current. */
3361 if (previousDynamic)
3363 gcmkERR_BREAK(gckVGCOMMAND_FetchCommand(
3364 Command,
3365 previousEnd,
3366 commandBuffer->address,
3367 commandBuffer->dataCount,
3368 gcvNULL
3371 /* The buffer will be auto-executed, only need to
3372 update it after it has been executed. */
3373 kernelEntry->handler = queueControl->update;
3375 /* The buffer is only being updated. */
3376 previousExecuted = gcvFALSE;
3378 else
3380 /* Set the buffer up for execution. */
3381 kernelEntry->handler = queueControl->execute;
3383 /* The buffer is being updated. */
3384 previousExecuted = gcvTRUE;
3387 /* The current buffer's END command becomes the last END. */
3388 previousEnd
3389 = ((gctUINT8_PTR) commandBuffer)
3390 + commandBuffer->bufferOffset
3391 + commandBuffer->dataCount * Command->info.commandAlignment
3392 - Command->info.staticTailSize;
3394 /* Update the last entry info. */
3395 previousDynamic = userEntry->dynamic;
3397 /* Advance entries. */
3398 userEntry += 1;
3399 kernelEntry += 1;
3401 /* Update the control index. */
3402 controlIndex = 1;
3405 /* If the previous entry was a dynamic command buffer,
3406 terminate it with an END. */
3407 if (previousDynamic)
3409 gcmkERR_BREAK(gckVGCOMMAND_EndCommand(
3410 Command,
3411 previousEnd,
3412 Command->info.feBufferInt,
3413 gcvNULL
3417 /* Last buffer? */
3418 if (EntryCount == 0)
3420 /* Modify the last command buffer's routines to handle
3421 tasks if any.*/
3422 if (haveFETasks)
3424 if (previousExecuted)
3426 kernelEntry[-1].handler = queueControl->lastExecute;
3428 else
3430 kernelEntry[-1].handler = queueControl->lastUpdate;
3434 /* Release the mutex. */
3435 gcmkERR_BREAK(gckOS_ReleaseMutex(
3436 Command->os,
3437 Command->queueMutex
3439 /* Schedule tasks. */
3440 gcmkERR_BREAK(_ScheduleTasks(Command, TaskTable, previousEnd));
3442 /* Acquire the mutex. */
3443 gcmkERR_BREAK(gckOS_AcquireMutex(
3444 Command->os,
3445 Command->queueMutex,
3446 gcvINFINITE
3450 /* Unkock and schedule the current queue for execution. */
3451 gcmkERR_BREAK(_UnlockCurrentQueue(
3452 Command, currentLength
3456 /* Unmap the user command buffer. */
3457 gcmkERR_BREAK(gckOS_UnmapUserPointer(
3458 Command->os,
3459 Queue,
3460 queueSize,
3461 mappedQueue
3464 while (gcvFALSE);
3466 /* Release the mutex. */
3467 gcmkCHECK_STATUS(gckOS_ReleaseMutex(
3468 Command->os,
3469 Command->commitMutex
3472 while (gcvFALSE);
3474 gcmkFOOTER();
3475 /* Return status. */
3476 return status;
3479 #endif /* gcdENABLE_VG */