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"
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
44 # define gcvQUEUE_TIMEOUT 10
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) \
59 _EventHandler_##Block##_##Number( \
60 IN gckVGKERNEL Kernel \
63 #define gcmDEFINE_INTERRUPT_HANDLER(Block, Number) \
64 gcmDECLARE_INTERRUPT_HANDLER(Block, Number) \
66 return _EventHandler_Block( \
68 &Kernel->command->taskTable[gcvBLOCK_##Block], \
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
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 \******************************************************************************/
103 IN gckVGCOMMAND Command
,
104 IN gcsKERNEL_QUEUE_HEADER_PTR Queue
107 gceSTATUS status
= gcvSTATUS_OK
;
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? */
127 /* Read IDLE register. */
128 gcmkVERIFY_OK(gckVGHARDWARE_GetIdle(Command
->hardware
, &idle
));
131 gcvLEVEL_ERROR
, gcvZONE_COMMAND
,
132 "%s: timeout, IDLE=%08X\n",
137 /* Increment the timeout counter. */
147 IN gckVGCOMMAND Command
,
152 gcsBLOCK_TASK_ENTRY_PTR entry
;
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. */
178 /* Set the new index. */
179 entry
->interruptIndex
= (index
== entry
->interruptCount
)
183 /* Return interrupt value. */
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 ------------------*/
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
;
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
;
254 /* Remove from the list. */
255 prev
->allocNext
= gcvNULL
;
258 /* Buffer from the middle. */
261 prev
->allocNext
= next
;
262 next
->allocPrev
= prev
;
267 /*----------------------------------------------------------------------------*/
268 /*--------------------- Free Task Buffer List Management ---------------------*/
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. */
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
;
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
);
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. */
327 /* Update the head. */
328 Command
->taskFreeHead
= Buffer
->freeNext
;
330 /* Terminate the next buffer. */
331 Command
->taskFreeHead
->freePrev
= gcvFREE_TASK_TERMINATOR
;
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. */
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 --------------------------*/
368 IN gckVGCOMMAND Command
,
369 IN gcsTASK_CONTAINER_PTR Buffer
,
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. */
389 /* Initialize the split buffer. */
390 splitBuffer
->referenceCount
= 0;
391 splitBuffer
->size
= splitBufferSize
;
392 splitBuffer
->freePrev
= gcvNULL
;
393 splitBuffer
->freeNext
= gcvNULL
;
396 _InsertTaskBuffer(Buffer
, splitBuffer
);
397 _AppendToFreeList(Command
, splitBuffer
);
402 _AllocateTaskContainer(
403 IN gckVGCOMMAND Command
,
405 OUT gcsTASK_CONTAINER_PTR
* Buffer
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. */
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(
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. */
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. */
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. */
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
);
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
);
552 merged
->size
= mergedSize
;
556 /* The current path data buffer is the one that remains. */
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
);
570 merged
->size
= mergedSize
;
573 /* Add the current buffer into the free list. */
574 _AppendToFreeList(Command
, merged
);
579 /******************************************************************************\
580 ********************************* Task Scheduling ******************************
581 \******************************************************************************/
585 IN gckVGCOMMAND Command
,
586 IN gcsTASK_MASTER_TABLE_PTR TaskTable
,
587 IN gctUINT8_PTR PreviousEnd
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
;
601 gctUINT8_PTR eventCommand
;
603 /* Nothing to schedule? */
604 if (TaskTable
->size
== 0)
606 status
= gcvSTATUS_OK
;
610 /* Acquire the mutex. */
611 gcmkERR_BREAK(gckOS_AcquireMutex(
618 gcvLEVEL_VERBOSE
, gcvZONE_COMMAND
,
620 __FUNCTION__
, __LINE__
626 gcvLEVEL_VERBOSE
, gcvZONE_COMMAND
,
627 " number of tasks scheduled = %d\n"
628 " size of event data in bytes = %d\n",
633 /* Allocate task buffer. */
634 gcmkERR_BREAK(_AllocateTaskContainer(
640 /* Determine the task data pointer. */
641 kernelTask
= (gctUINT8_PTR
) (container
+ 1);
643 /* Initialize the reference count. */
644 container
->referenceCount
= TaskTable
->count
;
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. */
660 gcvLEVEL_VERBOSE
, gcvZONE_COMMAND
,
661 " processing tasks for block %d\n",
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
)
672 gcvLEVEL_VERBOSE
, gcvZONE_COMMAND
,
673 " first task container for the block added\n",
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. */
685 kernelTaskEntry
->link
->cotainer
= container
;
686 kernelTaskEntry
->link
->task
= (gcsTASK_HEADER_PTR
) kernelTask
;
689 /* Set initial task. */
690 userTask
= userTaskEntry
->head
;
693 gcvLEVEL_VERBOSE
, gcvZONE_COMMAND
,
694 " copying user tasks over to the kernel\n"
701 gcvLEVEL_VERBOSE
, gcvZONE_COMMAND
,
702 " task ID = %d, size = %d\n",
703 ((gcsTASK_HEADER_PTR
) (userTask
+ 1))->id
,
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
);
732 /* Release the mutex. */
733 gcmkERR_BREAK(gckOS_ReleaseMutex(
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. */
753 /* Get the interrupt number. */
754 interrupt
= _GetNextInterrupt(Command
, block
);
757 gcvLEVEL_VERBOSE
, gcvZONE_COMMAND
,
758 "%s(%d): block = %d interrupt = %d\n",
759 __FUNCTION__
, __LINE__
,
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
779 /******************************************************************************\
780 ******************************** Memory Management *****************************
781 \******************************************************************************/
786 IN gcuVIDMEM_NODE_PTR Node
,
787 IN gctUINT32 Address
,
788 OUT gctPOINTER
* KernelPointer
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(
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(
831 gcmSIZEOF(gcsCMDBUFFER
),
832 (gctPOINTER
*) &mappedUserCommandBuffer
835 /* Determine the address of the header. */
837 = mappedUserCommandBuffer
->address
838 - mappedUserCommandBuffer
->bufferOffset
;
840 /* Translate the logical address to the kernel space. */
841 gcmkERR_BREAK(_HardwareToKernel(
843 mappedUserCommandBuffer
->node
,
845 (gctPOINTER
*) KernelCommandBuffer
850 /* Unmap the user command buffer. */
851 if (mappedUserCommandBuffer
!= gcvNULL
)
853 gcmkCHECK_STATUS(gckOS_UnmapUserPointer(
856 gcmSIZEOF(gcsCMDBUFFER
),
857 mappedUserCommandBuffer
867 IN gckVGCOMMAND Command
,
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;
884 /* Allocate from the system pool. */
885 pool
= gcvPOOL_SYSTEM
;
887 /* Allocate memory. */
888 gcmkERR_BREAK(gckKERNEL_AllocateLinearMemory(
889 Command
->kernel
->kernel
, &pool
,
891 gcvSURF_TYPE_UNKNOWN
,
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
;
903 /* Lock the command buffer. */
904 gcmkERR_BREAK(gckVIDMEM_Lock(
905 Command
->kernel
->kernel
,
911 /* Translate the logical address to the kernel space. */
912 gcmkERR_BREAK(_HardwareToKernel(
919 /* Set return values. */
932 /* Unlock the command buffer. */
935 gcmkCHECK_STATUS(gckVIDMEM_Unlock(
936 Command
->kernel
->kernel
, node
, gcvSURF_TYPE_UNKNOWN
, gcvNULL
940 /* Free the command buffer. */
941 gcmkCHECK_STATUS(gckVIDMEM_Free(
952 IN gckVGKERNEL Kernel
,
953 IN gcuVIDMEM_NODE_PTR Node
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
));
973 _AllocateCommandBuffer(
974 IN gckVGCOMMAND Command
,
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. */
993 = gcmALIGN(gcmSIZEOF(gcsCMDBUFFER
), Command
->info
.addressAlignment
);
995 /* Align the requested size. */
997 = gcmALIGN(Size
, Command
->info
.commandAlignment
);
999 /* Determine the size of the buffer to allocate. */
1003 + Command
->info
.staticTailSize
;
1005 /* Allocate the command buffer. */
1006 gcmkERR_BREAK(_AllocateLinear(
1009 Command
->info
.addressAlignment
,
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. */
1032 = (gctUINT8_PTR
) commandBuffer
1036 /* Append an END command. */
1037 gcmkERR_BREAK(gckVGCOMMAND_EndCommand(
1040 Command
->info
.feBufferInt
,
1044 /* Set the return pointer. */
1045 * CommandBuffer
= commandBuffer
;
1048 return gcvSTATUS_OK
;
1053 if (node
!= gcvNULL
)
1055 /* Free the command buffer. */
1056 gcmkCHECK_STATUS(_FreeLinear(Command
->kernel
, node
));
1059 /* Return status. */
1065 IN gckVGKERNEL Kernel
,
1066 IN gcsCMDBUFFER_PTR CommandBuffer
1071 /* Free the buffer. */
1072 status
= _FreeLinear(Kernel
, CommandBuffer
->node
);
1074 /* Return status. */
1079 /******************************************************************************\
1080 ****************************** TS Overflow Handler *****************************
1081 \******************************************************************************/
1084 _EventHandler_TSOverflow(
1085 IN gckVGKERNEL Kernel
1090 "%s(%d): **** TS OVERFLOW ENCOUNTERED ****\n",
1091 __FUNCTION__
, __LINE__
1094 return gcvSTATUS_OK
;
1098 /******************************************************************************\
1099 ****************************** Bus Error Handler *******************************
1100 \******************************************************************************/
1103 _EventHandler_BusError(
1104 IN gckVGKERNEL Kernel
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
1128 gckVGCOMMAND Command
,
1129 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1134 gckVGCOMMAND Command
,
1135 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1140 gckVGCOMMAND Command
,
1141 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1146 gckVGCOMMAND Command
,
1147 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1152 gckVGCOMMAND Command
,
1153 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1158 gckVGCOMMAND Command
,
1159 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1163 _TaskUnlockVideoMemory(
1164 gckVGCOMMAND Command
,
1165 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1169 _TaskFreeVideoMemory(
1170 gckVGCOMMAND Command
,
1171 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1175 _TaskFreeContiguousMemory(
1176 gckVGCOMMAND Command
,
1177 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1181 _TaskUnmapUserMemory(
1182 gckVGCOMMAND Command
,
1183 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
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 */
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
;
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
);
1243 return gcvSTATUS_OK
;
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. */
1266 /* Perform the current task. */
1267 gcmkERR_BREAK(_taskRoutine
[TaskHeader
->task
->id
](
1272 /* Update the task count. */
1276 /* Return status. */
1282 gckVGCOMMAND Command
,
1283 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
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(
1298 gcmSIZEOF(gctUINT32
),
1299 (gctPOINTER
*) &logical
1302 /* Increment data. */
1305 /* Unmap the physical memory. */
1306 gcmkERR_BREAK(gckOS_UnmapPhysical(
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);
1320 /* Return status. */
1326 gckVGCOMMAND Command
,
1327 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
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(
1342 gcmSIZEOF(gctUINT32
),
1343 (gctPOINTER
*) &logical
1346 /* Decrement data. */
1349 /* Unmap the physical memory. */
1350 gcmkERR_BREAK(gckOS_UnmapPhysical(
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);
1364 /* Return status. */
1370 gckVGCOMMAND Command
,
1371 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
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);
1393 /* Return status. */
1399 gckVGCOMMAND Command
,
1400 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
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(
1417 gcmSIZEOF(gctUINT32
),
1418 (gctPOINTER
*) &userCounter
1421 gcmkERR_BREAK(gckOS_MapPhysical(
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
)
1442 gcmkERR_BREAK(gckOS_Signal(
1443 Command
->os
, task
->signal
, gcvTRUE
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);
1463 /* Destroy the mapped signal. */
1464 if (signal
!= gcvNULL
)
1466 gcmkVERIFY_OK(gckOS_DestroySignal(
1471 /* Unmap the physical memory. */
1472 if (kernelCounter
!= gcvNULL
)
1474 gcmkVERIFY_OK(gckOS_UnmapPhysical(
1477 gcmSIZEOF(gctUINT32
)
1481 if (userCounter
!= gcvNULL
)
1483 gcmkVERIFY_OK(gckOS_UnmapPhysical(
1486 gcmSIZEOF(gctUINT32
)
1490 /* Return status. */
1495 _TaskUnlockVideoMemory(
1496 gckVGCOMMAND Command
,
1497 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
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
,
1512 gcvSURF_TYPE_UNKNOWN
,
1515 /* Update the reference counter. */
1516 TaskHeader
->container
->referenceCount
-= 1;
1518 /* Update the task pointer. */
1519 TaskHeader
->task
= (gcsTASK_HEADER_PTR
) (task
+ 1);
1523 /* Return status. */
1528 _TaskFreeVideoMemory(
1529 gckVGCOMMAND Command
,
1530 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
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);
1552 /* Return status. */
1557 _TaskFreeContiguousMemory(
1558 gckVGCOMMAND Command
,
1559 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
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);
1583 /* Return status. */
1588 _TaskUnmapUserMemory(
1589 gckVGCOMMAND Command
,
1590 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
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);
1614 /* Return status. */
1620 gckVGCOMMAND Command
,
1621 gcsBLOCK_TASK_ENTRY_PTR TaskHeader
1628 /* Cast the task pointer. */
1629 gcsTASK_UNMAP_MEMORY_PTR task
1630 = (gcsTASK_UNMAP_MEMORY_PTR
) TaskHeader
->task
;
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);
1645 /* Return status. */
1650 /******************************************************************************\
1651 ************ Hardware Block Interrupt Handlers For Scheduled Events ************
1652 \******************************************************************************/
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(
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
](
1701 /* Is the next task is LINK? */
1702 if (TaskHeader
->task
->id
== gcvTASK_LINK
)
1704 gcmkERR_BREAK(_taskRoutine
[TaskHeader
->task
->id
](
1715 /* Release the mutex. */
1716 gcmkCHECK_STATUS(gckOS_ReleaseMutex(
1724 /* 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
;
1745 /* Get the command buffer object. */
1746 command
= Kernel
->command
;
1748 /* Acquire the mutex. */
1749 gcmkERR_BREAK(gckOS_AcquireMutex(
1751 command
->queueMutex
,
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. */
1767 /* Call post-execution function. */
1768 status
= entry
->handler(Kernel
, entry
);
1771 if (gcmkIS_ERROR(status
))
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
;
1789 status
= gcvSTATUS_OK
;
1791 /* Break out of the loop. */
1795 /* Advance to the next 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
);
1815 += gcmSIZEOF(gcsKERNEL_QUEUE_HEADER
)
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(
1845 commandBuffer
->address
,
1846 commandBuffer
->dataCount
1850 if (gcmkIS_ERROR(status
))
1855 "[%s] line %d: failed to start the next queue.\n",
1856 __FUNCTION__
, __LINE__
1861 /* Break out of the loop. */
1866 /* Release the mutex. */
1867 gcmkCHECK_STATUS(gckOS_ReleaseMutex(
1875 /* 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 \******************************************************************************/
1917 _UpdateStaticCommandBuffer(
1918 IN gckVGKERNEL Kernel
,
1919 IN gcsKERNEL_CMDQUEUE_PTR Entry
1923 gcvLEVEL_VERBOSE
, gcvZONE_COMMAND
,
1925 __FUNCTION__
, __LINE__
1929 return gcvSTATUS_OK
;
1933 _ExecuteStaticCommandBuffer(
1934 IN gckVGKERNEL Kernel
,
1935 IN gcsKERNEL_CMDQUEUE_PTR Entry
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
;
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(
1961 commandBuffer
->address
,
1962 commandBuffer
->dataCount
1966 return gcvSTATUS_EXECUTED
;
1970 /* Return status. */
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
);
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(
1999 &Kernel
->command
->taskTable
[gcvBLOCK_COMMAND
],
2005 _ExecuteLastStaticCommandBuffer(
2006 IN gckVGKERNEL Kernel
,
2007 IN gcsKERNEL_CMDQUEUE_PTR Entry
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
;
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(
2031 commandBuffer
->address
,
2032 commandBuffer
->dataCount
2036 return gcvSTATUS_EXECUTED
;
2040 /* Return status. */
2045 /******************************************************************************\
2046 ************************* Dynamic Command Buffer Handlers **********************
2047 \******************************************************************************/
2050 _UpdateDynamicCommandBuffer(
2051 IN gckVGKERNEL Kernel
,
2052 IN gcsKERNEL_CMDQUEUE_PTR Entry
2056 gcvLEVEL_VERBOSE
, gcvZONE_COMMAND
,
2058 __FUNCTION__
, __LINE__
2062 return gcvSTATUS_OK
;
2066 _ExecuteDynamicCommandBuffer(
2067 IN gckVGKERNEL Kernel
,
2068 IN gcsKERNEL_CMDQUEUE_PTR Entry
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
;
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(
2092 commandBuffer
->address
,
2093 commandBuffer
->dataCount
2097 return gcvSTATUS_EXECUTED
;
2101 /* Return status. */
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
);
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(
2130 &Kernel
->command
->taskTable
[gcvBLOCK_COMMAND
],
2136 _ExecuteLastDynamicCommandBuffer(
2137 IN gckVGKERNEL Kernel
,
2138 IN gcsKERNEL_CMDQUEUE_PTR Entry
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
;
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(
2162 commandBuffer
->address
,
2163 commandBuffer
->dataCount
2167 return gcvSTATUS_EXECUTED
;
2171 /* Return status. */
2176 /******************************************************************************\
2177 ********************************* Other Handlers *******************************
2178 \******************************************************************************/
2181 _FreeKernelCommandBuffer(
2182 IN gckVGKERNEL Kernel
,
2183 IN gcsKERNEL_CMDQUEUE_PTR Entry
2188 /* Free the command buffer. */
2189 status
= _FreeCommandBuffer(Kernel
, Entry
->commandBuffer
);
2191 /* Return status. */
2196 /******************************************************************************\
2197 ******************************* Queue Management *******************************
2198 \******************************************************************************/
2200 #if gcvDUMP_COMMAND_BUFFER
2203 IN gckVGCOMMAND Command
,
2204 IN gcsKERNEL_QUEUE_HEADER_PTR QueueHeader
,
2205 IN gctUINT EntryCount
2208 gcsKERNEL_CMDQUEUE_PTR entry
;
2211 #if defined(gcvCOMMAND_BUFFER_NAME)
2212 static gctUINT arrayCount
= 0;
2215 /* Is dumpinng enabled? */
2216 if (!Commad
->enableDumping
)
2221 #if !defined(gcvCOMMAND_BUFFER_NAME)
2223 gcvLEVEL_INFO
, gcvZONE_COMMAND
,
2224 "COMMAND QUEUE DUMP: %d entries\n", EntryCount
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
;
2241 #if gcvDUMP_COMMAND_LINES
2245 #if !defined(gcvCOMMAND_BUFFER_NAME)
2247 gcvLEVEL_INFO
, gcvZONE_COMMAND
,
2248 "ENTRY %d\n", queueIndex
2252 /* Reset the count. */
2255 /* Set the initial buffer. */
2256 buffer
= entry
->commandBuffer
;
2258 /* Loop through all subbuffers. */
2261 /* Update the count. */
2264 /* Advance to the next subbuffer. */
2265 buffer
= buffer
->nextSubBuffer
;
2268 #if !defined(gcvCOMMAND_BUFFER_NAME)
2269 if (bufferCount
> 1)
2274 " COMMAND BUFFER SET: %d buffers.\n",
2280 /* Reset the buffer index. */
2283 /* Set the initial buffer. */
2284 buffer
= entry
->commandBuffer
;
2286 /* Loop through all subbuffers. */
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)
2299 " COMMAND BUFFER: count=%d (0x%X), size=%d bytes @ %08X.\n",
2311 " COMMAND BUFFER %d: count=%d (0x%X), size=%d bytes @ %08X\n",
2321 /* Determine the number of double words to print. */
2324 /* Determine the buffer location. */
2325 data
= (gctUINT32_PTR
)
2327 (gctUINT8_PTR
) buffer
+ buffer
->bufferOffset
2330 #if defined(gcvCOMMAND_BUFFER_NAME)
2334 "unsigned int _" gcvCOMMAND_BUFFER_NAME
"_%d[] =\n",
2347 #if gcvDUMP_COMMAND_LINES
2348 /* Reset the line number. */
2352 #if defined(gcvCOMMAND_BUFFER_NAME)
2356 for (i
= 0; i
< count
; i
+= 1)
2360 #if defined(gcvCOMMAND_BUFFER_NAME)
2361 gcmkTRACE_ZONE(gcvLEVEL_INFO
, gcvZONE_COMMAND
, "\t");
2363 gcmkTRACE_ZONE(gcvLEVEL_INFO
, gcvZONE_COMMAND
, " ");
2367 #if gcvDUMP_COMMAND_LINES
2368 if (lineNumber
== gcvDUMP_COMMAND_LINES
)
2370 gcmkTRACE_ZONE(gcvLEVEL_INFO
, gcvZONE_COMMAND
, " . . . . . . . . .\n");
2374 gcmkTRACE_ZONE(gcvLEVEL_INFO
, gcvZONE_COMMAND
, "0x%08X", data
[i
]);
2378 gcmkTRACE_ZONE(gcvLEVEL_INFO
, gcvZONE_COMMAND
, "\n");
2380 #if gcvDUMP_COMMAND_LINES
2386 if (((i
+ 1) % 8) == 0)
2388 gcmkTRACE_ZONE(gcvLEVEL_INFO
, gcvZONE_COMMAND
, ",\n");
2390 #if gcvDUMP_COMMAND_LINES
2396 gcmkTRACE_ZONE(gcvLEVEL_INFO
, gcvZONE_COMMAND
, ", ");
2401 #if defined(gcvCOMMAND_BUFFER_NAME)
2409 /* Advance to the next subbuffer. */
2410 buffer
= buffer
->nextSubBuffer
;
2414 /* Advance to the next entry. */
2422 IN gckVGCOMMAND Command
,
2423 OUT gcsKERNEL_CMDQUEUE_PTR
* Entries
,
2424 OUT gctUINT_PTR EntryCount
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(
2449 Command
->queueMutex
,
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
);
2466 return gcvSTATUS_OK
;
2470 /* Return status. */
2475 _UnlockCurrentQueue(
2476 IN gckVGCOMMAND Command
,
2477 IN gctUINT EntryCount
2484 #if !gcdENABLE_INFINITE_SPEED_HW
2485 gcsKERNEL_QUEUE_HEADER_PTR queueTail
;
2486 gcsKERNEL_QUEUE_HEADER_PTR queueHead
;
2487 gcsKERNEL_QUEUE_HEADER_PTR queueNext
;
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
);
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
)
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. */
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(
2561 commandBuffer
->address
,
2562 commandBuffer
->dataCount
2566 /* The queue was not empty. */
2569 /* Advance the merge buffer if needed. */
2570 if (queueHead
== Command
->mergeQueue
)
2572 Command
->mergeQueue
= queueNext
;
2577 /* Release the mutex. */
2578 gcmkERR_BREAK(gckOS_ReleaseMutex(
2584 return gcvSTATUS_OK
;
2588 /* Return status. */
2593 /******************************************************************************\
2594 ****************************** gckVGCOMMAND API Code *****************************
2595 \******************************************************************************/
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
;
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(
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
;
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(
2678 (gctPOINTER
*) &command
->queue
2681 /* Initialize the command queue. */
2682 queue
= command
->queue
;
2684 queue
->size
= QueueSize
- gcmSIZEOF(gcsKERNEL_QUEUE_HEADER
);
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(
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(
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(
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
2770 gcmkERR_BREAK(gckOS_IncrementSemaphore(
2771 command
->os
, entry
->interruptSemaphore
2777 if (gcmkIS_ERROR(status
))
2782 /* Get the FE interrupt. */
2783 command
->info
.feBufferInt
2784 = command
->taskTable
[gcvBLOCK_COMMAND
].interruptArray
[0];
2786 /* Return gckVGCOMMAND object pointer. */
2790 return gcvSTATUS_OK
;
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(
2821 entry
->interruptArray
[j
]
2826 /* Disable the bus error interrupt. */
2827 gcmkCHECK_STATUS(gckVGINTERRUPT_Disable(
2829 command
->busErrorInt
2832 /* Disable TS overflow interrupt. */
2833 if (command
->info
.tsOverflowInt
!= -1)
2835 gcmkCHECK_STATUS(gckVGINTERRUPT_Disable(
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(
2880 /* Return the error. */
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
);
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. */
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. */
2939 entry
->interruptCount
-= 1;
2943 if (gcmkIS_ERROR(status
))
2950 if (gcmkIS_ERROR(status
))
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
;
3026 if (gcmkIS_ERROR(status
))
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
));
3038 return gcvSTATUS_OK
;
3042 /* Restore the object type if failed. */
3043 Command
->object
.type
= gcvOBJ_COMMAND
;
3046 /* Return the error. */
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
)
3068 return gcvSTATUS_OK
;
3072 gckVGCOMMAND_Allocate(
3073 IN gckVGCOMMAND Command
,
3075 OUT gcsCMDBUFFER_PTR
* CommandBuffer
,
3076 OUT gctPOINTER
* Data
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
;
3099 /* Return status. */
3105 IN gckVGCOMMAND Command
,
3106 IN gcsCMDBUFFER_PTR CommandBuffer
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
);
3122 /* Return status. */
3127 gckVGCOMMAND_Execute(
3128 IN gckVGCOMMAND Command
,
3129 IN gcsCMDBUFFER_PTR CommandBuffer
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(
3163 /* Return status. */
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
;
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(
3245 Command
->commitMutex
,
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
;
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. */
3275 /* Set the signal to avoid user waiting. */
3276 gcmkERR_BREAK(gckOS_UserSignal(
3277 Command
->os
, Context
->signal
, Context
->process
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(
3302 (gctPOINTER
*) &mappedQueue
3305 /* Set the first entry. */
3306 userEntry
= mappedQueue
;
3308 /* Process the command queue. */
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
)
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. */
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(
3338 userEntry
->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. */
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(
3366 commandBuffer
->address
,
3367 commandBuffer
->dataCount
,
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
;
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. */
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. */
3401 /* Update the control index. */
3405 /* If the previous entry was a dynamic command buffer,
3406 terminate it with an END. */
3407 if (previousDynamic
)
3409 gcmkERR_BREAK(gckVGCOMMAND_EndCommand(
3412 Command
->info
.feBufferInt
,
3418 if (EntryCount
== 0)
3420 /* Modify the last command buffer's routines to handle
3424 if (previousExecuted
)
3426 kernelEntry
[-1].handler
= queueControl
->lastExecute
;
3430 kernelEntry
[-1].handler
= queueControl
->lastUpdate
;
3434 /* Release the mutex. */
3435 gcmkERR_BREAK(gckOS_ReleaseMutex(
3439 /* Schedule tasks. */
3440 gcmkERR_BREAK(_ScheduleTasks(Command
, TaskTable
, previousEnd
));
3442 /* Acquire the mutex. */
3443 gcmkERR_BREAK(gckOS_AcquireMutex(
3445 Command
->queueMutex
,
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(
3466 /* Release the mutex. */
3467 gcmkCHECK_STATUS(gckOS_ReleaseMutex(
3469 Command
->commitMutex
3475 /* Return status. */
3479 #endif /* gcdENABLE_VG */