1 /****************************************************************************
3 * Copyright (C) 2005 - 2014 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 *****************************************************************************/
22 #include "gc_hal_kernel_precomp.h"
24 #define _GC_OBJ_ZONE gcvZONE_VIDMEM
26 /******************************************************************************\
27 ******************************* Private Functions ******************************
28 \******************************************************************************/
30 /*******************************************************************************
34 ** Split a node on the required byte boundary.
39 ** Pointer to an gckOS object.
41 ** gcuVIDMEM_NODE_PTR Node
42 ** Pointer to the node to split.
45 ** Number of bytes to keep in the node.
54 ** gcvTRUE if the node was split successfully, or gcvFALSE if there is an
61 IN gcuVIDMEM_NODE_PTR Node,
65 gcuVIDMEM_NODE_PTR node;
66 gctPOINTER pointer = gcvNULL;
68 /* Make sure the byte boundary makes sense. */
69 if ((Bytes <= 0) || (Bytes > Node->VidMem.bytes))
74 /* Allocate a new gcuVIDMEM_NODE object. */
75 if (gcmIS_ERROR(gckOS_Allocate(Os,
76 gcmSIZEOF(gcuVIDMEM_NODE),
85 /* Initialize gcuVIDMEM_NODE structure. */
86 node->VidMem.offset = Node->VidMem.offset + Bytes;
87 node->VidMem.bytes = Node->VidMem.bytes - Bytes;
88 node->VidMem.alignment = 0;
89 node->VidMem.locked = 0;
90 node->VidMem.memory = Node->VidMem.memory;
91 node->VidMem.pool = Node->VidMem.pool;
92 node->VidMem.physical = Node->VidMem.physical;
94 node->VidMem.processID = 0;
95 node->VidMem.logical = gcvNULL;
98 /* Insert node behind specified node. */
99 node->VidMem.next = Node->VidMem.next;
100 node->VidMem.prev = Node;
101 Node->VidMem.next = node->VidMem.next->VidMem.prev = node;
103 /* Insert free node behind specified node. */
104 node->VidMem.nextFree = Node->VidMem.nextFree;
105 node->VidMem.prevFree = Node;
106 Node->VidMem.nextFree = node->VidMem.nextFree->VidMem.prevFree = node;
108 /* Adjust size of specified node. */
109 Node->VidMem.bytes = Bytes;
115 /*******************************************************************************
119 ** Merge two adjacent nodes together.
124 ** Pointer to an gckOS object.
126 ** gcuVIDMEM_NODE_PTR Node
127 ** Pointer to the first of the two nodes to merge.
137 IN gcuVIDMEM_NODE_PTR Node
140 gcuVIDMEM_NODE_PTR node;
143 /* Save pointer to next node. */
144 node = Node->VidMem.next;
146 /* This is a good time to make sure the heap is not corrupted. */
147 if (Node->VidMem.offset + Node->VidMem.bytes != node->VidMem.offset)
149 /* Corrupted heap. */
151 Node->VidMem.offset + Node->VidMem.bytes == node->VidMem.offset);
152 return gcvSTATUS_HEAP_CORRUPTED;
155 /* Adjust byte count. */
156 Node->VidMem.bytes += node->VidMem.bytes;
158 /* Unlink next node from linked list. */
159 Node->VidMem.next = node->VidMem.next;
160 Node->VidMem.nextFree = node->VidMem.nextFree;
162 Node->VidMem.next->VidMem.prev =
163 Node->VidMem.nextFree->VidMem.prevFree = Node;
165 /* Free next node. */
166 status = gcmkOS_SAFE_FREE(Os, node);
170 /******************************************************************************\
171 ******************************* gckVIDMEM API Code ******************************
172 \******************************************************************************/
174 /*******************************************************************************
176 ** gckVIDMEM_ConstructVirtual
178 ** Construct a new gcuVIDMEM_NODE union for virtual memory.
183 ** Pointer to an gckKERNEL object.
186 ** Number of byte to allocate.
190 ** gcuVIDMEM_NODE_PTR * Node
191 ** Pointer to a variable that receives the gcuVIDMEM_NODE union pointer.
194 gckVIDMEM_ConstructVirtual(
198 OUT gcuVIDMEM_NODE_PTR * Node
203 gcuVIDMEM_NODE_PTR node = gcvNULL;
204 gctPOINTER pointer = gcvNULL;
207 gcmkHEADER_ARG("Kernel=0x%x Flag=%x Bytes=%lu", Kernel, Flag, Bytes);
209 /* Verify the arguments. */
210 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
211 gcmkVERIFY_ARGUMENT(Bytes > 0);
212 gcmkVERIFY_ARGUMENT(Node != gcvNULL);
214 /* Extract the gckOS object pointer. */
216 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
218 /* Allocate an gcuVIDMEM_NODE union. */
219 gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcuVIDMEM_NODE), &pointer));
223 /* Initialize gcuVIDMEM_NODE union for virtual memory. */
224 node->Virtual.kernel = Kernel;
225 node->Virtual.contiguous = Flag & gcvALLOC_FLAG_CONTIGUOUS;
226 node->Virtual.logical = gcvNULL;
228 node->Virtual.kernelVirtual = gcvNULL;
231 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
233 node->Virtual.lockeds[i] = 0;
234 node->Virtual.pageTables[i] = gcvNULL;
235 node->Virtual.lockKernels[i] = gcvNULL;
238 gcmkONERROR(gckOS_GetProcessID(&node->Virtual.processID));
240 /* Allocate the virtual memory. */
242 gckOS_AllocatePagedMemoryEx(os,
244 node->Virtual.bytes = Bytes,
246 &node->Virtual.physical));
248 /* Return pointer to the gcuVIDMEM_NODE union. */
251 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
252 "Created virtual node 0x%x for %u bytes @ 0x%x",
253 node, Bytes, node->Virtual.physical);
256 gcmkFOOTER_ARG("*Node=0x%x", *Node);
263 /* Free the structure. */
264 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, node));
267 /* Return the status. */
272 /*******************************************************************************
274 ** gckVIDMEM_DestroyVirtual
276 ** Destroy an gcuVIDMEM_NODE union for virtual memory.
280 ** gcuVIDMEM_NODE_PTR Node
281 ** Pointer to a gcuVIDMEM_NODE union.
288 gckVIDMEM_DestroyVirtual(
289 IN gcuVIDMEM_NODE_PTR Node
294 gcmkHEADER_ARG("Node=0x%x", Node);
296 /* Verify the arguments. */
297 gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL);
299 /* Extact the gckOS object pointer. */
300 os = Node->Virtual.kernel->os;
301 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
303 /* Delete the gcuVIDMEM_NODE union. */
304 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, Node));
311 /*******************************************************************************
313 ** gckVIDMEM_Construct
315 ** Construct a new gckVIDMEM object.
320 ** Pointer to an gckOS object.
322 ** gctUINT32 BaseAddress
323 ** Base address for the video memory heap.
326 ** Number of bytes in the video memory heap.
328 ** gctSIZE_T Threshold
329 ** Minimum number of bytes beyond am allocation before the node is
330 ** split. Can be used as a minimum alignment requirement.
332 ** gctSIZE_T BankSize
333 ** Number of bytes per physical memory bank. Used by bank
338 ** gckVIDMEM * Memory
339 ** Pointer to a variable that will hold the pointer to the gckVIDMEM
345 IN gctUINT32 BaseAddress,
347 IN gctSIZE_T Threshold,
348 IN gctSIZE_T BankSize,
349 OUT gckVIDMEM * Memory
352 gckVIDMEM memory = gcvNULL;
354 gcuVIDMEM_NODE_PTR node;
356 gctPOINTER pointer = gcvNULL;
360 gcmkHEADER_ARG("Os=0x%x BaseAddress=%08x Bytes=%lu Threshold=%lu "
362 Os, BaseAddress, Bytes, Threshold, BankSize);
364 /* Verify the arguments. */
365 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
366 gcmkVERIFY_ARGUMENT(Bytes > 0);
367 gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
369 gcmkSAFECASTSIZET(heapBytes, Bytes);
370 gcmkSAFECASTSIZET(bankSize, BankSize);
372 /* Allocate the gckVIDMEM object. */
373 gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(struct _gckVIDMEM), &pointer));
377 /* Initialize the gckVIDMEM object. */
378 memory->object.type = gcvOBJ_VIDMEM;
381 /* Set video memory heap information. */
382 memory->baseAddress = BaseAddress;
383 memory->bytes = heapBytes;
384 memory->freeBytes = heapBytes;
385 memory->threshold = Threshold;
386 memory->mutex = gcvNULL;
390 /* Walk all possible banks. */
391 for (i = 0; i < gcmCOUNTOF(memory->sentinel); ++i)
397 /* Use all bytes for the first bank. */
402 /* Compute number of bytes for this bank. */
403 bytes = gcmALIGN(BaseAddress + 1, bankSize) - BaseAddress;
405 if (bytes > heapBytes)
407 /* Make sure we don't exceed the total number of bytes. */
414 /* Mark heap is not used. */
415 memory->sentinel[i].VidMem.next =
416 memory->sentinel[i].VidMem.prev =
417 memory->sentinel[i].VidMem.nextFree =
418 memory->sentinel[i].VidMem.prevFree = gcvNULL;
422 /* Allocate one gcuVIDMEM_NODE union. */
423 gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcuVIDMEM_NODE), &pointer));
427 /* Initialize gcuVIDMEM_NODE union. */
428 node->VidMem.memory = memory;
432 node->VidMem.nextFree =
433 node->VidMem.prevFree = &memory->sentinel[i];
435 node->VidMem.offset = BaseAddress;
436 node->VidMem.bytes = bytes;
437 node->VidMem.alignment = 0;
438 node->VidMem.physical = 0;
439 node->VidMem.pool = gcvPOOL_UNKNOWN;
441 node->VidMem.locked = 0;
444 node->VidMem.processID = 0;
445 node->VidMem.logical = gcvNULL;
449 node->VidMem.kernelVirtual = gcvNULL;
452 /* Initialize the linked list of nodes. */
453 memory->sentinel[i].VidMem.next =
454 memory->sentinel[i].VidMem.prev =
455 memory->sentinel[i].VidMem.nextFree =
456 memory->sentinel[i].VidMem.prevFree = node;
459 memory->sentinel[i].VidMem.bytes = 0;
461 /* Adjust address for next bank. */
462 BaseAddress += bytes;
467 /* Assign all the bank mappings. */
468 memory->mapping[gcvSURF_RENDER_TARGET] = banks - 1;
469 memory->mapping[gcvSURF_BITMAP] = banks - 1;
470 if (banks > 1) --banks;
471 memory->mapping[gcvSURF_DEPTH] = banks - 1;
472 memory->mapping[gcvSURF_HIERARCHICAL_DEPTH] = banks - 1;
473 if (banks > 1) --banks;
474 memory->mapping[gcvSURF_TEXTURE] = banks - 1;
475 if (banks > 1) --banks;
476 memory->mapping[gcvSURF_VERTEX] = banks - 1;
477 if (banks > 1) --banks;
478 memory->mapping[gcvSURF_INDEX] = banks - 1;
479 if (banks > 1) --banks;
480 memory->mapping[gcvSURF_TILE_STATUS] = banks - 1;
481 if (banks > 1) --banks;
482 memory->mapping[gcvSURF_TYPE_UNKNOWN] = 0;
485 memory->mapping[gcvSURF_IMAGE] = 0;
486 memory->mapping[gcvSURF_MASK] = 0;
487 memory->mapping[gcvSURF_SCISSOR] = 0;
490 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
491 "[GALCORE] INDEX: bank %d",
492 memory->mapping[gcvSURF_INDEX]);
493 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
494 "[GALCORE] VERTEX: bank %d",
495 memory->mapping[gcvSURF_VERTEX]);
496 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
497 "[GALCORE] TEXTURE: bank %d",
498 memory->mapping[gcvSURF_TEXTURE]);
499 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
500 "[GALCORE] RENDER_TARGET: bank %d",
501 memory->mapping[gcvSURF_RENDER_TARGET]);
502 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
503 "[GALCORE] DEPTH: bank %d",
504 memory->mapping[gcvSURF_DEPTH]);
505 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
506 "[GALCORE] TILE_STATUS: bank %d",
507 memory->mapping[gcvSURF_TILE_STATUS]);
509 /* Allocate the mutex. */
510 gcmkONERROR(gckOS_CreateMutex(Os, &memory->mutex));
512 /* Return pointer to the gckVIDMEM object. */
516 gcmkFOOTER_ARG("*Memory=0x%x", *Memory);
521 if (memory != gcvNULL)
523 if (memory->mutex != gcvNULL)
525 /* Delete the mutex. */
526 gcmkVERIFY_OK(gckOS_DeleteMutex(Os, memory->mutex));
529 for (i = 0; i < banks; ++i)
532 gcmkASSERT(memory->sentinel[i].VidMem.next != gcvNULL);
533 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, memory->sentinel[i].VidMem.next));
536 /* Free the object. */
537 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, memory));
540 /* Return the status. */
545 /*******************************************************************************
549 ** Destroy an gckVIDMEM object.
554 ** Pointer to an gckVIDMEM object to destroy.
565 gcuVIDMEM_NODE_PTR node, next;
568 gcmkHEADER_ARG("Memory=0x%x", Memory);
570 /* Verify the arguments. */
571 gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM);
573 /* Walk all sentinels. */
574 for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i)
576 /* Bail out of the heap is not used. */
577 if (Memory->sentinel[i].VidMem.next == gcvNULL)
582 /* Walk all the nodes until we reach the sentinel. */
583 for (node = Memory->sentinel[i].VidMem.next;
584 node->VidMem.bytes != 0;
587 /* Save pointer to the next node. */
588 next = node->VidMem.next;
591 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Memory->os, node));
595 /* Free the mutex. */
596 gcmkVERIFY_OK(gckOS_DeleteMutex(Memory->os, Memory->mutex));
598 /* Mark the object as unknown. */
599 Memory->object.type = gcvOBJ_UNKNOWN;
601 /* Free the gckVIDMEM object. */
602 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Memory->os, Memory));
609 #if gcdENABLE_BANK_ALIGNMENT
611 #if !gcdBANK_BIT_START
612 #error gcdBANK_BIT_START not defined.
616 #error gcdBANK_BIT_END not defined.
618 /*******************************************************************************
619 ** _GetSurfaceBankAlignment
621 ** Return the required offset alignment required to the make BaseAddress
627 ** Pointer to gcoOS object.
630 ** Type of allocation.
632 ** gctUINT32 BaseAddress
633 ** Base address of current video memory node.
637 ** gctUINT32_PTR AlignmentOffset
638 ** Pointer to a variable that will hold the number of bytes to skip in
639 ** the current video memory node in order to make the alignment bank
643 _GetSurfaceBankAlignment(
645 IN gceSURF_TYPE Type,
646 IN gctUINT32 BaseAddress,
647 OUT gctUINT32_PTR AlignmentOffset
651 /* To retrieve the bank. */
652 static const gctUINT32 bankMask = (0xFFFFFFFF << gcdBANK_BIT_START)
653 ^ (0xFFFFFFFF << (gcdBANK_BIT_END + 1));
655 /* To retrieve the bank and all the lower bytes. */
656 static const gctUINT32 byteMask = ~(0xFFFFFFFF << (gcdBANK_BIT_END + 1));
658 gcmkHEADER_ARG("Type=%d BaseAddress=0x%x ", Type, BaseAddress);
660 /* Verify the arguments. */
661 gcmkVERIFY_ARGUMENT(AlignmentOffset != gcvNULL);
665 case gcvSURF_RENDER_TARGET:
666 bank = (BaseAddress & bankMask) >> (gcdBANK_BIT_START);
668 /* Align to the first bank. */
669 *AlignmentOffset = (bank == 0) ?
671 ((1 << (gcdBANK_BIT_END + 1)) + 0) - (BaseAddress & byteMask);
675 bank = (BaseAddress & bankMask) >> (gcdBANK_BIT_START);
677 /* Align to the third bank. */
678 *AlignmentOffset = (bank == 2) ?
680 ((1 << (gcdBANK_BIT_END + 1)) + (2 << gcdBANK_BIT_START)) - (BaseAddress & byteMask);
682 /* Minimum 256 byte alignment needed for fast_msaa. */
683 if ((gcdBANK_CHANNEL_BIT > 7) ||
684 ((gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_FAST_MSAA) != gcvSTATUS_TRUE) &&
685 (gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_SMALL_MSAA) != gcvSTATUS_TRUE)))
687 /* Add a channel offset at the channel bit. */
688 *AlignmentOffset += (1 << gcdBANK_CHANNEL_BIT);
693 /* no alignment needed. */
694 *AlignmentOffset = 0;
697 /* Return the status. */
698 gcmkFOOTER_ARG("*AlignmentOffset=%u", *AlignmentOffset);
703 static gcuVIDMEM_NODE_PTR
709 IN gceSURF_TYPE Type,
710 IN OUT gctUINT32_PTR Alignment
713 gcuVIDMEM_NODE_PTR node;
716 #if gcdENABLE_BANK_ALIGNMENT
717 gctUINT32 bankAlignment;
721 if (Memory->sentinel[Bank].VidMem.nextFree == gcvNULL)
723 /* No free nodes left. */
727 #if gcdENABLE_BANK_ALIGNMENT
728 /* Walk all free nodes until we have one that is big enough or we have
729 ** reached the sentinel. */
730 for (node = Memory->sentinel[Bank].VidMem.nextFree;
731 node->VidMem.bytes != 0;
732 node = node->VidMem.nextFree)
734 if (node->VidMem.bytes < Bytes)
739 gcmkONERROR(_GetSurfaceBankAlignment(
742 node->VidMem.memory->baseAddress + node->VidMem.offset,
745 bankAlignment = gcmALIGN(bankAlignment, *Alignment);
747 /* Compute number of bytes to skip for alignment. */
748 alignment = (*Alignment == 0)
750 : (*Alignment - (node->VidMem.offset % *Alignment));
752 if (alignment == *Alignment)
754 /* Node is already aligned. */
758 if (node->VidMem.bytes >= Bytes + alignment + bankAlignment)
760 /* This node is big enough. */
761 *Alignment = alignment + bankAlignment;
767 /* Walk all free nodes until we have one that is big enough or we have
768 reached the sentinel. */
769 for (node = Memory->sentinel[Bank].VidMem.nextFree;
770 node->VidMem.bytes != 0;
771 node = node->VidMem.nextFree)
777 gcmkSAFECASTSIZET(offset, node->VidMem.offset);
779 modulo = gckMATH_ModuloInt(offset, *Alignment);
781 /* Compute number of bytes to skip for alignment. */
782 alignment = (*Alignment == 0) ? 0 : (*Alignment - modulo);
784 if (alignment == *Alignment)
786 /* Node is already aligned. */
790 if (node->VidMem.bytes >= Bytes + alignment)
792 /* This node is big enough. */
793 *Alignment = alignment;
798 #if gcdENABLE_BANK_ALIGNMENT
801 /* Not enough memory. */
805 /*******************************************************************************
807 ** gckVIDMEM_AllocateLinear
809 ** Allocate linear memory from the gckVIDMEM object.
814 ** Pointer to an gckVIDMEM object.
817 ** Number of bytes to allocate.
819 ** gctUINT32 Alignment
820 ** Byte alignment for allocation.
823 ** Type of surface to allocate (use by bank optimization).
826 ** If user must use this pool, it should set Specified to gcvTRUE,
827 ** otherwise allocator may reserve some memory for other usage, such
828 ** as small block size allocation request.
832 ** gcuVIDMEM_NODE_PTR * Node
833 ** Pointer to a variable that will hold the allocated memory node.
836 gckVIDMEM_AllocateLinear(
840 IN gctUINT32 Alignment,
841 IN gceSURF_TYPE Type,
842 IN gctBOOL Specified,
843 OUT gcuVIDMEM_NODE_PTR * Node
847 gcuVIDMEM_NODE_PTR node;
850 gctBOOL acquired = gcvFALSE;
852 gcmkHEADER_ARG("Memory=0x%x Bytes=%lu Alignment=%u Type=%d",
853 Memory, Bytes, Alignment, Type);
855 /* Verify the arguments. */
856 gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM);
857 gcmkVERIFY_ARGUMENT(Bytes > 0);
858 gcmkVERIFY_ARGUMENT(Node != gcvNULL);
859 gcmkVERIFY_ARGUMENT(Type < gcvSURF_NUM_TYPES);
861 /* Acquire the mutex. */
862 gcmkONERROR(gckOS_AcquireMutex(Memory->os, Memory->mutex, gcvINFINITE));
866 if (Bytes > Memory->freeBytes)
868 /* Not enough memory. */
869 status = gcvSTATUS_OUT_OF_MEMORY;
873 #if gcdSMALL_BLOCK_SIZE
874 if ((Memory->freeBytes < (Memory->bytes/gcdRATIO_FOR_SMALL_MEMORY))
875 && (Bytes >= gcdSMALL_BLOCK_SIZE)
876 && (Specified == gcvFALSE)
879 /* The left memory is for small memory.*/
880 status = gcvSTATUS_OUT_OF_MEMORY;
885 /* Find the default bank for this surface type. */
886 gcmkASSERT((gctINT) Type < gcmCOUNTOF(Memory->mapping));
887 bank = Memory->mapping[Type];
888 alignment = Alignment;
890 /* Find a free node in the default bank. */
891 node = _FindNode(Kernel, Memory, bank, Bytes, Type, &alignment);
896 /* Walk all lower banks. */
897 for (i = bank - 1; i >= 0; --i)
899 /* Find a free node inside the current bank. */
900 node = _FindNode(Kernel, Memory, i, Bytes, Type, &alignment);
910 /* Walk all upper banks. */
911 for (i = bank + 1; i < gcmCOUNTOF(Memory->sentinel); ++i)
913 if (Memory->sentinel[i].VidMem.nextFree == gcvNULL)
915 /* Abort when we reach unused banks. */
919 /* Find a free node inside the current bank. */
920 node = _FindNode(Kernel, Memory, i, Bytes, Type, &alignment);
931 status = gcvSTATUS_OUT_OF_MEMORY;
935 /* Do we have an alignment? */
938 /* Split the node so it is aligned. */
939 if (_Split(Memory->os, node, alignment))
941 /* Successful split, move to aligned node. */
942 node = node->VidMem.next;
944 /* Remove alignment. */
949 /* Do we have enough memory after the allocation to split it? */
950 if (node->VidMem.bytes - Bytes > Memory->threshold)
952 /* Adjust the node size. */
953 _Split(Memory->os, node, Bytes);
956 /* Remove the node from the free list. */
957 node->VidMem.prevFree->VidMem.nextFree = node->VidMem.nextFree;
958 node->VidMem.nextFree->VidMem.prevFree = node->VidMem.prevFree;
959 node->VidMem.nextFree =
960 node->VidMem.prevFree = gcvNULL;
962 /* Fill in the information. */
963 node->VidMem.alignment = alignment;
964 node->VidMem.memory = Memory;
966 node->VidMem.logical = gcvNULL;
967 gcmkONERROR(gckOS_GetProcessID(&node->VidMem.processID));
970 /* Adjust the number of free bytes. */
971 Memory->freeBytes -= node->VidMem.bytes;
974 node->VidMem.kernelVirtual = gcvNULL;
977 /* Release the mutex. */
978 gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex));
980 /* Return the pointer to the node. */
983 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
984 "Allocated %u bytes @ 0x%x [0x%08X]",
985 node->VidMem.bytes, node, node->VidMem.offset);
988 gcmkFOOTER_ARG("*Node=0x%x", *Node);
994 /* Release the mutex. */
995 gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex));
998 /* Return the status. */
1003 /*******************************************************************************
1007 ** Free an allocated video memory node.
1012 ** Pointer to an gckKERNEL object.
1014 ** gcuVIDMEM_NODE_PTR Node
1015 ** Pointer to a gcuVIDMEM_NODE object.
1023 IN gckKERNEL Kernel,
1024 IN gcuVIDMEM_NODE_PTR Node
1028 gckKERNEL kernel = gcvNULL;
1029 gckVIDMEM memory = gcvNULL;
1030 gcuVIDMEM_NODE_PTR node;
1031 gctBOOL mutexAcquired = gcvFALSE;
1033 gcmkHEADER_ARG("Node=0x%x", Node);
1035 /* Verify the arguments. */
1036 if ((Node == gcvNULL)
1037 || (Node->VidMem.memory == gcvNULL)
1040 /* Invalid object. */
1041 gcmkONERROR(gcvSTATUS_INVALID_OBJECT);
1044 /**************************** Video Memory ********************************/
1046 if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
1048 /* Extract pointer to gckVIDMEM object owning the node. */
1049 memory = Node->VidMem.memory;
1051 /* Acquire the mutex. */
1053 gckOS_AcquireMutex(memory->os, memory->mutex, gcvINFINITE));
1055 mutexAcquired = gcvTRUE;
1058 /* Unmap the video memory. */
1059 if (Node->VidMem.logical != gcvNULL)
1061 gckKERNEL_UnmapVideoMemory(
1063 Node->VidMem.logical,
1064 Node->VidMem.processID,
1065 Node->VidMem.bytes);
1066 Node->VidMem.logical = gcvNULL;
1070 Node->VidMem.processID = 0;
1072 /* Don't try to re-free an already freed node. */
1073 if ((Node->VidMem.nextFree == gcvNULL)
1074 && (Node->VidMem.prevFree == gcvNULL)
1079 if (Node->VidMem.kernelVirtual)
1081 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1082 "%s(%d) Unmap %x from kernel space.",
1083 __FUNCTION__, __LINE__,
1084 Node->VidMem.kernelVirtual);
1087 gckOS_UnmapPhysical(memory->os,
1088 Node->VidMem.kernelVirtual,
1089 Node->VidMem.bytes));
1091 Node->VidMem.kernelVirtual = gcvNULL;
1095 /* Check if Node is already freed. */
1096 if (Node->VidMem.nextFree)
1098 /* Node is alread freed. */
1099 gcmkONERROR(gcvSTATUS_INVALID_DATA);
1102 /* Update the number of free bytes. */
1103 memory->freeBytes += Node->VidMem.bytes;
1105 /* Find the next free node. */
1106 for (node = Node->VidMem.next;
1107 node != gcvNULL && node->VidMem.nextFree == gcvNULL;
1108 node = node->VidMem.next) ;
1110 /* Insert this node in the free list. */
1111 Node->VidMem.nextFree = node;
1112 Node->VidMem.prevFree = node->VidMem.prevFree;
1114 Node->VidMem.prevFree->VidMem.nextFree =
1115 node->VidMem.prevFree = Node;
1117 /* Is the next node a free node and not the sentinel? */
1118 if ((Node->VidMem.next == Node->VidMem.nextFree)
1119 && (Node->VidMem.next->VidMem.bytes != 0)
1122 /* Merge this node with the next node. */
1123 gcmkONERROR(_Merge(memory->os, node = Node));
1124 gcmkASSERT(node->VidMem.nextFree != node);
1125 gcmkASSERT(node->VidMem.prevFree != node);
1128 /* Is the previous node a free node and not the sentinel? */
1129 if ((Node->VidMem.prev == Node->VidMem.prevFree)
1130 && (Node->VidMem.prev->VidMem.bytes != 0)
1133 /* Merge this node with the previous node. */
1134 gcmkONERROR(_Merge(memory->os, node = Node->VidMem.prev));
1135 gcmkASSERT(node->VidMem.nextFree != node);
1136 gcmkASSERT(node->VidMem.prevFree != node);
1140 /* Release the mutex. */
1141 gcmkVERIFY_OK(gckOS_ReleaseMutex(memory->os, memory->mutex));
1143 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1144 "Node 0x%x is freed.",
1149 return gcvSTATUS_OK;
1152 /*************************** Virtual Memory *******************************/
1154 /* Get gckKERNEL object. */
1155 kernel = Node->Virtual.kernel;
1157 /* Verify the gckKERNEL object pointer. */
1158 gcmkVERIFY_OBJECT(kernel, gcvOBJ_KERNEL);
1161 if (Node->Virtual.kernelVirtual)
1163 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1164 "%s(%d) Unmap %x from kernel space.",
1165 __FUNCTION__, __LINE__,
1166 Node->Virtual.kernelVirtual);
1169 gckOS_UnmapPhysical(kernel->os,
1170 Node->Virtual.kernelVirtual,
1171 Node->Virtual.bytes));
1173 Node->Virtual.kernelVirtual = gcvNULL;
1177 /* Free the virtual memory. */
1178 gcmkVERIFY_OK(gckOS_FreePagedMemory(kernel->os,
1179 Node->Virtual.physical,
1180 Node->Virtual.bytes));
1182 /* Destroy the gcuVIDMEM_NODE union. */
1183 gcmkVERIFY_OK(gckVIDMEM_DestroyVirtual(Node));
1187 return gcvSTATUS_OK;
1192 /* Release the mutex. */
1193 gcmkVERIFY_OK(gckOS_ReleaseMutex(
1194 memory->os, memory->mutex
1198 /* Return the status. */
1203 #if !gcdPROCESS_ADDRESS_SPACE
1204 /*******************************************************************************
1206 ** _NeedVirtualMapping
1208 ** Whether setup GPU page table for video node.
1212 ** Pointer to an gckKERNEL object.
1214 ** gcuVIDMEM_NODE_PTR Node
1215 ** Pointer to a gcuVIDMEM_NODE union.
1218 ** Id of current GPU.
1221 ** gctBOOL * NeedMapping
1222 ** A pointer hold the result whether Node should be mapping.
1225 _NeedVirtualMapping(
1226 IN gckKERNEL Kernel,
1228 IN gcuVIDMEM_NODE_PTR Node,
1229 OUT gctBOOL * NeedMapping
1237 gctUINT32 baseAddress;
1240 gcmkHEADER_ARG("Node=0x%X", Node);
1242 /* Verify the arguments. */
1243 gcmkVERIFY_ARGUMENT(Kernel != gcvNULL);
1244 gcmkVERIFY_ARGUMENT(Node != gcvNULL);
1245 gcmkVERIFY_ARGUMENT(NeedMapping != gcvNULL);
1246 gcmkVERIFY_ARGUMENT(Core < gcdMAX_GPU_COUNT);
1248 if (Node->Virtual.contiguous)
1251 if (Core == gcvCORE_VG)
1253 *NeedMapping = gcvFALSE;
1258 /* Convert logical address into a physical address. */
1259 gcmkONERROR(gckOS_UserLogicalToPhysical(
1260 Kernel->os, Node->Virtual.logical, &phys
1263 gcmkONERROR(gckOS_GetBaseAddress(Kernel->os, &baseAddress));
1265 gcmkASSERT(phys >= baseAddress);
1267 /* Subtract baseAddress to get a GPU address used for programming. */
1268 phys -= baseAddress;
1270 /* If part of region is belong to gcvPOOL_VIRTUAL,
1271 ** whole region has to be mapped. */
1272 gcmkSAFECASTSIZET(bytes, Node->Virtual.bytes);
1273 end = phys + bytes - 1;
1275 gcmkONERROR(gckHARDWARE_SplitMemory(
1276 Kernel->hardware, end, &pool, &offset
1279 *NeedMapping = (pool == gcvPOOL_VIRTUAL);
1284 *NeedMapping = gcvTRUE;
1287 gcmkFOOTER_ARG("*NeedMapping=%d", *NeedMapping);
1288 return gcvSTATUS_OK;
1296 #if gcdPROCESS_ADDRESS_SPACE
1299 IN gcsGPU_MAP_PTR Head,
1303 gcsGPU_MAP_PTR map = Head;
1307 if (map->pid == ProcessID)
1321 IN gcsGPU_MAP_PTR *Head,
1322 IN gcsGPU_MAP_PTR *Tail,
1326 gcsGPU_MAP_PTR gpuMap;
1327 gctPOINTER pointer = gcvNULL;
1329 gckOS_Allocate(Os, sizeof(gcsGPU_MAP), &pointer);
1331 if (pointer == gcvNULL)
1338 gckOS_ZeroMemory(pointer, sizeof(gcsGPU_MAP));
1340 gpuMap->pid = ProcessID;
1344 *Head = *Tail = gpuMap;
1348 gpuMap->prev = *Tail;
1349 (*Tail)->next = gpuMap;
1359 IN gcsGPU_MAP_PTR *Head,
1360 IN gcsGPU_MAP_PTR *Tail,
1361 IN gcsGPU_MAP_PTR gpuMap
1365 if (gpuMap == *Head)
1367 if ((*Head = gpuMap->next) == gcvNULL)
1374 gpuMap->prev->next = gpuMap->next;
1375 if (gpuMap == *Tail)
1377 *Tail = gpuMap->prev;
1381 gpuMap->next->prev = gpuMap->prev;
1385 gcmkOS_SAFE_FREE(Os, gpuMap);
1389 /*******************************************************************************
1393 ** Lock a video memory node and return its hardware specific address.
1398 ** Pointer to an gckKERNEL object.
1400 ** gcuVIDMEM_NODE_PTR Node
1401 ** Pointer to a gcuVIDMEM_NODE union.
1405 ** gctUINT32 * Address
1406 ** Pointer to a variable that will hold the hardware specific address.
1408 ** gctUINT32 * PhysicalAddress
1409 ** Pointer to a variable that will hold the bus address of a contiguous
1414 IN gckKERNEL Kernel,
1415 IN gckVIDMEM_NODE Node,
1416 IN gctBOOL Cacheable,
1417 OUT gctUINT32 * Address,
1418 OUT gctUINT32 * Gid,
1419 OUT gctUINT64 * PhysicalAddress
1423 gctBOOL acquired = gcvFALSE;
1424 gctBOOL locked = gcvFALSE;
1426 #if !gcdPROCESS_ADDRESS_SPACE
1427 gctBOOL needMapping = gcvFALSE;
1429 gctUINT32 baseAddress;
1430 gctUINT32 physicalAddress;
1431 gcuVIDMEM_NODE_PTR node = Node->node;
1433 gcmkHEADER_ARG("Node=0x%x", Node);
1435 /* Verify the arguments. */
1436 gcmkVERIFY_ARGUMENT(Address != gcvNULL);
1437 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1439 /* Extract the gckOS object pointer. */
1441 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
1443 if ((node == gcvNULL)
1444 || (node->VidMem.memory == gcvNULL)
1447 /* Invalid object. */
1448 gcmkONERROR(gcvSTATUS_INVALID_OBJECT);
1451 /* Grab the mutex. */
1452 gcmkONERROR(gckOS_AcquireMutex(os, Node->mutex, gcvINFINITE));
1455 /**************************** Video Memory ********************************/
1457 if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
1461 if (Cacheable == gcvTRUE)
1463 gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
1466 /* Increment the lock count. */
1467 node->VidMem.locked ++;
1469 /* Return the physical address of the node. */
1470 gcmkSAFECASTSIZET(offset, node->VidMem.offset);
1472 *Address = node->VidMem.memory->baseAddress
1474 + node->VidMem.alignment;
1476 physicalAddress = *Address;
1478 /* Get hardware specific address. */
1480 if (Kernel->vg == gcvNULL)
1483 if (Kernel->hardware->mmuVersion == 0)
1485 /* Convert physical to GPU address for old mmu. */
1486 gcmkONERROR(gckOS_GetBaseAddress(Kernel->os, &baseAddress));
1487 gcmkASSERT(*Address > baseAddress);
1488 *Address -= baseAddress;
1492 gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(
1498 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1499 "Locked node 0x%x (%d) @ 0x%08X",
1501 node->VidMem.locked,
1505 /*************************** Virtual Memory *******************************/
1510 *Gid = node->Virtual.gid;
1512 #if gcdPAGED_MEMORY_CACHEABLE
1513 /* Force video memory cacheable. */
1514 Cacheable = gcvTRUE;
1519 node->Virtual.physical,
1520 node->Virtual.bytes,
1522 &node->Virtual.logical,
1523 &node->Virtual.pageCount));
1525 gcmkONERROR(gckOS_GetPhysicalAddress(
1527 node->Virtual.logical,
1532 node->Virtual.physicalAddress = physicalAddress;
1535 #if !gcdPROCESS_ADDRESS_SPACE
1536 /* Increment the lock count. */
1537 if (node->Virtual.lockeds[Kernel->core] ++ == 0)
1541 gcmkONERROR(_NeedVirtualMapping(Kernel, Kernel->core, node, &needMapping));
1543 if (needMapping == gcvFALSE)
1545 /* Get hardware specific address. */
1547 if (Kernel->vg != gcvNULL)
1549 gcmkONERROR(gckVGHARDWARE_ConvertLogical(
1550 Kernel->vg->hardware,
1551 node->Virtual.logical,
1553 &node->Virtual.addresses[Kernel->core]));
1558 gcmkONERROR(gckHARDWARE_ConvertLogical(
1560 node->Virtual.logical,
1562 &node->Virtual.addresses[Kernel->core]));
1568 gctPHYS_ADDR physicalArrayPhysical;
1569 gctPOINTER physicalArrayLogical;
1571 gcmkONERROR(gckOS_AllocatePageArray(
1573 node->Virtual.physical,
1574 node->Virtual.pageCount,
1575 &physicalArrayLogical,
1576 &physicalArrayPhysical
1579 gcmkONERROR(gckKERNEL_SecurityMapMemory(
1581 physicalArrayLogical,
1582 node->Virtual.pageCount,
1583 &node->Virtual.addresses[Kernel->core]
1586 gcmkONERROR(gckOS_FreeNonPagedMemory(
1589 physicalArrayPhysical,
1590 physicalArrayLogical
1594 if (Kernel->vg != gcvNULL)
1596 /* Allocate pages inside the MMU. */
1598 gckVGMMU_AllocatePages(Kernel->vg->mmu,
1599 node->Virtual.pageCount,
1600 &node->Virtual.pageTables[Kernel->core],
1601 &node->Virtual.addresses[Kernel->core]));
1606 /* Allocate pages inside the MMU. */
1608 gckMMU_AllocatePagesEx(Kernel->mmu,
1609 node->Virtual.pageCount,
1611 &node->Virtual.pageTables[Kernel->core],
1612 &node->Virtual.addresses[Kernel->core]));
1615 node->Virtual.lockKernels[Kernel->core] = Kernel;
1617 /* Map the pages. */
1619 gckOS_MapPagesEx(os,
1621 node->Virtual.physical,
1622 node->Virtual.pageCount,
1623 node->Virtual.addresses[Kernel->core],
1624 node->Virtual.pageTables[Kernel->core]));
1627 if (Kernel->core == gcvCORE_VG)
1629 gcmkONERROR(gckVGMMU_Flush(Kernel->vg->mmu));
1634 gcmkONERROR(gckMMU_Flush(Kernel->mmu, node->Virtual.type));
1638 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1639 "Mapped virtual node 0x%x to 0x%08X",
1641 node->Virtual.addresses[Kernel->core]);
1644 /* Return hardware address. */
1645 *Address = node->Virtual.addresses[Kernel->core];
1649 /* Release the mutex. */
1650 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mutex));
1652 *PhysicalAddress = (gctUINT64)physicalAddress;
1655 gcmkFOOTER_ARG("*Address=%08x", *Address);
1656 return gcvSTATUS_OK;
1661 if (node->Virtual.pageTables[Kernel->core] != gcvNULL)
1664 if (Kernel->vg != gcvNULL)
1666 /* Free the pages from the MMU. */
1668 gckVGMMU_FreePages(Kernel->vg->mmu,
1669 node->Virtual.pageTables[Kernel->core],
1670 node->Virtual.pageCount));
1675 /* Free the pages from the MMU. */
1677 gckMMU_FreePages(Kernel->mmu,
1678 node->Virtual.pageTables[Kernel->core],
1679 node->Virtual.pageCount));
1681 node->Virtual.pageTables[Kernel->core] = gcvNULL;
1682 node->Virtual.lockKernels[Kernel->core] = gcvNULL;
1685 /* Unlock the pages. */
1687 gckOS_UnlockPages(os,
1688 node->Virtual.physical,
1689 node->Virtual.bytes,
1690 node->Virtual.logical
1693 node->Virtual.lockeds[Kernel->core]--;
1698 /* Release the mutex. */
1699 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mutex));
1702 /* Return the status. */
1707 /*******************************************************************************
1711 ** Unlock a video memory node.
1716 ** Pointer to an gckKERNEL object.
1718 ** gcuVIDMEM_NODE_PTR Node
1719 ** Pointer to a locked gcuVIDMEM_NODE union.
1721 ** gceSURF_TYPE Type
1722 ** Type of surface to unlock.
1724 ** gctBOOL * Asynchroneous
1725 ** Pointer to a variable specifying whether the surface should be
1726 ** unlocked asynchroneously or not.
1730 ** gctBOOL * Asynchroneous
1731 ** Pointer to a variable receiving the number of bytes used in the
1732 ** command buffer specified by 'Commands'. If gcvNULL, there is no
1737 IN gckKERNEL Kernel,
1738 IN gckVIDMEM_NODE Node,
1739 IN gceSURF_TYPE Type,
1740 IN OUT gctBOOL * Asynchroneous
1745 gctBOOL acquired = gcvFALSE;
1746 gcuVIDMEM_NODE_PTR node = Node->node;
1748 gcmkHEADER_ARG("Node=0x%x Type=%d *Asynchroneous=%d",
1749 Node, Type, gcmOPT_VALUE(Asynchroneous));
1751 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1753 /* Get the gckOS object pointer. */
1755 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
1757 /* Verify the arguments. */
1758 if ((node == gcvNULL)
1759 || (node->VidMem.memory == gcvNULL)
1762 /* Invalid object. */
1763 gcmkONERROR(gcvSTATUS_INVALID_OBJECT);
1766 /* Grab the mutex. */
1767 gcmkONERROR(gckOS_AcquireMutex(os, Node->mutex, gcvINFINITE));
1770 /**************************** Video Memory ********************************/
1772 if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
1774 if (node->VidMem.locked <= 0)
1776 /* The surface was not locked. */
1777 status = gcvSTATUS_MEMORY_UNLOCKED;
1781 if (Asynchroneous != gcvNULL)
1783 /* Schedule an event to sync with GPU. */
1784 *Asynchroneous = gcvTRUE;
1788 /* Decrement the lock count. */
1789 node->VidMem.locked --;
1792 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1793 "Unlocked node 0x%x (%d)",
1795 node->VidMem.locked);
1798 /*************************** Virtual Memory *******************************/
1804 if (Asynchroneous == gcvNULL)
1806 #if !gcdPROCESS_ADDRESS_SPACE
1807 if (node->Virtual.lockeds[Kernel->core] == 0)
1809 status = gcvSTATUS_MEMORY_UNLOCKED;
1813 /* Decrement lock count. */
1814 -- node->Virtual.lockeds[Kernel->core];
1816 /* See if we can unlock the resources. */
1817 if (node->Virtual.lockeds[Kernel->core] == 0)
1820 if (node->Virtual.addresses[Kernel->core] > 0x80000000)
1822 gcmkONERROR(gckKERNEL_SecurityUnmapMemory(
1824 node->Virtual.addresses[Kernel->core],
1825 node->Virtual.pageCount
1829 /* Free the page table. */
1830 if (node->Virtual.pageTables[Kernel->core] != gcvNULL)
1833 if (Kernel->vg != gcvNULL)
1836 gckVGMMU_FreePages(Kernel->vg->mmu,
1837 node->Virtual.pageTables[Kernel->core],
1838 node->Virtual.pageCount));
1844 gckMMU_FreePages(Kernel->mmu,
1845 node->Virtual.pageTables[Kernel->core],
1846 node->Virtual.pageCount));
1849 gcmkONERROR(gckOS_UnmapPages(
1851 node->Virtual.pageCount,
1852 node->Virtual.addresses[Kernel->core]
1855 /* Mark page table as freed. */
1856 node->Virtual.pageTables[Kernel->core] = gcvNULL;
1857 node->Virtual.lockKernels[Kernel->core] = gcvNULL;
1862 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1863 "Unmapped virtual node 0x%x from 0x%08X",
1864 node, node->Virtual.addresses[Kernel->core]);
1872 gckOS_UnlockPages(os,
1873 node->Virtual.physical,
1874 node->Virtual.bytes,
1875 node->Virtual.logical));
1877 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1878 "Scheduled unlock for virtual node 0x%x",
1881 /* Schedule the surface to be unlocked. */
1882 *Asynchroneous = gcvTRUE;
1886 /* Release the mutex. */
1887 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mutex));
1888 acquired = gcvFALSE;
1891 gcmkFOOTER_ARG("*Asynchroneous=%d", gcmOPT_VALUE(Asynchroneous));
1892 return gcvSTATUS_OK;
1897 /* Release the mutex. */
1898 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mutex));
1901 /* Return the status. */
1906 #if gcdPROCESS_ADDRESS_SPACE
1908 gckVIDMEM_Node_Lock(
1909 IN gckKERNEL Kernel,
1910 IN gckVIDMEM_NODE Node,
1911 OUT gctUINT32 *Address
1916 gcuVIDMEM_NODE_PTR node = Node->node;
1917 gcsGPU_MAP_PTR gpuMap;
1918 gctPHYS_ADDR physical = gcvNULL;
1919 gctUINT32 phys = gcvINVALID_ADDRESS;
1920 gctUINT32 processID;
1921 gcsLOCK_INFO_PTR lockInfo;
1922 gctUINT32 pageCount;
1925 gctUINT32_PTR pageTableEntry;
1926 gctUINT32 offset = 0;
1927 gctBOOL acquired = gcvFALSE;
1929 gcmkHEADER_ARG("Node = %x", Node);
1931 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1932 gcmkVERIFY_ARGUMENT(Node != gcvNULL);
1933 gcmkVERIFY_ARGUMENT(Address != gcvNULL);
1936 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
1938 gcmkONERROR(gckOS_GetProcessID(&processID));
1940 gcmkONERROR(gckKERNEL_GetProcessMMU(Kernel, &mmu));
1942 gcmkONERROR(gckOS_AcquireMutex(os, Node->mapMutex, gcvINFINITE));
1945 /* Get map information for current process. */
1946 gpuMap = _FindGPUMap(Node->mapHead, processID);
1948 if (gpuMap == gcvNULL)
1950 gpuMap = _CreateGPUMap(os, &Node->mapHead, &Node->mapTail, processID);
1952 if (gpuMap == gcvNULL)
1954 gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
1958 lockInfo = &gpuMap->lockInfo;
1960 if (lockInfo->lockeds[Kernel->core] ++ == 0)
1962 /* Get necessary information. */
1963 if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
1965 phys = node->VidMem.memory->baseAddress
1966 + node->VidMem.offset
1967 + node->VidMem.alignment;
1969 /* GPU page table use 4K page. */
1970 pageCount = ((phys + node->VidMem.bytes + 4096 - 1) >> 12)
1973 offset = phys & 0xFFF;
1977 pageCount = node->Virtual.pageCount;
1978 physical = node->Virtual.physical;
1981 /* Allocate pages inside the MMU. */
1982 gcmkONERROR(gckMMU_AllocatePages(
1985 &lockInfo->pageTables[Kernel->core],
1986 &lockInfo->GPUAddresses[Kernel->core]));
1988 /* Record MMU from which pages are allocated. */
1989 lockInfo->lockMmus[Kernel->core] = mmu;
1991 pageTableEntry = lockInfo->pageTables[Kernel->core];
1993 /* Fill page table entries. */
1994 if (phys != gcvINVALID_ADDRESS)
1996 gctUINT32 address = lockInfo->GPUAddresses[Kernel->core];
1997 for (i = 0; i < pageCount; i++)
1999 gckMMU_GetPageEntry(mmu, address, &pageTableEntry);
2000 gckMMU_SetPage(mmu, phys & 0xFFFFF000, pageTableEntry);
2003 pageTableEntry += 1;
2008 gctUINT32 address = lockInfo->GPUAddresses[Kernel->core];
2009 gcmkASSERT(physical != gcvNULL);
2010 gcmkONERROR(gckOS_MapPagesEx(os,
2018 gcmkONERROR(gckMMU_Flush(mmu));
2021 *Address = lockInfo->GPUAddresses[Kernel->core] + offset;
2023 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mapMutex));
2024 acquired = gcvFALSE;
2028 return gcvSTATUS_OK;
2033 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mapMutex));
2041 gckVIDMEM_NODE_Unlock(
2042 IN gckKERNEL Kernel,
2043 IN gckVIDMEM_NODE Node,
2044 IN gctUINT32 ProcessID
2048 gcsGPU_MAP_PTR gpuMap;
2049 gcsLOCK_INFO_PTR lockInfo;
2051 gcuVIDMEM_NODE_PTR node;
2052 gctUINT32 pageCount;
2053 gctBOOL acquired = gcvFALSE;
2055 gcmkHEADER_ARG("Kernel=0x%08X, Node = %x, ProcessID=%d",
2056 Kernel, Node, ProcessID);
2058 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
2059 gcmkVERIFY_ARGUMENT(Node != gcvNULL);
2061 gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Node->mapMutex, gcvINFINITE));
2064 /* Get map information for current process. */
2065 gpuMap = _FindGPUMap(Node->mapHead, ProcessID);
2067 if (gpuMap == gcvNULL)
2069 /* No mapping for this process. */
2070 gcmkONERROR(gcvSTATUS_INVALID_DATA);
2073 lockInfo = &gpuMap->lockInfo;
2075 if (--lockInfo->lockeds[Kernel->core] == 0)
2079 /* Get necessary information. */
2080 if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
2082 gctUINT32 phys = node->VidMem.memory->baseAddress
2083 + node->VidMem.offset
2084 + node->VidMem.alignment;
2086 /* GPU page table use 4K page. */
2087 pageCount = ((phys + node->VidMem.bytes + 4096 - 1) >> 12)
2092 pageCount = node->Virtual.pageCount;
2095 /* Get MMU which allocates pages. */
2096 mmu = lockInfo->lockMmus[Kernel->core];
2098 /* Free virtual spaces in page table. */
2099 gcmkVERIFY_OK(gckMMU_FreePagesEx(
2101 lockInfo->GPUAddresses[Kernel->core],
2105 _DestroyGPUMap(Kernel->os, &Node->mapHead, &Node->mapTail, gpuMap);
2108 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Node->mapMutex));
2109 acquired = gcvFALSE;
2112 return gcvSTATUS_OK;
2117 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Node->mapMutex));
2125 /*******************************************************************************
2127 ** gckVIDMEM_HANDLE_Allocate
2129 ** Allocate a handle for a gckVIDMEM_NODE object.
2134 ** Pointer to an gckKERNEL object.
2136 ** gckVIDMEM_NODE Node
2137 ** Pointer to a gckVIDMEM_NODE object.
2141 ** gctUINT32 * Handle
2142 ** Pointer to a variable receiving a handle represent this
2143 ** gckVIDMEM_NODE in userspace.
2146 gckVIDMEM_HANDLE_Allocate(
2147 IN gckKERNEL Kernel,
2148 IN gckVIDMEM_NODE Node,
2149 OUT gctUINT32 * Handle
2153 gctUINT32 processID = 0;
2154 gctPOINTER pointer = gcvNULL;
2155 gctPOINTER handleDatabase = gcvNULL;
2156 gctPOINTER mutex = gcvNULL;
2157 gctUINT32 handle = 0;
2158 gckVIDMEM_HANDLE handleObject = gcvNULL;
2159 gckOS os = Kernel->os;
2161 gcmkHEADER_ARG("Kernel=0x%X, Node=0x%X", Kernel, Node);
2163 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
2165 /* Allocate a gckVIDMEM_HANDLE object. */
2166 gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsVIDMEM_HANDLE), &pointer));
2168 gcmkVERIFY_OK(gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsVIDMEM_HANDLE)));
2170 handleObject = pointer;
2172 gcmkONERROR(gckOS_AtomConstruct(os, &handleObject->reference));
2174 /* Set default reference count to 1. */
2175 gckOS_AtomSet(os, handleObject->reference, 1);
2177 gcmkVERIFY_OK(gckOS_GetProcessID(&processID));
2180 gckKERNEL_FindHandleDatbase(Kernel,
2185 /* Allocate a handle for this object. */
2187 gckKERNEL_AllocateIntegerId(handleDatabase, handleObject, &handle));
2189 handleObject->node = Node;
2190 handleObject->handle = handle;
2194 gcmkFOOTER_ARG("*Handle=%d", *Handle);
2195 return gcvSTATUS_OK;
2198 if (handleObject != gcvNULL)
2200 if (handleObject->reference != gcvNULL)
2202 gcmkVERIFY_OK(gckOS_AtomDestroy(os, handleObject->reference));
2205 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, handleObject));
2213 gckVIDMEM_NODE_Reference(
2214 IN gckKERNEL Kernel,
2215 IN gckVIDMEM_NODE Node
2219 gcmkHEADER_ARG("Kernel=0x%X Node=0x%X", Kernel, Node);
2221 gckOS_AtomIncrement(Kernel->os, Node->reference, &oldValue);
2224 return gcvSTATUS_OK;
2228 gckVIDMEM_HANDLE_Reference(
2229 IN gckKERNEL Kernel,
2230 IN gctUINT32 ProcessID,
2235 gckVIDMEM_HANDLE handleObject = gcvNULL;
2236 gctPOINTER database = gcvNULL;
2237 gctPOINTER mutex = gcvNULL;
2238 gctINT32 oldValue = 0;
2239 gctBOOL acquired = gcvFALSE;
2241 gcmkHEADER_ARG("Handle=%d PrcoessID=%d", Handle, ProcessID);
2244 gckKERNEL_FindHandleDatbase(Kernel, ProcessID, &database, &mutex));
2246 gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
2249 /* Translate handle to gckVIDMEM_HANDLE object. */
2251 gckKERNEL_QueryIntegerId(database, Handle, (gctPOINTER *)&handleObject));
2253 /* Increase the reference count. */
2254 gckOS_AtomIncrement(Kernel->os, handleObject->reference, &oldValue);
2256 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
2257 acquired = gcvFALSE;
2260 return gcvSTATUS_OK;
2265 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
2273 gckVIDMEM_HANDLE_Dereference(
2274 IN gckKERNEL Kernel,
2275 IN gctUINT32 ProcessID,
2280 gctPOINTER handleDatabase = gcvNULL;
2281 gctPOINTER mutex = gcvNULL;
2282 gctINT32 oldValue = 0;
2283 gckVIDMEM_HANDLE handleObject = gcvNULL;
2284 gctBOOL acquired = gcvFALSE;
2286 gcmkHEADER_ARG("Handle=%d PrcoessID=%d", Handle, ProcessID);
2289 gckKERNEL_FindHandleDatbase(Kernel,
2294 gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
2297 /* Translate handle to gckVIDMEM_HANDLE. */
2299 gckKERNEL_QueryIntegerId(handleDatabase, Handle, (gctPOINTER *)&handleObject));
2301 gckOS_AtomDecrement(Kernel->os, handleObject->reference, &oldValue);
2305 /* Remove handle from database if this is the last reference. */
2306 gcmkVERIFY_OK(gckKERNEL_FreeIntegerId(handleDatabase, Handle));
2309 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
2310 acquired = gcvFALSE;
2314 gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, handleObject->reference));
2315 gcmkOS_SAFE_FREE(Kernel->os, handleObject);
2319 return gcvSTATUS_OK;
2324 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
2332 gckVIDMEM_HANDLE_LookupAndReference(
2333 IN gckKERNEL Kernel,
2334 IN gctUINT32 Handle,
2335 OUT gckVIDMEM_NODE * Node
2339 gckVIDMEM_HANDLE handleObject = gcvNULL;
2340 gckVIDMEM_NODE node = gcvNULL;
2341 gctPOINTER database = gcvNULL;
2342 gctPOINTER mutex = gcvNULL;
2343 gctUINT32 processID = 0;
2344 gctBOOL acquired = gcvFALSE;
2346 gcmkHEADER_ARG("Kernel=0x%X Handle=%d", Kernel, Handle);
2348 gckOS_GetProcessID(&processID);
2351 gckKERNEL_FindHandleDatbase(Kernel, processID, &database, &mutex));
2353 gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
2356 /* Translate handle to gckVIDMEM_HANDLE object. */
2358 gckKERNEL_QueryIntegerId(database, Handle, (gctPOINTER *)&handleObject));
2360 /* Get gckVIDMEM_NODE object. */
2361 node = handleObject->node;
2363 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
2364 acquired = gcvFALSE;
2366 /* Reference this gckVIDMEM_NODE object. */
2367 gcmkVERIFY_OK(gckVIDMEM_NODE_Reference(Kernel, node));
2369 /* Return result. */
2372 gcmkFOOTER_ARG("*Node=%d", *Node);
2373 return gcvSTATUS_OK;
2378 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
2386 gckVIDMEM_HANDLE_Lookup(
2387 IN gckKERNEL Kernel,
2388 IN gctUINT32 ProcessID,
2389 IN gctUINT32 Handle,
2390 OUT gckVIDMEM_NODE * Node
2394 gckVIDMEM_HANDLE handleObject = gcvNULL;
2395 gckVIDMEM_NODE node = gcvNULL;
2396 gctPOINTER database = gcvNULL;
2397 gctPOINTER mutex = gcvNULL;
2398 gctBOOL acquired = gcvFALSE;
2400 gcmkHEADER_ARG("Kernel=0x%X ProcessID=%d Handle=%d",
2401 Kernel, ProcessID, Handle);
2404 gckKERNEL_FindHandleDatbase(Kernel, ProcessID, &database, &mutex));
2406 gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
2410 gckKERNEL_QueryIntegerId(database, Handle, (gctPOINTER *)&handleObject));
2412 node = handleObject->node;
2414 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
2415 acquired = gcvFALSE;
2419 gcmkFOOTER_ARG("*Node=%d", *Node);
2420 return gcvSTATUS_OK;
2425 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
2432 /*******************************************************************************
2434 ** gckVIDMEM_NODE_Allocate
2436 ** Allocate a gckVIDMEM_NODE object.
2441 ** Pointer to an gckKERNEL object.
2443 ** gcuVIDMEM_NODE_PTR Node
2444 ** Pointer to a gcuVIDMEM_NODE union.
2448 ** gctUINT32 * Handle
2449 ** Pointer to a variable receiving a handle represent this
2450 ** gckVIDMEM_NODE in userspace.
2453 gckVIDMEM_NODE_Allocate(
2454 IN gckKERNEL Kernel,
2455 IN gcuVIDMEM_NODE_PTR VideoNode,
2456 IN gceSURF_TYPE Type,
2458 IN gctUINT32 * Handle
2462 gckVIDMEM_NODE node = gcvNULL;
2463 gctPOINTER pointer = gcvNULL;
2464 gctUINT32 handle = 0;
2465 gckOS os = Kernel->os;
2467 gcmkHEADER_ARG("Kernel=0x%X VideoNode=0x%X", Kernel, VideoNode);
2469 /* Construct a node. */
2470 gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsVIDMEM_NODE), &pointer));
2472 gcmkVERIFY_OK(gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsVIDMEM_NODE)));
2476 node->node = VideoNode;
2480 #if gcdPROCESS_ADDRESS_SPACE
2481 gcmkONERROR(gckOS_CreateMutex(os, &node->mapMutex));
2484 gcmkONERROR(gckOS_AtomConstruct(os, &node->reference));
2486 gcmkONERROR(gckOS_CreateMutex(os, &node->mutex));
2488 /* Reference is 1 by default . */
2489 gckVIDMEM_NODE_Reference(Kernel, node);
2491 /* Create a handle to represent this node. */
2492 gcmkONERROR(gckVIDMEM_HANDLE_Allocate(Kernel, node, &handle));
2496 gcmkFOOTER_ARG("*Handle=%d", *Handle);
2497 return gcvSTATUS_OK;
2500 if (node != gcvNULL)
2502 #if gcdPROCESS_ADDRESS_SPACE
2503 if (node->mapMutex != gcvNULL)
2505 gcmkVERIFY_OK(gckOS_DeleteMutex(os, node->mapMutex));
2511 gcmkVERIFY_OK(gckOS_DeleteMutex(os, node->mutex));
2514 if (node->reference != gcvNULL)
2516 gcmkVERIFY_OK(gckOS_AtomDestroy(os, node->reference));
2519 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, node));
2527 gckVIDMEM_NODE_Dereference(
2528 IN gckKERNEL Kernel,
2529 IN gckVIDMEM_NODE Node
2532 gctINT32 oldValue = 0;
2533 gctPOINTER database = Kernel->db->nameDatabase;
2534 gctPOINTER mutex = Kernel->db->nameDatabaseMutex;
2536 gcmkHEADER_ARG("Kernel=0x%X Node=0x%X", Kernel, Node);
2538 gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
2540 gcmkVERIFY_OK(gckOS_AtomDecrement(Kernel->os, Node->reference, &oldValue));
2542 if (oldValue == 1 && Node->name)
2544 /* Free name if exists. */
2545 gcmkVERIFY_OK(gckKERNEL_FreeIntegerId(database, Node->name));
2548 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
2552 /* Free gcuVIDMEM_NODE. */
2553 gcmkVERIFY_OK(gckVIDMEM_Free(Kernel, Node->node));
2554 gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Node->reference));
2555 #if gcdPROCESS_ADDRESS_SPACE
2556 gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Node->mapMutex));
2558 gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Node->mutex));
2559 gcmkOS_SAFE_FREE(Kernel->os, Node);
2563 return gcvSTATUS_OK;
2566 /*******************************************************************************
2568 ** gckVIDMEM_NODE_Name
2570 ** Naming a gckVIDMEM_NODE object.
2575 ** Pointer to an gckKERNEL object.
2578 ** Handle to a gckVIDMEM_NODE object.
2583 ** Pointer to a variable receiving a name which can be pass to another
2587 gckVIDMEM_NODE_Name(
2588 IN gckKERNEL Kernel,
2589 IN gctUINT32 Handle,
2594 gckVIDMEM_NODE node = gcvNULL;
2596 gctUINT32 processID = 0;
2597 gctPOINTER database = Kernel->db->nameDatabase;
2598 gctPOINTER mutex = Kernel->db->nameDatabaseMutex;
2599 gctBOOL acquired = gcvFALSE;
2600 gctBOOL referenced = gcvFALSE;
2601 gcmkHEADER_ARG("Kernel=0x%X Handle=%d", Kernel, Handle);
2603 gcmkONERROR(gckOS_GetProcessID(&processID));
2605 gcmkONERROR(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
2608 gcmkONERROR(gckVIDMEM_HANDLE_LookupAndReference(Kernel, Handle, &node));
2609 referenced = gcvTRUE;
2611 if (node->name == 0)
2613 /* Name this node. */
2614 gcmkONERROR(gckKERNEL_AllocateIntegerId(database, node, &name));
2618 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
2619 acquired = gcvFALSE;
2621 gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, node));
2628 gcmkFOOTER_ARG("*Name=%d", *Name);
2629 return gcvSTATUS_OK;
2634 gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, node));
2639 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
2646 /*******************************************************************************
2648 ** gckVIDMEM_NODE_Import
2650 ** Import a gckVIDMEM_NODE object.
2655 ** Pointer to an gckKERNEL object.
2658 ** Name of a gckVIDMEM_NODE object.
2662 ** gctUINT32 * Handle
2663 ** Pointer to a variable receiving a handle represent this
2664 ** gckVIDMEM_NODE in userspace.
2667 gckVIDMEM_NODE_Import(
2668 IN gckKERNEL Kernel,
2670 IN gctUINT32 * Handle
2674 gckVIDMEM_NODE node = gcvNULL;
2675 gctPOINTER database = Kernel->db->nameDatabase;
2676 gctPOINTER mutex = Kernel->db->nameDatabaseMutex;
2677 gctBOOL acquired = gcvFALSE;
2678 gctBOOL referenced = gcvFALSE;
2680 gcmkHEADER_ARG("Kernel=0x%X Name=%d", Kernel, Name);
2682 gcmkONERROR(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
2685 /* Lookup in database to get the node. */
2686 gcmkONERROR(gckKERNEL_QueryIntegerId(database, Name, (gctPOINTER *)&node));
2688 /* Reference the node. */
2689 gcmkONERROR(gckVIDMEM_NODE_Reference(Kernel, node));
2690 referenced = gcvTRUE;
2692 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
2693 acquired = gcvFALSE;
2695 /* Allocate a handle for current process. */
2696 gcmkONERROR(gckVIDMEM_HANDLE_Allocate(Kernel, node, Handle));
2698 gcmkFOOTER_ARG("*Handle=%d", *Handle);
2699 return gcvSTATUS_OK;
2704 gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, node));
2709 gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
2717 typedef struct _gcsVIDMEM_NODE_FDPRIVATE
2721 gckVIDMEM_NODE node;
2723 gcsVIDMEM_NODE_FDPRIVATE;
2728 gcsFDPRIVATE_PTR FdPrivate
2731 /* Cast private info. */
2732 gcsVIDMEM_NODE_FDPRIVATE * private = (gcsVIDMEM_NODE_FDPRIVATE *) FdPrivate;
2734 gckVIDMEM_NODE_Dereference(private->kernel, private->node);
2735 gckOS_Free(private->kernel->os, private);
2740 /*******************************************************************************
2742 ** gckVIDMEM_NODE_GetFd
2744 ** Attach a gckVIDMEM_NODE object to a native fd.
2749 ** Pointer to an gckKERNEL object.
2752 ** Handle to a gckVIDMEM_NODE object.
2757 ** Pointer to a variable receiving a native fd from os.
2760 gckVIDMEM_NODE_GetFd(
2761 IN gckKERNEL Kernel,
2762 IN gctUINT32 Handle,
2767 gckVIDMEM_NODE node = gcvNULL;
2768 gctBOOL referenced = gcvFALSE;
2769 gcsVIDMEM_NODE_FDPRIVATE * fdPrivate = gcvNULL;
2770 gcmkHEADER_ARG("Kernel=0x%X Handle=%d", Kernel, Handle);
2772 /* Query and reference handle. */
2773 gcmkONERROR(gckVIDMEM_HANDLE_LookupAndReference(Kernel, Handle, &node));
2774 referenced = gcvTRUE;
2776 /* Allocate memory for private info. */
2777 gcmkONERROR(gckOS_Allocate(
2779 gcmSIZEOF(gcsVIDMEM_NODE_FDPRIVATE),
2780 (gctPOINTER *)&fdPrivate
2783 fdPrivate->base.release = _ReleaseFdPrivate;
2784 fdPrivate->kernel = Kernel;
2785 fdPrivate->node = node;
2787 /* Allocated fd owns a reference. */
2788 gcmkONERROR(gckOS_GetFd("vidmem", &fdPrivate->base, Fd));
2790 gcmkFOOTER_ARG("*Fd=%d", *Fd);
2791 return gcvSTATUS_OK;
2796 gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, node));
2801 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, fdPrivate));