ENGR00156850 gpu-viv: add gpu-viv driver source
[wandboard.git] / drivers / mxc / gpu-viv / hal / kernel / gc_hal_kernel_video_memory.c
blob2c282f861b18287ecf8a5a1d641a2b34f18ed23f
1 /****************************************************************************
3 * Copyright (C) 2005 - 2011 by Vivante Corp.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the license, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *****************************************************************************/
24 #include "gc_hal_kernel_precomp.h"
26 #define _GC_OBJ_ZONE gcvZONE_VIDMEM
28 /******************************************************************************\
29 ******************************* Private Functions ******************************
30 \******************************************************************************/
32 /*******************************************************************************
34 ** _Split
36 ** Split a node on the required byte boundary.
38 ** INPUT:
40 ** gckOS Os
41 ** Pointer to an gckOS object.
43 ** gcuVIDMEM_NODE_PTR Node
44 ** Pointer to the node to split.
46 ** gctSIZE_T Bytes
47 ** Number of bytes to keep in the node.
49 ** OUTPUT:
51 ** Nothing.
53 ** RETURNS:
55 ** gctBOOL
56 ** gcvTRUE if the node was split successfully, or gcvFALSE if there is an
57 ** error.
60 static gctBOOL
61 _Split(
62 IN gckOS Os,
63 IN gcuVIDMEM_NODE_PTR Node,
64 IN gctSIZE_T Bytes
67 gcuVIDMEM_NODE_PTR node;
68 gctPOINTER pointer = gcvNULL;
70 /* Make sure the byte boundary makes sense. */
71 if ((Bytes <= 0) || (Bytes > Node->VidMem.bytes))
73 return gcvFALSE;
76 /* Allocate a new gcuVIDMEM_NODE object. */
77 if (gcmIS_ERROR(gckOS_Allocate(Os,
78 gcmSIZEOF(gcuVIDMEM_NODE),
79 &pointer)))
81 /* Error. */
82 return gcvFALSE;
85 node = pointer;
87 /* Initialize gcuVIDMEM_NODE structure. */
88 node->VidMem.offset = Node->VidMem.offset + Bytes;
89 node->VidMem.bytes = Node->VidMem.bytes - Bytes;
90 node->VidMem.alignment = 0;
91 node->VidMem.locked = 0;
92 node->VidMem.memory = Node->VidMem.memory;
93 node->VidMem.pool = Node->VidMem.pool;
94 node->VidMem.physical = Node->VidMem.physical;
95 #ifdef __QNXNTO__
96 #if gcdUSE_VIDMEM_PER_PID
97 gcmkASSERT(Node->VidMem.physical != 0);
98 gcmkASSERT(Node->VidMem.logical != gcvNULL);
99 node->VidMem.processID = Node->VidMem.processID;
100 node->VidMem.physical = Node->VidMem.physical + Bytes;
101 node->VidMem.logical = Node->VidMem.logical + Bytes;
102 #else
103 node->VidMem.processID = 0;
104 node->VidMem.logical = gcvNULL;
105 #endif
106 #endif
108 /* Insert node behind specified node. */
109 node->VidMem.next = Node->VidMem.next;
110 node->VidMem.prev = Node;
111 Node->VidMem.next = node->VidMem.next->VidMem.prev = node;
113 /* Insert free node behind specified node. */
114 node->VidMem.nextFree = Node->VidMem.nextFree;
115 node->VidMem.prevFree = Node;
116 Node->VidMem.nextFree = node->VidMem.nextFree->VidMem.prevFree = node;
118 /* Adjust size of specified node. */
119 Node->VidMem.bytes = Bytes;
121 /* Success. */
122 return gcvTRUE;
125 /*******************************************************************************
127 ** _Merge
129 ** Merge two adjacent nodes together.
131 ** INPUT:
133 ** gckOS Os
134 ** Pointer to an gckOS object.
136 ** gcuVIDMEM_NODE_PTR Node
137 ** Pointer to the first of the two nodes to merge.
139 ** OUTPUT:
141 ** Nothing.
144 static gceSTATUS
145 _Merge(
146 IN gckOS Os,
147 IN gcuVIDMEM_NODE_PTR Node
150 gcuVIDMEM_NODE_PTR node;
151 gceSTATUS status;
153 /* Save pointer to next node. */
154 node = Node->VidMem.next;
155 #if gcdUSE_VIDMEM_PER_PID
156 /* Check if the nodes are adjacent physically. */
157 if ( ((Node->VidMem.physical + Node->VidMem.bytes) != node->VidMem.physical) ||
158 ((Node->VidMem.logical + Node->VidMem.bytes) != node->VidMem.logical) )
160 /* Can't merge. */
161 return gcvSTATUS_OK;
163 #else
165 /* This is a good time to make sure the heap is not corrupted. */
166 if (Node->VidMem.offset + Node->VidMem.bytes != node->VidMem.offset)
168 /* Corrupted heap. */
169 gcmkASSERT(
170 Node->VidMem.offset + Node->VidMem.bytes == node->VidMem.offset);
171 return gcvSTATUS_HEAP_CORRUPTED;
173 #endif
175 /* Adjust byte count. */
176 Node->VidMem.bytes += node->VidMem.bytes;
178 /* Unlink next node from linked list. */
179 Node->VidMem.next = node->VidMem.next;
180 Node->VidMem.nextFree = node->VidMem.nextFree;
182 Node->VidMem.next->VidMem.prev =
183 Node->VidMem.nextFree->VidMem.prevFree = Node;
185 /* Free next node. */
186 status = gcmkOS_SAFE_FREE(Os, node);
187 return status;
190 /******************************************************************************\
191 ******************************* gckVIDMEM API Code ******************************
192 \******************************************************************************/
194 /*******************************************************************************
196 ** gckVIDMEM_ConstructVirtual
198 ** Construct a new gcuVIDMEM_NODE union for virtual memory.
200 ** INPUT:
202 ** gckKERNEL Kernel
203 ** Pointer to an gckKERNEL object.
205 ** gctSIZE_T Bytes
206 ** Number of byte to allocate.
208 ** OUTPUT:
210 ** gcuVIDMEM_NODE_PTR * Node
211 ** Pointer to a variable that receives the gcuVIDMEM_NODE union pointer.
213 gceSTATUS
214 gckVIDMEM_ConstructVirtual(
215 IN gckKERNEL Kernel,
216 IN gctBOOL Contiguous,
217 IN gctSIZE_T Bytes,
218 OUT gcuVIDMEM_NODE_PTR * Node
221 gckOS os;
222 gceSTATUS status;
223 gcuVIDMEM_NODE_PTR node = gcvNULL;
224 gctPOINTER pointer = gcvNULL;
225 gctINT i;
227 gcmkHEADER_ARG("Kernel=0x%x Contiguous=%d Bytes=%lu", Kernel, Contiguous, Bytes);
229 /* Verify the arguments. */
230 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
231 gcmkVERIFY_ARGUMENT(Bytes > 0);
232 gcmkVERIFY_ARGUMENT(Node != gcvNULL);
234 /* Extract the gckOS object pointer. */
235 os = Kernel->os;
236 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
238 /* Allocate an gcuVIDMEM_NODE union. */
239 gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcuVIDMEM_NODE), &pointer));
241 node = pointer;
243 /* Initialize gcuVIDMEM_NODE union for virtual memory. */
244 node->Virtual.kernel = Kernel;
245 node->Virtual.contiguous = Contiguous;
246 node->Virtual.logical = gcvNULL;
248 for (i = 0; i < gcdCORE_COUNT; i++)
250 node->Virtual.lockeds[i] = 0;
251 node->Virtual.pageTables[i] = gcvNULL;
252 node->Virtual.lockKernels[i] = gcvNULL;
255 node->Virtual.mutex = gcvNULL;
257 gcmkONERROR(gckOS_GetProcessID(&node->Virtual.processID));
259 #ifdef __QNXNTO__
260 node->Virtual.next = gcvNULL;
261 node->Virtual.freePending = gcvFALSE;
262 for (i = 0; i < gcdCORE_COUNT; i++)
264 node->Virtual.unlockPendings[i] = gcvFALSE;
266 #endif
268 node->Virtual.freed = gcvFALSE;
269 /* Create the mutex. */
270 gcmkONERROR(
271 gckOS_CreateMutex(os, &node->Virtual.mutex));
273 /* Allocate the virtual memory. */
274 gcmkONERROR(
275 gckOS_AllocatePagedMemoryEx(os,
276 node->Virtual.contiguous,
277 node->Virtual.bytes = Bytes,
278 &node->Virtual.physical));
280 #ifdef __QNXNTO__
281 /* Register. */
282 gckMMU_InsertNode(Kernel->mmu, node);
283 #endif
285 /* Return pointer to the gcuVIDMEM_NODE union. */
286 *Node = node;
288 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
289 "Created virtual node 0x%x for %u bytes @ 0x%x",
290 node, Bytes, node->Virtual.physical);
292 /* Success. */
293 gcmkFOOTER_ARG("*Node=0x%x", *Node);
294 return gcvSTATUS_OK;
296 OnError:
297 /* Roll back. */
298 if (node != gcvNULL)
300 if (node->Virtual.mutex != gcvNULL)
302 /* Destroy the mutex. */
303 gcmkVERIFY_OK(gckOS_DeleteMutex(os, node->Virtual.mutex));
306 /* Free the structure. */
307 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, node));
310 /* Return the status. */
311 gcmkFOOTER();
312 return status;
315 /*******************************************************************************
317 ** gckVIDMEM_DestroyVirtual
319 ** Destroy an gcuVIDMEM_NODE union for virtual memory.
321 ** INPUT:
323 ** gcuVIDMEM_NODE_PTR Node
324 ** Pointer to a gcuVIDMEM_NODE union.
326 ** OUTPUT:
328 ** Nothing.
330 gceSTATUS
331 gckVIDMEM_DestroyVirtual(
332 IN gcuVIDMEM_NODE_PTR Node
335 gckOS os;
336 gctINT i;
338 gcmkHEADER_ARG("Node=0x%x", Node);
340 /* Verify the arguments. */
341 gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL);
343 /* Extact the gckOS object pointer. */
344 os = Node->Virtual.kernel->os;
345 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
347 #ifdef __QNXNTO__
348 /* Unregister. */
349 gcmkVERIFY_OK(
350 gckMMU_RemoveNode(Node->Virtual.kernel->mmu, Node));
351 #endif
353 /* Delete the mutex. */
354 gcmkVERIFY_OK(gckOS_DeleteMutex(os, Node->Virtual.mutex));
356 for (i = 0; i < gcdCORE_COUNT; i++)
358 if (Node->Virtual.pageTables[i] != gcvNULL)
360 #if gcdENABLE_VG
361 if (i == gcvCORE_VG)
363 /* Free the pages. */
364 gcmkVERIFY_OK(gckVGMMU_FreePages(Node->Virtual.lockKernels[i]->vg->mmu,
365 Node->Virtual.pageTables[i],
366 Node->Virtual.pageCount));
368 else
369 #endif
371 /* Free the pages. */
372 gcmkVERIFY_OK(gckMMU_FreePages(Node->Virtual.lockKernels[i]->mmu,
373 Node->Virtual.pageTables[i],
374 Node->Virtual.pageCount));
379 /* Delete the gcuVIDMEM_NODE union. */
380 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, Node));
382 /* Success. */
383 gcmkFOOTER_NO();
384 return gcvSTATUS_OK;
387 /*******************************************************************************
389 ** gckVIDMEM_Construct
391 ** Construct a new gckVIDMEM object.
393 ** INPUT:
395 ** gckOS Os
396 ** Pointer to an gckOS object.
398 ** gctUINT32 BaseAddress
399 ** Base address for the video memory heap.
401 ** gctSIZE_T Bytes
402 ** Number of bytes in the video memory heap.
404 ** gctSIZE_T Threshold
405 ** Minimum number of bytes beyond am allocation before the node is
406 ** split. Can be used as a minimum alignment requirement.
408 ** gctSIZE_T BankSize
409 ** Number of bytes per physical memory bank. Used by bank
410 ** optimization.
412 ** OUTPUT:
414 ** gckVIDMEM * Memory
415 ** Pointer to a variable that will hold the pointer to the gckVIDMEM
416 ** object.
418 gceSTATUS
419 gckVIDMEM_Construct(
420 IN gckOS Os,
421 IN gctUINT32 BaseAddress,
422 IN gctSIZE_T Bytes,
423 IN gctSIZE_T Threshold,
424 IN gctSIZE_T BankSize,
425 OUT gckVIDMEM * Memory
428 gckVIDMEM memory = gcvNULL;
429 gceSTATUS status;
430 gcuVIDMEM_NODE_PTR node;
431 gctINT i, banks = 0;
432 gctPOINTER pointer = gcvNULL;
434 gcmkHEADER_ARG("Os=0x%x BaseAddress=%08x Bytes=%lu Threshold=%lu "
435 "BankSize=%lu",
436 Os, BaseAddress, Bytes, Threshold, BankSize);
438 /* Verify the arguments. */
439 gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
440 gcmkVERIFY_ARGUMENT(Bytes > 0);
441 gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
443 /* Allocate the gckVIDMEM object. */
444 gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(struct _gckVIDMEM), &pointer));
446 memory = pointer;
448 /* Initialize the gckVIDMEM object. */
449 memory->object.type = gcvOBJ_VIDMEM;
450 memory->os = Os;
452 /* Set video memory heap information. */
453 memory->baseAddress = BaseAddress;
454 memory->bytes = Bytes;
455 memory->freeBytes = Bytes;
456 memory->threshold = Threshold;
457 memory->mutex = gcvNULL;
458 #if gcdUSE_VIDMEM_PER_PID
459 gcmkONERROR(gckOS_GetProcessID(&memory->pid));
460 #endif
462 BaseAddress = 0;
464 /* Walk all possible banks. */
465 for (i = 0; i < gcmCOUNTOF(memory->sentinel); ++i)
467 gctSIZE_T bytes;
469 if (BankSize == 0)
471 /* Use all bytes for the first bank. */
472 bytes = Bytes;
474 else
476 /* Compute number of bytes for this bank. */
477 bytes = gcmALIGN(BaseAddress + 1, BankSize) - BaseAddress;
479 if (bytes > Bytes)
481 /* Make sure we don't exceed the total number of bytes. */
482 bytes = Bytes;
486 if (bytes == 0)
488 /* Mark heap is not used. */
489 memory->sentinel[i].VidMem.next =
490 memory->sentinel[i].VidMem.prev =
491 memory->sentinel[i].VidMem.nextFree =
492 memory->sentinel[i].VidMem.prevFree = gcvNULL;
493 continue;
496 /* Allocate one gcuVIDMEM_NODE union. */
497 gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcuVIDMEM_NODE), &pointer));
499 node = pointer;
501 /* Initialize gcuVIDMEM_NODE union. */
502 node->VidMem.memory = memory;
504 node->VidMem.next =
505 node->VidMem.prev =
506 node->VidMem.nextFree =
507 node->VidMem.prevFree = &memory->sentinel[i];
509 node->VidMem.offset = BaseAddress;
510 node->VidMem.bytes = bytes;
511 node->VidMem.alignment = 0;
512 node->VidMem.physical = 0;
513 node->VidMem.pool = gcvPOOL_UNKNOWN;
515 node->VidMem.locked = 0;
517 #ifdef __QNXNTO__
518 #if gcdUSE_VIDMEM_PER_PID
519 node->VidMem.processID = memory->pid;
520 node->VidMem.physical = memory->baseAddress + BaseAddress;
521 gcmkONERROR(gckOS_GetLogicalAddressProcess(Os,
522 node->VidMem.processID,
523 node->VidMem.physical,
524 &node->VidMem.logical));
525 #else
526 node->VidMem.processID = 0;
527 node->VidMem.logical = gcvNULL;
528 #endif
529 #endif
531 /* Initialize the linked list of nodes. */
532 memory->sentinel[i].VidMem.next =
533 memory->sentinel[i].VidMem.prev =
534 memory->sentinel[i].VidMem.nextFree =
535 memory->sentinel[i].VidMem.prevFree = node;
537 /* Mark sentinel. */
538 memory->sentinel[i].VidMem.bytes = 0;
540 /* Adjust address for next bank. */
541 BaseAddress += bytes;
542 Bytes -= bytes;
543 banks ++;
546 /* Assign all the bank mappings. */
547 memory->mapping[gcvSURF_RENDER_TARGET] = banks - 1;
548 memory->mapping[gcvSURF_BITMAP] = banks - 1;
549 if (banks > 1) --banks;
550 memory->mapping[gcvSURF_DEPTH] = banks - 1;
551 memory->mapping[gcvSURF_HIERARCHICAL_DEPTH] = banks - 1;
552 if (banks > 1) --banks;
553 memory->mapping[gcvSURF_TEXTURE] = banks - 1;
554 if (banks > 1) --banks;
555 memory->mapping[gcvSURF_VERTEX] = banks - 1;
556 if (banks > 1) --banks;
557 memory->mapping[gcvSURF_INDEX] = banks - 1;
558 if (banks > 1) --banks;
559 memory->mapping[gcvSURF_TILE_STATUS] = banks - 1;
560 if (banks > 1) --banks;
561 memory->mapping[gcvSURF_TYPE_UNKNOWN] = 0;
563 #if gcdENABLE_VG
564 memory->mapping[gcvSURF_IMAGE] = 0;
565 memory->mapping[gcvSURF_MASK] = 0;
566 memory->mapping[gcvSURF_SCISSOR] = 0;
567 #endif
569 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
570 "[GALCORE] INDEX: bank %d",
571 memory->mapping[gcvSURF_INDEX]);
572 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
573 "[GALCORE] VERTEX: bank %d",
574 memory->mapping[gcvSURF_VERTEX]);
575 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
576 "[GALCORE] TEXTURE: bank %d",
577 memory->mapping[gcvSURF_TEXTURE]);
578 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
579 "[GALCORE] RENDER_TARGET: bank %d",
580 memory->mapping[gcvSURF_RENDER_TARGET]);
581 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
582 "[GALCORE] DEPTH: bank %d",
583 memory->mapping[gcvSURF_DEPTH]);
584 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
585 "[GALCORE] TILE_STATUS: bank %d",
586 memory->mapping[gcvSURF_TILE_STATUS]);
588 /* Allocate the mutex. */
589 gcmkONERROR(gckOS_CreateMutex(Os, &memory->mutex));
591 /* Return pointer to the gckVIDMEM object. */
592 *Memory = memory;
594 /* Success. */
595 gcmkFOOTER_ARG("*Memory=0x%x", *Memory);
596 return gcvSTATUS_OK;
598 OnError:
599 /* Roll back. */
600 if (memory != gcvNULL)
602 if (memory->mutex != gcvNULL)
604 /* Delete the mutex. */
605 gcmkVERIFY_OK(gckOS_DeleteMutex(Os, memory->mutex));
608 for (i = 0; i < banks; ++i)
610 /* Free the heap. */
611 gcmkASSERT(memory->sentinel[i].VidMem.next != gcvNULL);
612 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, memory->sentinel[i].VidMem.next));
615 /* Free the object. */
616 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, memory));
619 /* Return the status. */
620 gcmkFOOTER();
621 return status;
624 /*******************************************************************************
626 ** gckVIDMEM_Destroy
628 ** Destroy an gckVIDMEM object.
630 ** INPUT:
632 ** gckVIDMEM Memory
633 ** Pointer to an gckVIDMEM object to destroy.
635 ** OUTPUT:
637 ** Nothing.
639 gceSTATUS
640 gckVIDMEM_Destroy(
641 IN gckVIDMEM Memory
644 gcuVIDMEM_NODE_PTR node, next;
645 gctINT i;
647 gcmkHEADER_ARG("Memory=0x%x", Memory);
649 /* Verify the arguments. */
650 gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM);
652 /* Walk all sentinels. */
653 for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i)
655 /* Bail out of the heap is not used. */
656 if (Memory->sentinel[i].VidMem.next == gcvNULL)
658 break;
661 /* Walk all the nodes until we reach the sentinel. */
662 for (node = Memory->sentinel[i].VidMem.next;
663 node->VidMem.bytes != 0;
664 node = next)
666 /* Save pointer to the next node. */
667 next = node->VidMem.next;
669 /* Free the node. */
670 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Memory->os, node));
674 /* Free the mutex. */
675 gcmkVERIFY_OK(gckOS_DeleteMutex(Memory->os, Memory->mutex));
677 /* Mark the object as unknown. */
678 Memory->object.type = gcvOBJ_UNKNOWN;
680 /* Free the gckVIDMEM object. */
681 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Memory->os, Memory));
683 /* Success. */
684 gcmkFOOTER_NO();
685 return gcvSTATUS_OK;
688 /*******************************************************************************
690 ** gckVIDMEM_Allocate
692 ** Allocate rectangular memory from the gckVIDMEM object.
694 ** INPUT:
696 ** gckVIDMEM Memory
697 ** Pointer to an gckVIDMEM object.
699 ** gctUINT Width
700 ** Width of rectangle to allocate. Make sure the width is properly
701 ** aligned.
703 ** gctUINT Height
704 ** Height of rectangle to allocate. Make sure the height is properly
705 ** aligned.
707 ** gctUINT Depth
708 ** Depth of rectangle to allocate. This equals to the number of
709 ** rectangles to allocate contiguously (i.e., for cubic maps and volume
710 ** textures).
712 ** gctUINT BytesPerPixel
713 ** Number of bytes per pixel.
715 ** gctUINT32 Alignment
716 ** Byte alignment for allocation.
718 ** gceSURF_TYPE Type
719 ** Type of surface to allocate (use by bank optimization).
721 ** OUTPUT:
723 ** gcuVIDMEM_NODE_PTR * Node
724 ** Pointer to a variable that will hold the allocated memory node.
726 gceSTATUS
727 gckVIDMEM_Allocate(
728 IN gckVIDMEM Memory,
729 IN gctUINT Width,
730 IN gctUINT Height,
731 IN gctUINT Depth,
732 IN gctUINT BytesPerPixel,
733 IN gctUINT32 Alignment,
734 IN gceSURF_TYPE Type,
735 OUT gcuVIDMEM_NODE_PTR * Node
738 gctSIZE_T bytes;
739 gceSTATUS status;
741 gcmkHEADER_ARG("Memory=0x%x Width=%u Height=%u Depth=%u BytesPerPixel=%u "
742 "Alignment=%u Type=%d",
743 Memory, Width, Height, Depth, BytesPerPixel, Alignment,
744 Type);
746 /* Verify the arguments. */
747 gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM);
748 gcmkVERIFY_ARGUMENT(Width > 0);
749 gcmkVERIFY_ARGUMENT(Height > 0);
750 gcmkVERIFY_ARGUMENT(Depth > 0);
751 gcmkVERIFY_ARGUMENT(BytesPerPixel > 0);
752 gcmkVERIFY_ARGUMENT(Node != gcvNULL);
754 /* Compute linear size. */
755 bytes = Width * Height * Depth * BytesPerPixel;
757 /* Allocate through linear function. */
758 gcmkONERROR(
759 gckVIDMEM_AllocateLinear(Memory, bytes, Alignment, Type, Node));
761 /* Success. */
762 gcmkFOOTER_ARG("*Node=0x%x", *Node);
763 return gcvSTATUS_OK;
765 OnError:
766 /* Return the status. */
767 gcmkFOOTER();
768 return status;
771 static gcuVIDMEM_NODE_PTR
772 _FindNode(
773 IN gckVIDMEM Memory,
774 IN gctINT Bank,
775 IN gctSIZE_T Bytes,
776 IN gceSURF_TYPE Type,
777 IN OUT gctUINT32_PTR Alignment
780 gcuVIDMEM_NODE_PTR node;
781 gctUINT32 alignment;
783 #if gcdENABLE_BANK_ALIGNMENT
784 gctUINT32 bankAlignment;
785 gceSTATUS status;
787 /* Walk all free nodes until we have one that is big enough or we have
788 ** reached the sentinel. */
789 for (node = Memory->sentinel[Bank].VidMem.nextFree;
790 node->VidMem.bytes != 0;
791 node = node->VidMem.nextFree)
793 gcmkONERROR(gckOS_GetSurfaceBankAlignment(
794 Memory->os,
795 Type,
796 node->VidMem.memory->baseAddress + node->VidMem.offset,
797 &bankAlignment));
799 bankAlignment = gcmALIGN(bankAlignment, *Alignment);
801 /* Compute number of bytes to skip for alignment. */
802 alignment = (*Alignment == 0)
804 : (*Alignment - (node->VidMem.offset % *Alignment));
806 if (alignment == *Alignment)
808 /* Node is already aligned. */
809 alignment = 0;
812 if (node->VidMem.bytes >= Bytes + alignment + bankAlignment)
814 /* This node is big enough. */
815 *Alignment = alignment + bankAlignment;
816 return node;
819 #endif
821 /* Walk all free nodes until we have one that is big enough or we have
822 reached the sentinel. */
823 for (node = Memory->sentinel[Bank].VidMem.nextFree;
824 node->VidMem.bytes != 0;
825 node = node->VidMem.nextFree)
828 gctINT modulo = gckMATH_ModuloInt(node->VidMem.offset, *Alignment);
830 /* Compute number of bytes to skip for alignment. */
831 alignment = (*Alignment == 0) ? 0 : (*Alignment - modulo);
833 if (alignment == *Alignment)
835 /* Node is already aligned. */
836 alignment = 0;
839 if (node->VidMem.bytes >= Bytes + alignment)
841 /* This node is big enough. */
842 *Alignment = alignment;
843 return node;
847 #if gcdENABLE_BANK_ALIGNMENT
848 OnError:
849 #endif
850 /* Not enough memory. */
851 return gcvNULL;
854 /*******************************************************************************
856 ** gckVIDMEM_AllocateLinear
858 ** Allocate linear memory from the gckVIDMEM object.
860 ** INPUT:
862 ** gckVIDMEM Memory
863 ** Pointer to an gckVIDMEM object.
865 ** gctSIZE_T Bytes
866 ** Number of bytes to allocate.
868 ** gctUINT32 Alignment
869 ** Byte alignment for allocation.
871 ** gceSURF_TYPE Type
872 ** Type of surface to allocate (use by bank optimization).
874 ** OUTPUT:
876 ** gcuVIDMEM_NODE_PTR * Node
877 ** Pointer to a variable that will hold the allocated memory node.
879 gceSTATUS
880 gckVIDMEM_AllocateLinear(
881 IN gckVIDMEM Memory,
882 IN gctSIZE_T Bytes,
883 IN gctUINT32 Alignment,
884 IN gceSURF_TYPE Type,
885 OUT gcuVIDMEM_NODE_PTR * Node
888 gceSTATUS status;
889 gcuVIDMEM_NODE_PTR node;
890 gctUINT32 alignment;
891 gctINT bank, i;
892 gctBOOL acquired = gcvFALSE;
894 gcmkHEADER_ARG("Memory=0x%x Bytes=%lu Alignment=%u Type=%d",
895 Memory, Bytes, Alignment, Type);
897 /* Verify the arguments. */
898 gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM);
899 gcmkVERIFY_ARGUMENT(Bytes > 0);
900 gcmkVERIFY_ARGUMENT(Node != gcvNULL);
901 gcmkVERIFY_ARGUMENT(Type < gcvSURF_NUM_TYPES);
903 /* Acquire the mutex. */
904 gcmkONERROR(gckOS_AcquireMutex(Memory->os, Memory->mutex, gcvINFINITE));
906 acquired = gcvTRUE;
907 #if !gcdUSE_VIDMEM_PER_PID
909 if (Bytes > Memory->freeBytes)
911 /* Not enough memory. */
912 status = gcvSTATUS_OUT_OF_MEMORY;
913 goto OnError;
915 #endif
917 /* Find the default bank for this surface type. */
918 gcmkASSERT((gctINT) Type < gcmCOUNTOF(Memory->mapping));
919 bank = Memory->mapping[Type];
920 alignment = Alignment;
922 #if gcdUSE_VIDMEM_PER_PID
923 if (Bytes <= Memory->freeBytes)
925 #endif
926 /* Find a free node in the default bank. */
927 node = _FindNode(Memory, bank, Bytes, Type, &alignment);
929 /* Out of memory? */
930 if (node == gcvNULL)
932 /* Walk all lower banks. */
933 for (i = bank - 1; i >= 0; --i)
935 /* Find a free node inside the current bank. */
936 node = _FindNode(Memory, i, Bytes, Type, &alignment);
937 if (node != gcvNULL)
939 break;
944 if (node == gcvNULL)
946 /* Walk all upper banks. */
947 for (i = bank + 1; i < gcmCOUNTOF(Memory->sentinel); ++i)
949 if (Memory->sentinel[i].VidMem.nextFree == gcvNULL)
951 /* Abort when we reach unused banks. */
952 break;
955 /* Find a free node inside the current bank. */
956 node = _FindNode(Memory, i, Bytes, Type, &alignment);
957 if (node != gcvNULL)
959 break;
963 #if gcdUSE_VIDMEM_PER_PID
965 #endif
967 if (node == gcvNULL)
969 /* Out of memory. */
970 #if gcdUSE_VIDMEM_PER_PID
971 /* Allocate more memory from shared pool. */
972 gctSIZE_T bytes;
973 gctPHYS_ADDR physical_temp;
974 gctUINT32 physical;
975 gctPOINTER logical;
977 bytes = gcmALIGN(Bytes, gcdUSE_VIDMEM_PER_PID_SIZE);
979 gcmkONERROR(gckOS_AllocateContiguous(Memory->os,
980 gcvTRUE,
981 &bytes,
982 &physical_temp,
983 &logical));
985 /* physical address is returned as 0 for user space. workaround. */
986 if (physical_temp == gcvNULL)
988 gcmkONERROR(gckOS_GetPhysicalAddress(Memory->os, logical, &physical));
991 /* Allocate one gcuVIDMEM_NODE union. */
992 gcmkONERROR(
993 gckOS_Allocate(Memory->os,
994 gcmSIZEOF(gcuVIDMEM_NODE),
995 (gctPOINTER *) &node));
997 /* Initialize gcuVIDMEM_NODE union. */
998 node->VidMem.memory = Memory;
1000 node->VidMem.offset = 0;
1001 node->VidMem.bytes = bytes;
1002 node->VidMem.alignment = 0;
1003 node->VidMem.physical = physical;
1004 node->VidMem.pool = gcvPOOL_UNKNOWN;
1006 node->VidMem.locked = 0;
1008 #ifdef __QNXNTO__
1009 gcmkONERROR(gckOS_GetProcessID(&node->VidMem.processID));
1010 node->VidMem.logical = logical;
1011 gcmkASSERT(logical != gcvNULL);
1012 #endif
1014 /* Insert node behind sentinel node. */
1015 node->VidMem.next = Memory->sentinel[bank].VidMem.next;
1016 node->VidMem.prev = &Memory->sentinel[bank];
1017 Memory->sentinel[bank].VidMem.next = node->VidMem.next->VidMem.prev = node;
1019 /* Insert free node behind sentinel node. */
1020 node->VidMem.nextFree = Memory->sentinel[bank].VidMem.nextFree;
1021 node->VidMem.prevFree = &Memory->sentinel[bank];
1022 Memory->sentinel[bank].VidMem.nextFree = node->VidMem.nextFree->VidMem.prevFree = node;
1024 Memory->freeBytes += bytes;
1025 #else
1026 status = gcvSTATUS_OUT_OF_MEMORY;
1027 goto OnError;
1028 #endif
1031 /* Do we have an alignment? */
1032 if (alignment > 0)
1034 /* Split the node so it is aligned. */
1035 if (_Split(Memory->os, node, alignment))
1037 /* Successful split, move to aligned node. */
1038 node = node->VidMem.next;
1040 /* Remove alignment. */
1041 alignment = 0;
1045 /* Do we have enough memory after the allocation to split it? */
1046 if (node->VidMem.bytes - Bytes > Memory->threshold)
1048 /* Adjust the node size. */
1049 _Split(Memory->os, node, Bytes);
1052 /* Remove the node from the free list. */
1053 node->VidMem.prevFree->VidMem.nextFree = node->VidMem.nextFree;
1054 node->VidMem.nextFree->VidMem.prevFree = node->VidMem.prevFree;
1055 node->VidMem.nextFree =
1056 node->VidMem.prevFree = gcvNULL;
1058 /* Fill in the information. */
1059 node->VidMem.alignment = alignment;
1060 node->VidMem.memory = Memory;
1061 #ifdef __QNXNTO__
1062 #if !gcdUSE_VIDMEM_PER_PID
1063 node->VidMem.logical = gcvNULL;
1064 gcmkONERROR(gckOS_GetProcessID(&node->VidMem.processID));
1065 #else
1066 gcmkASSERT(node->VidMem.logical != gcvNULL);
1067 #endif
1068 #endif
1070 /* Adjust the number of free bytes. */
1071 Memory->freeBytes -= node->VidMem.bytes;
1073 node->VidMem.freePending = gcvFALSE;
1075 /* Release the mutex. */
1076 gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex));
1078 /* Return the pointer to the node. */
1079 *Node = node;
1081 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1082 "Allocated %u bytes @ 0x%x [0x%08X]",
1083 node->VidMem.bytes, node, node->VidMem.offset);
1085 /* Success. */
1086 gcmkFOOTER_ARG("*Node=0x%x", *Node);
1087 return gcvSTATUS_OK;
1089 OnError:
1090 if (acquired)
1092 /* Release the mutex. */
1093 gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex));
1096 /* Return the status. */
1097 gcmkFOOTER();
1098 return status;
1101 /*******************************************************************************
1103 ** gckVIDMEM_Free
1105 ** Free an allocated video memory node.
1107 ** INPUT:
1109 ** gcuVIDMEM_NODE_PTR Node
1110 ** Pointer to a gcuVIDMEM_NODE object.
1112 ** OUTPUT:
1114 ** Nothing.
1116 gceSTATUS
1117 gckVIDMEM_Free(
1118 IN gcuVIDMEM_NODE_PTR Node
1121 gceSTATUS status;
1122 gckKERNEL kernel = gcvNULL;
1123 gckVIDMEM memory = gcvNULL;
1124 gcuVIDMEM_NODE_PTR node;
1125 gctBOOL mutexAcquired = gcvFALSE;
1126 gckOS os = gcvFALSE;
1127 gctBOOL acquired = gcvFALSE;
1128 gctINT32 i, totalLocked;
1130 gcmkHEADER_ARG("Node=0x%x", Node);
1132 /* Verify the arguments. */
1133 if ((Node == gcvNULL)
1134 || (Node->VidMem.memory == gcvNULL)
1137 /* Invalid object. */
1138 gcmkONERROR(gcvSTATUS_INVALID_OBJECT);
1141 /**************************** Video Memory ********************************/
1143 if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
1145 if (Node->VidMem.locked > 0)
1147 /* Client still has a lock, defer free op 'till when lock reaches 0. */
1148 Node->VidMem.freePending = gcvTRUE;
1150 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1151 "Node 0x%x is locked (%d)... deferring free.",
1152 Node, Node->VidMem.locked);
1154 gcmkFOOTER_NO();
1155 return gcvSTATUS_OK;
1158 /* Extract pointer to gckVIDMEM object owning the node. */
1159 memory = Node->VidMem.memory;
1161 /* Acquire the mutex. */
1162 gcmkONERROR(
1163 gckOS_AcquireMutex(memory->os, memory->mutex, gcvINFINITE));
1165 mutexAcquired = gcvTRUE;
1167 #ifdef __QNXNTO__
1168 #if !gcdUSE_VIDMEM_PER_PID
1169 /* Reset. */
1170 Node->VidMem.processID = 0;
1171 Node->VidMem.logical = gcvNULL;
1172 #endif
1174 /* Don't try to re-free an already freed node. */
1175 if ((Node->VidMem.nextFree == gcvNULL)
1176 && (Node->VidMem.prevFree == gcvNULL)
1178 #endif
1180 /* Update the number of free bytes. */
1181 memory->freeBytes += Node->VidMem.bytes;
1183 /* Find the next free node. */
1184 for (node = Node->VidMem.next;
1185 node != gcvNULL && node->VidMem.nextFree == gcvNULL;
1186 node = node->VidMem.next) ;
1188 /* Insert this node in the free list. */
1189 Node->VidMem.nextFree = node;
1190 Node->VidMem.prevFree = node->VidMem.prevFree;
1192 Node->VidMem.prevFree->VidMem.nextFree =
1193 node->VidMem.prevFree = Node;
1195 /* Is the next node a free node and not the sentinel? */
1196 if ((Node->VidMem.next == Node->VidMem.nextFree)
1197 && (Node->VidMem.next->VidMem.bytes != 0)
1200 /* Merge this node with the next node. */
1201 gcmkONERROR(_Merge(memory->os, node = Node));
1202 gcmkASSERT(node->VidMem.nextFree != node);
1203 gcmkASSERT(node->VidMem.prevFree != node);
1206 /* Is the previous node a free node and not the sentinel? */
1207 if ((Node->VidMem.prev == Node->VidMem.prevFree)
1208 && (Node->VidMem.prev->VidMem.bytes != 0)
1211 /* Merge this node with the previous node. */
1212 gcmkONERROR(_Merge(memory->os, node = Node->VidMem.prev));
1213 gcmkASSERT(node->VidMem.nextFree != node);
1214 gcmkASSERT(node->VidMem.prevFree != node);
1218 /* Release the mutex. */
1219 gcmkVERIFY_OK(gckOS_ReleaseMutex(memory->os, memory->mutex));
1221 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1222 "Node 0x%x is freed.",
1223 Node);
1225 /* Success. */
1226 gcmkFOOTER_NO();
1227 return gcvSTATUS_OK;
1230 /*************************** Virtual Memory *******************************/
1232 /* Get gckKERNEL object. */
1233 kernel = Node->Virtual.kernel;
1235 /* Verify the gckKERNEL object pointer. */
1236 gcmkVERIFY_OBJECT(kernel, gcvOBJ_KERNEL);
1238 /* Get the gckOS object pointer. */
1239 os = kernel->os;
1240 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
1242 /* Grab the mutex. */
1243 gcmkONERROR(
1244 gckOS_AcquireMutex(os, Node->Virtual.mutex, gcvINFINITE));
1246 acquired = gcvTRUE;
1248 for (i = 0, totalLocked = 0; i < gcdCORE_COUNT; i++)
1250 totalLocked += Node->Virtual.lockeds[i];
1253 if (totalLocked > 0)
1255 gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_VIDMEM,
1256 "gckVIDMEM_Free: Virtual node 0x%x is locked (%d)",
1257 Node, totalLocked);
1259 /* Set Flag */
1260 Node->Virtual.freed = gcvTRUE;
1262 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex));
1264 else
1266 /* Free the virtual memory. */
1267 gcmkVERIFY_OK(gckOS_FreePagedMemory(kernel->os,
1268 Node->Virtual.physical,
1269 Node->Virtual.bytes));
1271 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex));
1273 /* Destroy the gcuVIDMEM_NODE union. */
1274 gcmkVERIFY_OK(gckVIDMEM_DestroyVirtual(Node));
1277 /* Success. */
1278 gcmkFOOTER_NO();
1279 return gcvSTATUS_OK;
1281 OnError:
1282 if (mutexAcquired)
1284 /* Release the mutex. */
1285 gcmkVERIFY_OK(gckOS_ReleaseMutex(
1286 memory->os, memory->mutex
1290 if (acquired)
1292 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex));
1295 /* Return the status. */
1296 gcmkFOOTER();
1297 return status;
1301 #ifdef __QNXNTO__
1302 /*******************************************************************************
1304 ** gcoVIDMEM_FreeHandleMemory
1306 ** Free all allocated video memory nodes for a handle.
1308 ** INPUT:
1310 ** gcoVIDMEM Memory
1311 ** Pointer to an gcoVIDMEM object..
1313 ** OUTPUT:
1315 ** Nothing.
1317 gceSTATUS
1318 gckVIDMEM_FreeHandleMemory(
1319 IN gckKERNEL Kernel,
1320 IN gckVIDMEM Memory,
1321 IN gctUINT32 Pid
1324 gceSTATUS status;
1325 gctBOOL mutex = gcvFALSE;
1326 gcuVIDMEM_NODE_PTR node;
1327 gctINT i;
1328 gctUINT32 nodeCount = 0, byteCount = 0;
1329 gctBOOL again;
1331 gcmkHEADER_ARG("Kernel=0x%x, Memory=0x%x Pid=0x%u", Kernel, Memory, Pid);
1333 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
1334 gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM);
1336 gcmkONERROR(gckOS_AcquireMutex(Memory->os, Memory->mutex, gcvINFINITE));
1337 mutex = gcvTRUE;
1339 /* Walk all sentinels. */
1340 for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i)
1342 /* Bail out of the heap if it is not used. */
1343 if (Memory->sentinel[i].VidMem.next == gcvNULL)
1345 break;
1350 again = gcvFALSE;
1352 /* Walk all the nodes until we reach the sentinel. */
1353 for (node = Memory->sentinel[i].VidMem.next;
1354 node->VidMem.bytes != 0;
1355 node = node->VidMem.next)
1357 /* Free the node if it was allocated by Handle. */
1358 if (node->VidMem.processID == Pid)
1360 /* Unlock video memory. */
1361 while (node->VidMem.locked > 0)
1363 gckVIDMEM_Unlock(Kernel, node, gcvSURF_TYPE_UNKNOWN, gcvNULL);
1366 nodeCount++;
1367 byteCount += node->VidMem.bytes;
1369 /* Free video memory. */
1370 gcmkVERIFY_OK(gckVIDMEM_Free(node));
1373 * Freeing may cause a merge which will invalidate our iteration.
1374 * Don't be clever, just restart.
1376 again = gcvTRUE;
1378 break;
1380 #if gcdUSE_VIDMEM_PER_PID
1381 else
1383 gcmkASSERT(node->VidMem.processID == Pid);
1385 #endif
1388 while (again);
1391 gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex));
1392 gcmkFOOTER();
1393 return gcvSTATUS_OK;
1395 OnError:
1396 if (mutex)
1398 gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex));
1401 gcmkFOOTER();
1402 return status;
1404 #endif
1406 /*******************************************************************************
1408 ** gckVIDMEM_Lock
1410 ** Lock a video memory node and return its hardware specific address.
1412 ** INPUT:
1414 ** gckKERNEL Kernel
1415 ** Pointer to an gckKERNEL object.
1417 ** gcuVIDMEM_NODE_PTR Node
1418 ** Pointer to a gcuVIDMEM_NODE union.
1420 ** OUTPUT:
1422 ** gctUINT32 * Address
1423 ** Pointer to a variable that will hold the hardware specific address.
1425 gceSTATUS
1426 gckVIDMEM_Lock(
1427 IN gckKERNEL Kernel,
1428 IN gcuVIDMEM_NODE_PTR Node,
1429 IN gctBOOL Cacheable,
1430 OUT gctUINT32 * Address
1433 gceSTATUS status;
1434 gctBOOL acquired = gcvFALSE;
1435 gctBOOL locked = gcvFALSE;
1436 gckOS os = gcvNULL;
1438 gcmkHEADER_ARG("Node=0x%x", Node);
1440 /* Verify the arguments. */
1441 gcmkVERIFY_ARGUMENT(Address != gcvNULL);
1443 if ((Node == gcvNULL)
1444 || (Node->VidMem.memory == gcvNULL)
1447 /* Invalid object. */
1448 gcmkONERROR(gcvSTATUS_INVALID_OBJECT);
1451 /**************************** Video Memory ********************************/
1453 if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
1455 if (Cacheable == gcvTRUE)
1457 gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
1460 /* Increment the lock count. */
1461 Node->VidMem.locked ++;
1463 /* Return the address of the node. */
1464 #if !gcdUSE_VIDMEM_PER_PID
1465 *Address = Node->VidMem.memory->baseAddress
1466 + Node->VidMem.offset
1467 + Node->VidMem.alignment;
1468 #else
1469 *Address = Node->VidMem.physical;
1470 #endif
1472 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1473 "Locked node 0x%x (%d) @ 0x%08X",
1474 Node,
1475 Node->VidMem.locked,
1476 *Address);
1479 /*************************** Virtual Memory *******************************/
1481 else
1483 /* Verify the gckKERNEL object pointer. */
1484 gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL);
1486 /* Extract the gckOS object pointer. */
1487 os = Node->Virtual.kernel->os;
1488 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
1490 /* Grab the mutex. */
1491 gcmkONERROR(gckOS_AcquireMutex(os, Node->Virtual.mutex, gcvINFINITE));
1492 acquired = gcvTRUE;
1494 gcmkONERROR(
1495 gckOS_LockPages(os,
1496 Node->Virtual.physical,
1497 Node->Virtual.bytes,
1498 Cacheable,
1499 &Node->Virtual.logical,
1500 &Node->Virtual.pageCount));
1502 /* Increment the lock count. */
1503 if (Node->Virtual.lockeds[Kernel->core] ++ == 0)
1505 /* Is this node pending for a final unlock? */
1506 #ifdef __QNXNTO__
1507 if (!Node->Virtual.contiguous && Node->Virtual.unlockPendings[Kernel->core])
1509 /* Make sure we have a page table. */
1510 gcmkASSERT(Node->Virtual.pageTables[Kernel->core] != gcvNULL);
1512 /* Remove pending unlock. */
1513 Node->Virtual.unlockPendings[Kernel->core] = gcvFALSE;
1516 /* First lock - create a page table. */
1517 gcmkASSERT(Node->Virtual.pageTables[Kernel->core] == gcvNULL);
1519 /* Make sure we mark our node as not flushed. */
1520 Node->Virtual.unlockPendings[Kernel->core] = gcvFALSE;
1521 #endif
1523 locked = gcvTRUE;
1525 if (Node->Virtual.contiguous)
1527 /* Get physical address directly */
1528 gcmkONERROR(gckOS_GetPhysicalAddress(os,
1529 Node->Virtual.logical,
1530 &Node->Virtual.addresses[Kernel->core]));
1532 else
1534 #if gcdENABLE_VG
1535 if (Kernel->vg != gcvNULL)
1537 /* Allocate pages inside the MMU. */
1538 gcmkONERROR(
1539 gckVGMMU_AllocatePages(Kernel->vg->mmu,
1540 Node->Virtual.pageCount,
1541 &Node->Virtual.pageTables[Kernel->core],
1542 &Node->Virtual.addresses[Kernel->core]));
1544 else
1545 #endif
1547 /* Allocate pages inside the MMU. */
1548 gcmkONERROR(
1549 gckMMU_AllocatePages(Kernel->mmu,
1550 Node->Virtual.pageCount,
1551 &Node->Virtual.pageTables[Kernel->core],
1552 &Node->Virtual.addresses[Kernel->core]));
1555 Node->Virtual.lockKernels[Kernel->core] = Kernel;
1557 /* Map the pages. */
1558 #ifdef __QNXNTO__
1559 gcmkONERROR(
1560 gckOS_MapPagesEx(os,
1561 Kernel->core,
1562 Node->Virtual.physical,
1563 Node->Virtual.logical,
1564 Node->Virtual.pageCount,
1565 Node->Virtual.pageTables[Kernel->core]));
1566 #else
1567 gcmkONERROR(
1568 gckOS_MapPagesEx(os,
1569 Kernel->core,
1570 Node->Virtual.physical,
1571 Node->Virtual.pageCount,
1572 Node->Virtual.pageTables[Kernel->core]));
1573 #endif
1576 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1577 "Mapped virtual node 0x%x to 0x%08X",
1578 Node,
1579 Node->Virtual.addresses[Kernel->core]);
1582 /* Return hardware address. */
1583 *Address = Node->Virtual.addresses[Kernel->core];
1585 /* Release the mutex. */
1586 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex));
1589 /* Success. */
1590 gcmkFOOTER_ARG("*Address=%08x", *Address);
1591 return gcvSTATUS_OK;
1593 OnError:
1594 if (locked)
1596 if (Node->Virtual.pageTables[Kernel->core] != gcvNULL)
1598 #if gcdENABLE_VG
1599 if (Kernel->vg != gcvNULL)
1601 /* Free the pages from the MMU. */
1602 gcmkVERIFY_OK(
1603 gckVGMMU_FreePages(Kernel->vg->mmu,
1604 Node->Virtual.pageTables[Kernel->core],
1605 Node->Virtual.pageCount));
1607 else
1608 #endif
1610 /* Free the pages from the MMU. */
1611 gcmkVERIFY_OK(
1612 gckMMU_FreePages(Kernel->mmu,
1613 Node->Virtual.pageTables[Kernel->core],
1614 Node->Virtual.pageCount));
1616 Node->Virtual.pageTables[Kernel->core] = gcvNULL;
1617 Node->Virtual.lockKernels[Kernel->core] = gcvNULL;
1620 /* Unlock the pages. */
1621 gcmkVERIFY_OK(
1622 gckOS_UnlockPages(os,
1623 Node->Virtual.physical,
1624 Node->Virtual.bytes,
1625 Node->Virtual.logical
1628 Node->Virtual.lockeds[Kernel->core]--;
1631 if (acquired)
1633 /* Release the mutex. */
1634 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex));
1637 /* Return the status. */
1638 gcmkFOOTER();
1639 return status;
1642 /*******************************************************************************
1644 ** gckVIDMEM_Unlock
1646 ** Unlock a video memory node.
1648 ** INPUT:
1650 ** gckKERNEL Kernel
1651 ** Pointer to an gckKERNEL object.
1653 ** gcuVIDMEM_NODE_PTR Node
1654 ** Pointer to a locked gcuVIDMEM_NODE union.
1656 ** gceSURF_TYPE Type
1657 ** Type of surface to unlock.
1659 ** gctBOOL * Asynchroneous
1660 ** Pointer to a variable specifying whether the surface should be
1661 ** unlocked asynchroneously or not.
1663 ** OUTPUT:
1665 ** gctBOOL * Asynchroneous
1666 ** Pointer to a variable receiving the number of bytes used in the
1667 ** command buffer specified by 'Commands'. If gcvNULL, there is no
1668 ** command buffer.
1670 gceSTATUS
1671 gckVIDMEM_Unlock(
1672 IN gckKERNEL Kernel,
1673 IN gcuVIDMEM_NODE_PTR Node,
1674 IN gceSURF_TYPE Type,
1675 IN OUT gctBOOL * Asynchroneous
1678 gceSTATUS status;
1679 gckHARDWARE hardware;
1680 gctPOINTER buffer;
1681 gctSIZE_T requested, bufferSize;
1682 gckCOMMAND command = gcvNULL;
1683 gceKERNEL_FLUSH flush;
1684 gckOS os = gcvNULL;
1685 gctBOOL acquired = gcvFALSE;
1686 gctBOOL commitEntered = gcvFALSE;
1687 gctINT32 i, totalLocked;
1689 gcmkHEADER_ARG("Node=0x%x Type=%d *Asynchroneous=%d",
1690 Node, Type, gcmOPT_VALUE(Asynchroneous));
1692 /* Verify the arguments. */
1693 if ((Node == gcvNULL)
1694 || (Node->VidMem.memory == gcvNULL)
1697 /* Invalid object. */
1698 gcmkONERROR(gcvSTATUS_INVALID_OBJECT);
1701 /**************************** Video Memory ********************************/
1703 if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
1705 if (Node->VidMem.locked <= 0)
1707 /* The surface was not locked. */
1708 status = gcvSTATUS_MEMORY_UNLOCKED;
1709 goto OnError;
1712 /* Decrement the lock count. */
1713 Node->VidMem.locked --;
1715 if (Asynchroneous != gcvNULL)
1717 /* No need for any events. */
1718 *Asynchroneous = gcvFALSE;
1721 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1722 "Unlocked node 0x%x (%d)",
1723 Node,
1724 Node->VidMem.locked);
1726 if (Node->VidMem.freePending && (Node->VidMem.locked == 0))
1728 /* Client has unlocked node previously attempted to be freed by compositor. Free now. */
1729 Node->VidMem.freePending = gcvFALSE;
1730 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1731 "Deferred-freeing Node 0x%x.",
1732 Node);
1733 gcmkONERROR(gckVIDMEM_Free(Node));
1737 /*************************** Virtual Memory *******************************/
1739 else
1741 /* Verify the gckHARDWARE object pointer. */
1742 hardware = Kernel->hardware;
1743 gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
1745 /* Verify the gckCOMMAND object pointer. */
1746 command = Kernel->command;
1747 gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND);
1749 /* Get the gckOS object pointer. */
1750 os = Kernel->os;
1751 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
1753 /* Grab the mutex. */
1754 gcmkONERROR(
1755 gckOS_AcquireMutex(os, Node->Virtual.mutex, gcvINFINITE));
1757 acquired = gcvTRUE;
1759 if (Asynchroneous == gcvNULL)
1761 if (Node->Virtual.lockeds[Kernel->core] == 0)
1763 status = gcvSTATUS_MEMORY_UNLOCKED;
1764 goto OnError;
1767 /* Decrement lock count. */
1768 -- Node->Virtual.lockeds[Kernel->core];
1770 /* See if we can unlock the resources. */
1771 if (Node->Virtual.lockeds[Kernel->core] == 0)
1773 /* Free the page table. */
1774 if (Node->Virtual.pageTables[Kernel->core] != gcvNULL)
1776 #if gcdENABLE_VG
1777 if (Kernel->vg != gcvNULL)
1779 gcmkONERROR(
1780 gckVGMMU_FreePages(Kernel->vg->mmu,
1781 Node->Virtual.pageTables[Kernel->core],
1782 Node->Virtual.pageCount));
1784 else
1785 #endif
1787 gcmkONERROR(
1788 gckMMU_FreePages(Kernel->mmu,
1789 Node->Virtual.pageTables[Kernel->core],
1790 Node->Virtual.pageCount));
1792 /* Mark page table as freed. */
1793 Node->Virtual.pageTables[Kernel->core] = gcvNULL;
1794 Node->Virtual.lockKernels[Kernel->core] = gcvNULL;
1797 #ifdef __QNXNTO__
1798 /* Mark node as unlocked. */
1799 Node->Virtual.unlockPendings[Kernel->core] = gcvFALSE;
1800 #endif
1803 for (i = 0, totalLocked = 0; i < gcdCORE_COUNT; i++)
1805 totalLocked += Node->Virtual.lockeds[i];
1808 if (totalLocked == 0)
1810 /* Owner have already freed this node
1811 ** and we are the last one to unlock, do
1812 ** real free */
1813 if (Node->Virtual.freed)
1815 /* Free the virtual memory. */
1816 gcmkVERIFY_OK(gckOS_FreePagedMemory(Kernel->os,
1817 Node->Virtual.physical,
1818 Node->Virtual.bytes));
1820 /* Release mutex before node is destroyed */
1821 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex));
1823 acquired = gcvFALSE;
1825 /* Destroy the gcuVIDMEM_NODE union. */
1826 gcmkVERIFY_OK(gckVIDMEM_DestroyVirtual(Node));
1828 /* Node has been destroyed, so we should not touch it any more */
1829 gcmkFOOTER();
1830 return gcvSTATUS_OK;
1834 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1835 "Unmapped virtual node 0x%x from 0x%08X",
1836 Node, Node->Virtual.addresses[Kernel->core]);
1840 else
1842 /* If we need to unlock a node from virtual memory we have to be
1843 ** very carefull. If the node is still inside the caches we
1844 ** might get a bus error later if the cache line needs to be
1845 ** replaced. So - we have to flush the caches before we do
1846 ** anything. */
1848 /* gckCommand_EnterCommit() can't be called in interrupt handler because
1849 ** of a dead lock situation:
1850 ** process call Command_Commit(), and acquire Command->mutexQueue in
1851 ** gckCOMMAND_EnterCommit(). Then it will wait for a signal which depends
1852 ** on interrupt handler to generate, if interrupt handler enter
1853 ** gckCommand_EnterCommit(), process will never get the signal. */
1855 /* So, flush cache when we still in process context, and then ask caller to
1856 ** schedule a event. */
1858 gcmkONERROR(
1859 gckOS_UnlockPages(os,
1860 Node->Virtual.physical,
1861 Node->Virtual.bytes,
1862 Node->Virtual.logical));
1864 if (!Node->Virtual.contiguous
1865 && (Node->Virtual.lockeds[Kernel->core] == 1)
1868 if (Type == gcvSURF_BITMAP)
1870 /* Flush 2D cache. */
1871 flush = gcvFLUSH_2D;
1873 else if (Type == gcvSURF_RENDER_TARGET)
1875 /* Flush color cache. */
1876 flush = gcvFLUSH_COLOR;
1878 else if (Type == gcvSURF_DEPTH)
1880 /* Flush depth cache. */
1881 flush = gcvFLUSH_DEPTH;
1883 else
1885 /* No flush required. */
1886 flush = (gceKERNEL_FLUSH) 0;
1889 gcmkONERROR(
1890 gckHARDWARE_Flush(hardware, flush, gcvNULL, &requested));
1892 if (requested != 0)
1894 /* Acquire the command queue. */
1895 gcmkONERROR(gckCOMMAND_EnterCommit(command, gcvFALSE));
1896 commitEntered = gcvTRUE;
1898 gcmkONERROR(gckCOMMAND_Reserve(
1899 command, requested, &buffer, &bufferSize
1902 gcmkONERROR(gckHARDWARE_Flush(
1903 hardware, flush, buffer, &bufferSize
1906 /* Mark node as pending. */
1907 #ifdef __QNXNTO__
1908 Node->Virtual.unlockPendings[Kernel->core] = gcvTRUE;
1909 #endif
1911 gcmkONERROR(gckCOMMAND_Execute(command, requested));
1913 /* Release the command queue. */
1914 gcmkONERROR(gckCOMMAND_ExitCommit(command, gcvFALSE));
1915 commitEntered = gcvFALSE;
1919 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
1920 "Scheduled unlock for virtual node 0x%x",
1921 Node);
1923 /* Schedule the surface to be unlocked. */
1924 *Asynchroneous = gcvTRUE;
1927 /* Release the mutex. */
1928 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex));
1930 acquired = gcvFALSE;
1933 /* Success. */
1934 gcmkFOOTER_ARG("*Asynchroneous=%d", gcmOPT_VALUE(Asynchroneous));
1935 return gcvSTATUS_OK;
1937 OnError:
1938 if (commitEntered)
1940 /* Release the command queue mutex. */
1941 gcmkVERIFY_OK(gckCOMMAND_ExitCommit(command, gcvFALSE));
1944 if (acquired)
1946 /* Release the mutex. */
1947 gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex));
1950 /* Return the status. */
1951 gcmkFOOTER();
1952 return status;