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_MMU
26 typedef enum _gceMMU_TYPE
28 gcvMMU_USED = (0 << 4),
29 gcvMMU_SINGLE = (1 << 4),
30 gcvMMU_FREE = (2 << 4),
34 #define gcmENTRY_TYPE(x) (x & 0xF0)
36 #define gcdMMU_TABLE_DUMP 0
38 #define gcdUSE_MMU_EXCEPTION 1
43 The clear value for the entry of the old MMU.
45 #ifndef gcdMMU_CLEAR_VALUE
46 # define gcdMMU_CLEAR_VALUE 0x00000ABC
49 #define gcdVERTEX_START (128 << 10)
51 typedef struct _gcsMMU_STLB *gcsMMU_STLB_PTR;
53 typedef struct _gcsMMU_STLB
55 gctPHYS_ADDR physical;
56 gctUINT32_PTR logical;
61 gctUINT32 mtlbEntryNum;
65 #if gcdSHARED_PAGETABLE
66 typedef struct _gcsSharedPageTable * gcsSharedPageTable_PTR;
67 typedef struct _gcsSharedPageTable
69 /* Shared gckMMU object. */
72 /* Hardwares which use this shared pagetable. */
73 gckHARDWARE hardwares[gcdMAX_GPU_COUNT];
75 /* Number of cores use this shared pagetable. */
80 static gcsSharedPageTable_PTR sharedPageTable = gcvNULL;
83 #if gcdMIRROR_PAGETABLE
84 typedef struct _gcsMirrorPageTable * gcsMirrorPageTable_PTR;
85 typedef struct _gcsMirrorPageTable
88 gckMMU mmus[gcdMAX_GPU_COUNT];
90 /* Hardwares which use this shared pagetable. */
91 gckHARDWARE hardwares[gcdMAX_GPU_COUNT];
93 /* Number of cores use this shared pagetable. */
98 static gcsMirrorPageTable_PTR mirrorPageTable = gcvNULL;
99 static gctPOINTER mirrorPageTableMutex = gcvNULL;
102 typedef struct _gcsDynamicSpaceNode * gcsDynamicSpaceNode_PTR;
103 typedef struct _gcsDynamicSpaceNode
112 IN gctUINT32_PTR PageEntry,
113 IN gctUINT32 EntryValue
116 static gctUINT16 data = 0xff00;
118 if (*(gctUINT8 *)&data == 0xff)
120 *PageEntry = gcmSWAB32(EntryValue);
124 *PageEntry = EntryValue;
130 IN gctUINT32_PTR PageEntry
133 static gctUINT16 data = 0xff00;
134 gctUINT32 entryValue;
136 if (*(gctUINT8 *)&data == 0xff)
138 entryValue = *PageEntry;
139 return gcmSWAB32(entryValue);
149 IN gctUINT32_PTR PageTable,
150 IN gctUINT32 PageCount,
151 IN gctUINT32 EntryValue
156 for (i = 0; i < PageCount; i++)
158 _WritePageEntry(PageTable + i, EntryValue);
171 if (Index >= Mmu->pageTableEntries)
173 /* Just move heap pointer. */
174 Mmu->heapList = Next;
178 /* Address page table. */
179 gctUINT32_PTR map = Mmu->mapLogical;
181 /* Dispatch on node type. */
182 switch (gcmENTRY_TYPE(_ReadPageEntry(&map[Index])))
185 /* Set single index. */
186 _WritePageEntry(&map[Index], (Next << 8) | gcvMMU_SINGLE);
191 _WritePageEntry(&map[Index + 1], Next);
195 gcmkFATAL("MMU table correcupted at index %u!", Index);
196 return gcvSTATUS_HEAP_CORRUPTED;
212 gctUINT32_PTR map = Mmu->mapLogical;
216 /* Initialize a single page node. */
217 _WritePageEntry(map + Node, (~((1U<<8)-1)) | gcvMMU_SINGLE);
221 /* Initialize the node. */
222 _WritePageEntry(map + Node + 0, (Count << 8) | gcvMMU_FREE);
223 _WritePageEntry(map + Node + 1, ~0U);
226 /* Append the node. */
227 return _Link(Mmu, Index, Node);
235 gctUINT32_PTR map = Mmu->mapLogical;
237 gctUINT32 i, previous, start = 0, count = 0;
239 previous = Mmu->heapList = ~0U;
240 Mmu->freeNodes = gcvFALSE;
242 /* Walk the entire page table. */
243 for (i = 0; i < Mmu->pageTableEntries; ++i)
245 /* Dispatch based on type of page. */
246 switch (gcmENTRY_TYPE(_ReadPageEntry(&map[i])))
249 /* Used page, so close any open node. */
253 gcmkONERROR(_AddFree(Mmu, previous, start, count));
255 /* Reset the node. */
262 /* Single free node. */
265 /* Start a new node. */
274 /* Start a new node. */
278 /* Advance the count. */
279 count += _ReadPageEntry(&map[i]) >> 8;
281 /* Advance the index into the page table. */
282 i += (_ReadPageEntry(&map[i]) >> 8) - 1;
286 gcmkFATAL("MMU page table correcupted at index %u!", i);
287 return gcvSTATUS_HEAP_CORRUPTED;
291 /* See if we have an open node left. */
294 /* Add the node to the list. */
295 gcmkONERROR(_AddFree(Mmu, previous, start, count));
298 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_MMU,
299 "Performed a garbage collection of the MMU heap.");
305 /* Return the staus. */
310 _SetPage(gctUINT32 PageAddress)
315 /* Ignore exception */
321 #if gcdPROCESS_ADDRESS_SPACE
328 gctUINT32 mtlbOffset = (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
329 gctUINT32 stlbOffset = (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
331 return (mtlbOffset - Mmu->dynamicMappingStart) * gcdMMU_STLB_4K_ENTRY_NUM + stlbOffset;
339 return (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
347 return (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
353 OUT gcsMMU_STLB_PTR *Stlb
357 gcsMMU_STLB_PTR stlb;
360 /* Allocate slave TLB record. */
361 gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsMMU_STLB), &pointer));
364 stlb->size = gcdMMU_STLB_4K_SIZE;
366 /* Allocate slave TLB entries. */
367 gcmkONERROR(gckOS_AllocateContiguous(
372 (gctPOINTER)&stlb->logical
375 gcmkONERROR(gckOS_GetPhysicalAddress(Os, stlb->logical, &stlb->physBase));
377 #if gcdUSE_MMU_EXCEPTION
378 _FillPageTable(stlb->logical, stlb->size / 4, gcdMMU_STLB_EXCEPTION);
380 gckOS_ZeroMemory(stlb->logical, stlb->size);
392 _SetupProcessAddressSpace(
397 gctINT numEntries = 0;
400 numEntries = gcdPROCESS_ADDRESS_SPACE_SIZE
401 /* Address space mapped by one MTLB entry. */
402 / (1 << gcdMMU_MTLB_SHIFT);
404 Mmu->dynamicMappingStart = 0;
406 Mmu->pageTableSize = numEntries * 4096;
408 Mmu->pageTableEntries = Mmu->pageTableSize / gcmSIZEOF(gctUINT32);
410 gcmkONERROR(gckOS_Allocate(Mmu->os,
412 (void **)&Mmu->mapLogical));
415 map = Mmu->mapLogical;
416 _WritePageEntry(map, (Mmu->pageTableEntries << 8) | gcvMMU_FREE);
417 _WritePageEntry(map + 1, ~0U);
419 Mmu->freeNodes = gcvFALSE;
430 IN gctUINT32 PhysBase,
435 gctBOOL mutex = gcvFALSE;
436 gcsMMU_STLB_PTR head = gcvNULL, pre = gcvNULL;
437 gctUINT32 start = PhysBase & (~gcdMMU_PAGE_64K_MASK);
438 gctUINT32 end = (PhysBase + Size - 1) & (~gcdMMU_PAGE_64K_MASK);
439 gctUINT32 mStart = start >> gcdMMU_MTLB_SHIFT;
440 gctUINT32 mEnd = end >> gcdMMU_MTLB_SHIFT;
441 gctUINT32 sStart = (start & gcdMMU_STLB_64K_MASK) >> gcdMMU_STLB_64K_SHIFT;
442 gctUINT32 sEnd = (end & gcdMMU_STLB_64K_MASK) >> gcdMMU_STLB_64K_SHIFT;
443 gctBOOL ace = gckHARDWARE_IsFeatureAvailable(Mmu->hardware, gcvFEATURE_ACE);
445 /* Grab the mutex. */
446 gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
449 while (mStart <= mEnd)
451 gcmkASSERT(mStart < gcdMMU_MTLB_ENTRY_NUM);
452 if (*(Mmu->mtlbLogical + mStart) == 0)
454 gcsMMU_STLB_PTR stlb;
455 gctPOINTER pointer = gcvNULL;
456 gctUINT32 last = (mStart == mEnd) ? sEnd : (gcdMMU_STLB_64K_ENTRY_NUM - 1);
459 gcmkONERROR(gckOS_Allocate(Mmu->os, sizeof(struct _gcsMMU_STLB), &pointer));
462 stlb->mtlbEntryNum = 0;
463 stlb->next = gcvNULL;
464 stlb->physical = gcvNULL;
465 stlb->logical = gcvNULL;
466 stlb->size = gcdMMU_STLB_64K_SIZE;
475 gcmkASSERT(pre->next == gcvNULL);
481 gckOS_AllocateContiguous(Mmu->os,
485 (gctPOINTER)&stlb->logical));
487 gcmkONERROR(gckOS_ZeroMemory(stlb->logical, stlb->size));
489 gcmkONERROR(gckOS_GetPhysicalAddress(
494 if (stlb->physBase & (gcdMMU_STLB_64K_SIZE - 1))
496 gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
499 mtlbEntry = stlb->physBase
502 /* Ignore exception */
509 mtlbEntry = mtlbEntry
514 _WritePageEntry(Mmu->mtlbLogical + mStart, mtlbEntry);
516 #if gcdMMU_TABLE_DUMP
517 gckOS_Print("%s(%d): insert MTLB[%d]: %08x\n",
518 __FUNCTION__, __LINE__,
520 _ReadPageEntry(Mmu->mtlbLogical + mStart));
523 stlb->mtlbIndex = mStart;
524 stlb->mtlbEntryNum = 1;
525 #if gcdMMU_TABLE_DUMP
526 gckOS_Print("%s(%d): STLB: logical:%08x -> physical:%08x\n",
527 __FUNCTION__, __LINE__,
532 while (sStart <= last)
534 gcmkASSERT(!(start & gcdMMU_PAGE_64K_MASK));
535 _WritePageEntry(stlb->logical + sStart, _SetPage(start));
536 #if gcdMMU_TABLE_DUMP
537 gckOS_Print("%s(%d): insert STLB[%d]: %08x\n",
538 __FUNCTION__, __LINE__,
540 _ReadPageEntry(stlb->logical + sStart));
543 start += gcdMMU_PAGE_64K_SIZE;
553 gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
557 /* Insert the stlb into staticSTLB. */
558 if (Mmu->staticSTLB == gcvNULL)
560 Mmu->staticSTLB = head;
564 gcmkASSERT(pre == gcvNULL);
565 gcmkASSERT(pre->next == gcvNULL);
566 pre->next = Mmu->staticSTLB;
567 Mmu->staticSTLB = head;
570 /* Release the mutex. */
571 gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
578 while (head != gcvNULL)
583 if (pre->physical != gcvNULL)
586 gckOS_FreeContiguous(Mmu->os,
592 if (pre->mtlbEntryNum != 0)
594 gcmkASSERT(pre->mtlbEntryNum == 1);
595 _WritePageEntry(Mmu->mtlbLogical + pre->mtlbIndex, 0);
598 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, pre));
603 /* Release the mutex. */
604 gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
613 OUT gcsDynamicSpaceNode_PTR *Array,
617 gceSTATUS status = gcvSTATUS_OK;
618 gctPOINTER pointer = gcvNULL;
619 gcsDynamicSpaceNode_PTR array = gcvNULL;
621 gctINT i = 0, nodeStart = -1, nodeEntries = 0;
623 /* Allocate memory for the array. */
624 gcmkONERROR(gckOS_Allocate(Mmu->os,
625 gcmSIZEOF(*array) * (gcdMMU_MTLB_ENTRY_NUM / 2),
628 array = (gcsDynamicSpaceNode_PTR)pointer;
630 /* Loop all the entries. */
631 while (i < gcdMMU_MTLB_ENTRY_NUM)
633 if (!Mmu->mtlbLogical[i])
637 /* This is the first entry of the dynamic space. */
643 /* Other entries of the dynamic space. */
647 else if (nodeStart >= 0)
649 /* Save the previous node. */
650 array[size].start = nodeStart;
651 array[size].entries = nodeEntries;
654 /* Reset the start. */
662 /* Save the previous node. */
665 array[size].start = nodeStart;
666 array[size].entries = nodeEntries;
670 #if gcdMMU_TABLE_DUMP
671 for (i = 0; i < size; i++)
673 gckOS_Print("%s(%d): [%d]: start=%d, entries=%d.\n",
674 __FUNCTION__, __LINE__,
687 if (pointer != gcvNULL)
689 gckOS_Free(Mmu->os, pointer);
701 gcsDynamicSpaceNode_PTR nodeArray = gcvNULL;
702 gctINT i, nodeArraySize = 0;
704 gctINT numEntries = 0;
706 gctBOOL acquired = gcvFALSE;
708 gctBOOL ace = gckHARDWARE_IsFeatureAvailable(Mmu->hardware, gcvFEATURE_ACE);
710 /* Find all the dynamic address space. */
711 gcmkONERROR(_FindDynamicSpace(Mmu, &nodeArray, &nodeArraySize));
713 /* TODO: We only use the largest one for now. */
714 for (i = 0; i < nodeArraySize; i++)
716 if (nodeArray[i].entries > numEntries)
718 Mmu->dynamicMappingStart = nodeArray[i].start;
719 numEntries = nodeArray[i].entries;
723 gckOS_Free(Mmu->os, (gctPOINTER)nodeArray);
725 Mmu->pageTableSize = numEntries * 4096;
727 gcmkSAFECASTSIZET(Mmu->pageTableEntries, Mmu->pageTableSize / gcmSIZEOF(gctUINT32));
729 gcmkONERROR(gckOS_Allocate(Mmu->os,
731 (void **)&Mmu->mapLogical));
733 /* Construct Slave TLB. */
734 gcmkONERROR(gckOS_AllocateContiguous(Mmu->os,
737 &Mmu->pageTablePhysical,
738 (gctPOINTER)&Mmu->pageTableLogical));
740 #if gcdUSE_MMU_EXCEPTION
741 gcmkONERROR(_FillPageTable(Mmu->pageTableLogical,
742 Mmu->pageTableEntries,
743 /* Enable exception */
746 /* Invalidate all entries. */
747 gcmkONERROR(gckOS_ZeroMemory(Mmu->pageTableLogical,
748 Mmu->pageTableSize));
752 map = Mmu->mapLogical;
753 _WritePageEntry(map, (Mmu->pageTableEntries << 8) | gcvMMU_FREE);
754 _WritePageEntry(map + 1, ~0U);
756 Mmu->freeNodes = gcvFALSE;
758 gcmkONERROR(gckOS_GetPhysicalAddress(Mmu->os,
759 Mmu->pageTableLogical,
762 /* Grab the mutex. */
763 gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
766 /* Map to Master TLB. */
767 for (i = (gctINT)Mmu->dynamicMappingStart;
768 i < (gctINT)Mmu->dynamicMappingStart + numEntries;
774 /* Ignore exception */
781 mtlbEntry = mtlbEntry
786 _WritePageEntry(Mmu->mtlbLogical + i, mtlbEntry);
788 #if gcdMMU_TABLE_DUMP
789 gckOS_Print("%s(%d): insert MTLB[%d]: %08x\n",
790 __FUNCTION__, __LINE__,
792 _ReadPageEntry(Mmu->mtlbLogical + i));
794 physical += gcdMMU_STLB_4K_SIZE;
797 /* Release the mutex. */
798 gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
806 gckOS_Free(Mmu->os, (gctPOINTER) Mmu->mapLogical));
810 gckOS_FreeContiguous(Mmu->os,
811 Mmu->pageTablePhysical,
812 (gctPOINTER) Mmu->pageTableLogical,
813 Mmu->pageTableSize));
818 /* Release the mutex. */
819 gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
826 /*******************************************************************************
830 ** Construct a new gckMMU object.
835 ** Pointer to an gckKERNEL object.
838 ** Number of bytes for the page table.
843 ** Pointer to a variable that receives the gckMMU object pointer.
848 IN gctSIZE_T MmuSize,
853 gckHARDWARE hardware;
855 gckMMU mmu = gcvNULL;
857 gctPOINTER pointer = gcvNULL;
858 #if gcdPROCESS_ADDRESS_SPACE
864 gctUINT32 gpuAddress;
866 gcmkHEADER_ARG("Kernel=0x%x MmuSize=%lu", Kernel, MmuSize);
868 /* Verify the arguments. */
869 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
870 gcmkVERIFY_ARGUMENT(MmuSize > 0);
871 gcmkVERIFY_ARGUMENT(Mmu != gcvNULL);
873 /* Extract the gckOS object pointer. */
875 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
877 /* Extract the gckHARDWARE object pointer. */
878 hardware = Kernel->hardware;
879 gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
881 /* Allocate memory for the gckMMU object. */
882 gcmkONERROR(gckOS_Allocate(os, sizeof(struct _gckMMU), &pointer));
886 /* Initialize the gckMMU object. */
887 mmu->object.type = gcvOBJ_MMU;
889 mmu->hardware = hardware;
890 mmu->pageTableMutex = gcvNULL;
891 mmu->pageTableLogical = gcvNULL;
892 mmu->mtlbLogical = gcvNULL;
893 mmu->staticSTLB = gcvNULL;
894 mmu->enabled = gcvFALSE;
895 mmu->mapLogical = gcvNULL;
897 /* Create the page table mutex. */
898 gcmkONERROR(gckOS_CreateMutex(os, &mmu->pageTableMutex));
900 if (hardware->mmuVersion == 0)
902 mmu->pageTableSize = MmuSize;
904 /* Construct address space management table. */
905 gcmkONERROR(gckOS_Allocate(mmu->os,
909 mmu->mapLogical = pointer;
911 /* Construct page table read by GPU. */
912 gcmkONERROR(gckOS_AllocateContiguous(mmu->os,
915 &mmu->pageTablePhysical,
916 (gctPOINTER)&mmu->pageTableLogical));
919 /* Compute number of entries in page table. */
920 gcmkSAFECASTSIZET(mmu->pageTableEntries, mmu->pageTableSize / sizeof(gctUINT32));
922 /* Mark all pages as free. */
923 map = mmu->mapLogical;
925 #if gcdMMU_CLEAR_VALUE
926 _FillPageTable(mmu->pageTableLogical, mmu->pageTableEntries, gcdMMU_CLEAR_VALUE);
929 _WritePageEntry(map, (mmu->pageTableEntries << 8) | gcvMMU_FREE);
930 _WritePageEntry(map + 1, ~0U);
932 mmu->freeNodes = gcvFALSE;
936 /* Allocate the 4K mode MTLB table. */
937 mmu->mtlbSize = gcdMMU_MTLB_SIZE + 64;
940 gckOS_AllocateContiguous(os,
946 mmu->mtlbLogical = pointer;
948 #if gcdPROCESS_ADDRESS_SPACE
949 _FillPageTable(pointer, mmu->mtlbSize / 4, gcdMMU_MTLB_EXCEPTION);
951 /* Allocate a array to store stlbs. */
952 gcmkONERROR(gckOS_Allocate(os, mmu->mtlbSize, &mmu->stlbs));
954 gckOS_ZeroMemory(mmu->stlbs, mmu->mtlbSize);
956 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
958 gcmkONERROR(gckOS_AtomConstruct(os, &mmu->pageTableDirty[i]));
961 _SetupProcessAddressSpace(mmu);
963 /* Map kernel command buffer in MMU. */
964 for (i = 0; i < gcdCOMMAND_QUEUES; i++)
966 gcmkONERROR(gckOS_GetPhysicalAddress(
968 Kernel->command->queues[i].logical,
972 gcmkONERROR(gckMMU_FlatMapping(mmu, physical));
975 /* Invalid all the entries. */
977 gckOS_ZeroMemory(pointer, mmu->mtlbSize));
980 gckOS_QueryOption(mmu->os, "physBase", &physBase));
983 gckOS_QueryOption(mmu->os, "physSize", &physSize));
986 gckOS_CPUPhysicalToGPUPhysical(mmu->os, physBase, &gpuAddress));
988 /* Setup [physBase - physSize) flat mapping. */
989 gcmkONERROR(_FillFlatMapping(
995 gcmkONERROR(_SetupDynamicSpace(mmu));
999 /* Return the gckMMU object pointer. */
1003 gcmkFOOTER_ARG("*Mmu=0x%x", *Mmu);
1004 return gcvSTATUS_OK;
1010 if (mmu->mapLogical != gcvNULL)
1013 gckOS_Free(os, (gctPOINTER) mmu->mapLogical));
1017 gckOS_FreeContiguous(os,
1018 mmu->pageTablePhysical,
1019 (gctPOINTER) mmu->pageTableLogical,
1020 mmu->pageTableSize));
1023 if (mmu->mtlbLogical != gcvNULL)
1026 gckOS_FreeContiguous(os,
1028 (gctPOINTER) mmu->mtlbLogical,
1032 if (mmu->pageTableMutex != gcvNULL)
1034 /* Delete the mutex. */
1036 gckOS_DeleteMutex(os, mmu->pageTableMutex));
1039 /* Mark the gckMMU object as unknown. */
1040 mmu->object.type = gcvOBJ_UNKNOWN;
1042 /* Free the allocates memory. */
1043 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, mmu));
1046 /* Return the status. */
1051 /*******************************************************************************
1055 ** Destroy a gckMMU object.
1060 ** Pointer to an gckMMU object.
1071 #if gcdPROCESS_ADDRESS_SPACE
1074 gcmkHEADER_ARG("Mmu=0x%x", Mmu);
1076 /* Verify the arguments. */
1077 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
1079 while (Mmu->staticSTLB != gcvNULL)
1081 gcsMMU_STLB_PTR pre = Mmu->staticSTLB;
1082 Mmu->staticSTLB = pre->next;
1084 if (pre->physical != gcvNULL)
1087 gckOS_FreeContiguous(Mmu->os,
1093 if (pre->mtlbEntryNum != 0)
1095 gcmkASSERT(pre->mtlbEntryNum == 1);
1096 _WritePageEntry(Mmu->mtlbLogical + pre->mtlbIndex, 0);
1097 #if gcdMMU_TABLE_DUMP
1098 gckOS_Print("%s(%d): clean MTLB[%d]\n",
1099 __FUNCTION__, __LINE__,
1104 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, pre));
1107 if (Mmu->hardware->mmuVersion != 0)
1110 gckOS_FreeContiguous(Mmu->os,
1112 (gctPOINTER) Mmu->mtlbLogical,
1116 /* Free address space management table. */
1117 if (Mmu->mapLogical != gcvNULL)
1120 gckOS_Free(Mmu->os, (gctPOINTER) Mmu->mapLogical));
1123 if (Mmu->pageTableLogical != gcvNULL)
1125 /* Free page table. */
1127 gckOS_FreeContiguous(Mmu->os,
1128 Mmu->pageTablePhysical,
1129 (gctPOINTER) Mmu->pageTableLogical,
1130 Mmu->pageTableSize));
1133 /* Delete the page table mutex. */
1134 gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->pageTableMutex));
1136 #if gcdPROCESS_ADDRESS_SPACE
1137 for (i = 0; i < Mmu->mtlbSize / 4; i++)
1139 struct _gcsMMU_STLB *stlb = ((struct _gcsMMU_STLB **)Mmu->stlbs)[i];
1143 gcmkVERIFY_OK(gckOS_FreeContiguous(
1149 gcmkOS_SAFE_FREE(Mmu->os, stlb);
1153 gcmkOS_SAFE_FREE(Mmu->os, Mmu->stlbs);
1156 /* Mark the gckMMU object as unknown. */
1157 Mmu->object.type = gcvOBJ_UNKNOWN;
1159 /* Free the gckMMU object. */
1160 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, Mmu));
1164 return gcvSTATUS_OK;
1167 /*******************************************************************************
1170 ** Adjust the index from which we search for a usable node to make sure
1171 ** index allocated is greater than Start.
1177 IN gctUINT32 PageCount,
1179 OUT gctUINT32 * IndexAdjusted
1183 gctUINT32 index = Index;
1184 gctUINT32_PTR map = Mmu->mapLogical;
1188 for (; index < Mmu->pageTableEntries;)
1190 gctUINT32 result = 0;
1191 gctUINT32 nodeSize = 0;
1198 switch (gcmENTRY_TYPE(map[index]))
1205 nodeSize = map[index] >> 8;
1209 gcmkFATAL("MMU table correcupted at index %u!", index);
1210 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
1213 if (nodeSize > PageCount)
1215 result = index + (nodeSize - PageCount);
1217 if (result >= Start)
1223 switch (gcmENTRY_TYPE(map[index]))
1226 index = map[index] >> 8;
1230 index = map[index + 1];
1234 gcmkFATAL("MMU table correcupted at index %u!", index);
1235 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
1239 *IndexAdjusted = index;
1242 return gcvSTATUS_OK;
1251 IN gckKERNEL Kernel,
1252 IN gctSIZE_T MmuSize,
1256 #if gcdSHARED_PAGETABLE
1260 gcmkHEADER_ARG("Kernel=0x%08x", Kernel);
1262 if (sharedPageTable == gcvNULL)
1265 gckOS_Allocate(Kernel->os,
1266 sizeof(struct _gcsSharedPageTable),
1268 sharedPageTable = pointer;
1271 gckOS_ZeroMemory(sharedPageTable,
1272 sizeof(struct _gcsSharedPageTable)));
1274 gcmkONERROR(_Construct(Kernel, MmuSize, &sharedPageTable->mmu));
1277 *Mmu = sharedPageTable->mmu;
1279 sharedPageTable->hardwares[sharedPageTable->reference] = Kernel->hardware;
1281 sharedPageTable->reference++;
1283 gcmkFOOTER_ARG("sharedPageTable->reference=%lu", sharedPageTable->reference);
1284 return gcvSTATUS_OK;
1287 if (sharedPageTable)
1289 if (sharedPageTable->mmu)
1291 gcmkVERIFY_OK(gckMMU_Destroy(sharedPageTable->mmu));
1294 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, sharedPageTable));
1299 #elif gcdMIRROR_PAGETABLE
1303 gcmkHEADER_ARG("Kernel=0x%08x", Kernel);
1305 if (mirrorPageTable == gcvNULL)
1308 gckOS_Allocate(Kernel->os,
1309 sizeof(struct _gcsMirrorPageTable),
1311 mirrorPageTable = pointer;
1314 gckOS_ZeroMemory(mirrorPageTable,
1315 sizeof(struct _gcsMirrorPageTable)));
1318 gckOS_CreateMutex(Kernel->os, &mirrorPageTableMutex));
1321 gcmkONERROR(_Construct(Kernel, MmuSize, Mmu));
1323 mirrorPageTable->mmus[mirrorPageTable->reference] = *Mmu;
1325 mirrorPageTable->hardwares[mirrorPageTable->reference] = Kernel->hardware;
1327 mirrorPageTable->reference++;
1329 gcmkFOOTER_ARG("mirrorPageTable->reference=%lu", mirrorPageTable->reference);
1330 return gcvSTATUS_OK;
1333 if (mirrorPageTable && mirrorPageTable->reference == 0)
1335 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, mirrorPageTable));
1341 return _Construct(Kernel, MmuSize, Mmu);
1350 #if gcdSHARED_PAGETABLE
1353 sharedPageTable->reference--;
1355 if (sharedPageTable->reference == 0)
1357 if (sharedPageTable->mmu)
1359 gcmkVERIFY_OK(_Destroy(Mmu));
1362 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, sharedPageTable));
1365 return gcvSTATUS_OK;
1366 #elif gcdMIRROR_PAGETABLE
1367 mirrorPageTable->reference--;
1369 if (mirrorPageTable->reference == 0)
1371 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, mirrorPageTable));
1372 gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, mirrorPageTableMutex));
1375 return _Destroy(Mmu);
1377 return _Destroy(Mmu);
1381 /*******************************************************************************
1383 ** gckMMU_AllocatePages
1385 ** Allocate pages inside the page table.
1390 ** Pointer to an gckMMU object.
1392 ** gctSIZE_T PageCount
1393 ** Number of pages to allocate.
1397 ** gctPOINTER * PageTable
1398 ** Pointer to a variable that receives the base address of the page
1401 ** gctUINT32 * Address
1402 ** Pointer to a variable that receives the hardware specific address.
1407 IN gctSIZE_T PageCount,
1408 IN gceSURF_TYPE Type,
1409 OUT gctPOINTER * PageTable,
1410 OUT gctUINT32 * Address
1414 gctBOOL mutex = gcvFALSE;
1415 gctUINT32 index = 0, previous = ~0U, left;
1419 gctUINT32 pageCount;
1421 gcmkHEADER_ARG("Mmu=0x%x PageCount=%lu", Mmu, PageCount);
1423 /* Verify the arguments. */
1424 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
1425 gcmkVERIFY_ARGUMENT(PageCount > 0);
1426 gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
1428 if (PageCount > Mmu->pageTableEntries)
1430 /* Not enough pages avaiable. */
1431 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
1434 gcmkSAFECASTSIZET(pageCount, PageCount);
1436 /* Grab the mutex. */
1437 gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
1440 /* Cast pointer to page table. */
1441 for (map = Mmu->mapLogical, gotIt = gcvFALSE; !gotIt;)
1443 index = Mmu->heapList;
1445 if ((Mmu->hardware->mmuVersion == 0) && (Type == gcvSURF_VERTEX))
1447 gcmkONERROR(_AdjustIndex(
1451 gcdVERTEX_START / gcmSIZEOF(gctUINT32),
1456 /* Walk the heap list. */
1457 for (; !gotIt && (index < Mmu->pageTableEntries);)
1459 /* Check the node type. */
1460 switch (gcmENTRY_TYPE(_ReadPageEntry(&map[index])))
1463 /* Single odes are valid if we only need 1 page. */
1470 /* Move to next node. */
1472 index = _ReadPageEntry(&map[index]) >> 8;
1477 /* Test if the node has enough space. */
1478 if (pageCount <= (_ReadPageEntry(&map[index]) >> 8))
1484 /* Move to next node. */
1486 index = _ReadPageEntry(&map[index + 1]);
1491 gcmkFATAL("MMU table correcupted at index %u!", index);
1492 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
1496 /* Test if we are out of memory. */
1497 if (index >= Mmu->pageTableEntries)
1501 /* Time to move out the trash! */
1502 gcmkONERROR(_Collect(Mmu));
1506 /* Out of resources. */
1507 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
1512 switch (gcmENTRY_TYPE(_ReadPageEntry(&map[index])))
1515 /* Unlink single node from free list. */
1517 _Link(Mmu, previous, _ReadPageEntry(&map[index]) >> 8));
1521 /* Check how many pages will be left. */
1522 left = (_ReadPageEntry(&map[index]) >> 8) - pageCount;
1526 /* The entire node is consumed, just unlink it. */
1528 _Link(Mmu, previous, _ReadPageEntry(&map[index + 1])));
1532 /* One page will remain. Convert the node to a single node and
1533 ** advance the index. */
1534 _WritePageEntry(&map[index], (_ReadPageEntry(&map[index + 1]) << 8) | gcvMMU_SINGLE);
1539 /* Enough pages remain for a new node. However, we will just adjust
1540 ** the size of the current node and advance the index. */
1541 _WritePageEntry(&map[index], (left << 8) | gcvMMU_FREE);
1548 /* Mark node as used. */
1549 gcmkONERROR(_FillPageTable(&map[index], pageCount, gcvMMU_USED));
1551 /* Return pointer to page table. */
1552 *PageTable = &Mmu->pageTableLogical[index];
1554 /* Build virtual address. */
1555 if (Mmu->hardware->mmuVersion == 0)
1558 gckHARDWARE_BuildVirtualAddress(Mmu->hardware, index, 0, &address));
1562 gctUINT32 masterOffset = index / gcdMMU_STLB_4K_ENTRY_NUM
1563 + Mmu->dynamicMappingStart;
1564 gctUINT32 slaveOffset = index % gcdMMU_STLB_4K_ENTRY_NUM;
1566 address = (masterOffset << gcdMMU_MTLB_SHIFT)
1567 | (slaveOffset << gcdMMU_STLB_4K_SHIFT);
1570 if (Address != gcvNULL)
1575 /* Release the mutex. */
1576 gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
1579 gcmkFOOTER_ARG("*PageTable=0x%x *Address=%08x",
1580 *PageTable, gcmOPT_VALUE(Address));
1581 return gcvSTATUS_OK;
1587 /* Release the mutex. */
1588 gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
1591 /* Return the status. */
1596 /*******************************************************************************
1600 ** Free pages inside the page table.
1605 ** Pointer to an gckMMU object.
1607 ** gctPOINTER PageTable
1608 ** Base address of the page table to free.
1610 ** gctSIZE_T PageCount
1611 ** Number of pages to free.
1620 IN gctPOINTER PageTable,
1621 IN gctSIZE_T PageCount
1626 gctBOOL acquired = gcvFALSE;
1627 gctUINT32 pageCount;
1629 gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=%lu",
1630 Mmu, PageTable, PageCount);
1632 /* Verify the arguments. */
1633 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
1634 gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
1635 gcmkVERIFY_ARGUMENT(PageCount > 0);
1637 gcmkSAFECASTSIZET(pageCount, PageCount);
1639 /* Get the node by index. */
1640 node = Mmu->mapLogical + ((gctUINT32_PTR)PageTable - Mmu->pageTableLogical);
1642 gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
1645 #if gcdMMU_CLEAR_VALUE
1646 if (Mmu->hardware->mmuVersion == 0)
1648 _FillPageTable(PageTable, pageCount, gcdMMU_CLEAR_VALUE);
1654 /* Single page node. */
1655 _WritePageEntry(node, (~((1U<<8)-1)) | gcvMMU_SINGLE);
1656 #if gcdUSE_MMU_EXCEPTION
1657 /* Enable exception */
1658 _WritePageEntry(PageTable, (1 << 1));
1663 /* Mark the node as free. */
1664 _WritePageEntry(node, (pageCount << 8) | gcvMMU_FREE);
1665 _WritePageEntry(node + 1, ~0U);
1667 #if gcdUSE_MMU_EXCEPTION
1668 /* Enable exception */
1669 gcmkVERIFY_OK(_FillPageTable(PageTable, pageCount, 1 << 1));
1673 /* We have free nodes. */
1674 Mmu->freeNodes = gcvTRUE;
1676 gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
1677 acquired = gcvFALSE;
1681 return gcvSTATUS_OK;
1686 gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
1694 gckMMU_AllocatePages(
1696 IN gctSIZE_T PageCount,
1697 OUT gctPOINTER * PageTable,
1698 OUT gctUINT32 * Address
1701 return gckMMU_AllocatePagesEx(
1702 Mmu, PageCount, gcvSURF_TYPE_UNKNOWN, PageTable, Address);
1706 gckMMU_AllocatePagesEx(
1708 IN gctSIZE_T PageCount,
1709 IN gceSURF_TYPE Type,
1710 OUT gctPOINTER * PageTable,
1711 OUT gctUINT32 * Address
1714 #if gcdMIRROR_PAGETABLE
1716 gctPOINTER pageTable;
1720 gctBOOL acquired = gcvFALSE;
1721 gctBOOL allocated = gcvFALSE;
1723 gckOS_AcquireMutex(Mmu->os, mirrorPageTableMutex, gcvINFINITE);
1726 /* Allocate page table for current MMU. */
1727 for (i = 0; i < (gctINT)mirrorPageTable->reference; i++)
1729 if (Mmu == mirrorPageTable->mmus[i])
1731 gcmkONERROR(_AllocatePages(Mmu, PageCount, Type, PageTable, Address));
1732 allocated = gcvTRUE;
1736 /* Allocate page table for other MMUs. */
1737 for (i = 0; i < (gctINT)mirrorPageTable->reference; i++)
1739 mmu = mirrorPageTable->mmus[i];
1743 gcmkONERROR(_AllocatePages(mmu, PageCount, Type, &pageTable, &address));
1744 gcmkASSERT(address == *Address);
1748 gckOS_ReleaseMutex(Mmu->os, mirrorPageTableMutex);
1749 acquired = gcvFALSE;
1751 return gcvSTATUS_OK;
1756 /* Page tables for multiple GPU always keep the same. So it is impossible
1757 * the fist one allocates successfully but others fail.
1764 gckOS_ReleaseMutex(Mmu->os, mirrorPageTableMutex);
1769 return _AllocatePages(Mmu, PageCount, Type, PageTable, Address);
1776 IN gctPOINTER PageTable,
1777 IN gctSIZE_T PageCount
1780 #if gcdMIRROR_PAGETABLE
1785 gckOS_AcquireMutex(Mmu->os, mirrorPageTableMutex, gcvINFINITE);
1787 gcmkVERIFY_OK(_FreePages(Mmu, PageTable, PageCount));
1789 offset = (gctUINT32)PageTable - (gctUINT32)Mmu->pageTableLogical;
1791 for (i = 0; i < (gctINT)mirrorPageTable->reference; i++)
1793 mmu = mirrorPageTable->mmus[i];
1797 gcmkVERIFY_OK(_FreePages(mmu, mmu->pageTableLogical + offset/4, PageCount));
1801 gckOS_ReleaseMutex(Mmu->os, mirrorPageTableMutex);
1803 return gcvSTATUS_OK;
1805 return _FreePages(Mmu, PageTable, PageCount);
1812 IN gctUINT32 PageAddress,
1813 IN gctUINT32 *PageEntry
1816 #if gcdMIRROR_PAGETABLE
1817 gctUINT32_PTR pageEntry;
1820 gctUINT32 offset = (gctUINT32)PageEntry - (gctUINT32)Mmu->pageTableLogical;
1823 gcmkHEADER_ARG("Mmu=0x%x", Mmu);
1825 /* Verify the arguments. */
1826 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
1827 gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL);
1828 gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF));
1830 if (Mmu->hardware->mmuVersion == 0)
1832 _WritePageEntry(PageEntry, PageAddress);
1836 _WritePageEntry(PageEntry, _SetPage(PageAddress));
1839 #if gcdMIRROR_PAGETABLE
1840 for (i = 0; i < (gctINT)mirrorPageTable->reference; i++)
1842 mmu = mirrorPageTable->mmus[i];
1846 pageEntry = mmu->pageTableLogical + offset / 4;
1848 if (mmu->hardware->mmuVersion == 0)
1850 _WritePageEntry(pageEntry, PageAddress);
1854 _WritePageEntry(pageEntry, _SetPage(PageAddress));
1863 return gcvSTATUS_OK;
1866 #if gcdPROCESS_ADDRESS_SPACE
1868 gckMMU_GetPageEntry(
1870 IN gctUINT32 Address,
1871 IN gctUINT32_PTR *PageTable
1875 struct _gcsMMU_STLB *stlb;
1876 struct _gcsMMU_STLB **stlbs = Mmu->stlbs;
1877 gctUINT32 offset = _MtlbOffset(Address);
1878 gctUINT32 mtlbEntry;
1879 gctBOOL ace = gckHARDWARE_IsFeatureAvailable(Mmu->hardware, gcvFEATURE_ACE);
1881 gcmkHEADER_ARG("Mmu=0x%x", Mmu);
1883 /* Verify the arguments. */
1884 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
1885 gcmkVERIFY_ARGUMENT((Address & 0xFFF) == 0);
1887 stlb = stlbs[offset];
1889 if (stlb == gcvNULL)
1891 gcmkONERROR(_AllocateStlb(Mmu->os, &stlb));
1893 mtlbEntry = stlb->physBase
1894 | gcdMMU_MTLB_4K_PAGE
1895 | gcdMMU_MTLB_PRESENT
1900 mtlbEntry = mtlbEntry
1905 /* Insert Slave TLB address to Master TLB entry.*/
1906 _WritePageEntry(Mmu->mtlbLogical + offset, mtlbEntry);
1909 stlbs[offset] = stlb;
1912 *PageTable = &stlb->logical[_StlbOffset(Address)];
1916 return gcvSTATUS_OK;
1929 gctUINT32_PTR map = Mmu->mapLogical;
1932 for (index = Mmu->heapList; index < Mmu->pageTableEntries;)
1934 /* Check the node type. */
1935 switch (gcmENTRY_TYPE(_ReadPageEntry(&map[index])))
1938 /* Move to next node. */
1939 index = _ReadPageEntry(&map[index]) >> 8;
1943 /* Move to next node. */
1944 index = _ReadPageEntry(&map[index + 1]);
1948 gcmkFATAL("MMU table correcupted at index [%u] = %x!", index, map[index]);
1949 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
1953 return gcvSTATUS_OK;
1962 IN gctUINT32 Physical
1966 gctUINT32 index = _AddressToIndex(Mmu, Physical);
1968 gctBOOL gotIt = gcvFALSE;
1969 gctUINT32_PTR map = Mmu->mapLogical;
1970 gctUINT32 previous = ~0U;
1971 gctUINT32_PTR pageTable;
1973 gckMMU_GetPageEntry(Mmu, Physical, &pageTable);
1975 _WritePageEntry(pageTable, _SetPage(Physical));
1979 /* Find node which contains index. */
1980 for (i = 0; !gotIt && (i < Mmu->pageTableEntries);)
1984 switch (gcmENTRY_TYPE(_ReadPageEntry(&map[i])))
1994 i = _ReadPageEntry(&map[i]) >> 8;
1999 numPages = _ReadPageEntry(&map[i]) >> 8;
2000 if (index >= i && index < i + numPages)
2007 i = _ReadPageEntry(&map[i + 1]);
2012 gcmkFATAL("MMU table correcupted at index %u!", index);
2013 gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
2017 switch (gcmENTRY_TYPE(_ReadPageEntry(&map[i])))
2020 /* Unlink single node from free list. */
2022 _Link(Mmu, previous, _ReadPageEntry(&map[i]) >> 8));
2026 /* Split the node. */
2029 gctUINT32 next = _ReadPageEntry(&map[i+1]);
2030 gctUINT32 total = _ReadPageEntry(&map[i]) >> 8;
2031 gctUINT32 countLeft = index - i;
2032 gctUINT32 countRight = total - countLeft - 1;
2037 _AddFree(Mmu, previous, start, countLeft);
2044 _AddFree(Mmu, previous, start, countRight);
2048 _Link(Mmu, previous, next);
2054 return gcvSTATUS_OK;
2067 IN gctUINT32 Address,
2068 IN gctSIZE_T PageCount
2074 #if gcdUSE_MMU_EXCEPTION
2076 struct _gcsMMU_STLB *stlb;
2077 struct _gcsMMU_STLB **stlbs = Mmu->stlbs;
2080 gcmkHEADER_ARG("Mmu=0x%x Address=0x%x PageCount=%lu",
2081 Mmu, Address, PageCount);
2083 /* Verify the arguments. */
2084 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
2085 gcmkVERIFY_ARGUMENT(PageCount > 0);
2087 /* Get the node by index. */
2088 node = Mmu->mapLogical + _AddressToIndex(Mmu, Address);
2090 gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
2094 /* Single page node. */
2095 _WritePageEntry(node, (~((1U<<8)-1)) | gcvMMU_SINGLE);
2099 /* Mark the node as free. */
2100 _WritePageEntry(node, (PageCount << 8) | gcvMMU_FREE);
2101 _WritePageEntry(node + 1, ~0U);
2104 /* We have free nodes. */
2105 Mmu->freeNodes = gcvTRUE;
2107 #if gcdUSE_MMU_EXCEPTION
2108 for (i = 0; i < PageCount; i++)
2111 stlb = stlbs[_MtlbOffset(Address)];
2113 /* Enable exception */
2114 stlb->logical[_StlbOffset(Address)] = gcdMMU_STLB_EXCEPTION;
2118 gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
2123 return gcvSTATUS_OK;
2134 IN gceSURF_TYPE Type
2137 gckHARDWARE hardware;
2141 if (Type == gcvSURF_VERTEX || Type == gcvSURF_INDEX)
2143 mask = gcvPAGE_TABLE_DIRTY_BIT_FE;
2147 mask = gcvPAGE_TABLE_DIRTY_BIT_OTHER;
2150 #if gcdPROCESS_ADDRESS_SPACE
2151 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
2154 gckOS_AtomSetMask(Mmu->pageTableDirty[i], mask));
2157 #if gcdSHARED_PAGETABLE
2158 for (i = 0; i < gcdMAX_GPU_COUNT; i++)
2160 hardware = sharedPageTable->hardwares[i];
2163 gcmkVERIFY_OK(gckOS_AtomSetMask(hardware->pageTableDirty, mask));
2166 #elif gcdMIRROR_PAGETABLE
2167 for (i = 0; i < (gctINT)mirrorPageTable->reference; i++)
2169 hardware = mirrorPageTable->hardwares[i];
2171 /* Notify cores who use this page table. */
2173 gckOS_AtomSetMask(hardware->pageTableDirty, mask));
2176 hardware = Mmu->hardware;
2178 gckOS_AtomSetMask(hardware->pageTableDirty, mask));
2182 return gcvSTATUS_OK;
2186 gckMMU_DumpPageTableEntry(
2188 IN gctUINT32 Address
2191 #if gcdPROCESS_ADDRESS_SPACE
2192 gcsMMU_STLB_PTR *stlbs = Mmu->stlbs;
2193 gcsMMU_STLB_PTR stlbDesc = stlbs[_MtlbOffset(Address)];
2195 gctUINT32_PTR pageTable;
2197 gctUINT32 mtlb, stlb;
2200 gcmkHEADER_ARG("Mmu=0x%08X Address=0x%08X", Mmu, Address);
2201 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
2203 gcmkASSERT(Mmu->hardware->mmuVersion > 0);
2205 #if gcdPROCESS_ADDRESS_SPACE
2208 gcmkPRINT(" STLB entry = 0x%08X",
2209 _ReadPageEntry(&stlbDesc->logical[_StlbOffset(Address)]));
2213 gcmkPRINT(" MTLB entry is empty.");
2216 mtlb = (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
2218 if (mtlb >= Mmu->dynamicMappingStart)
2220 stlb = (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
2222 pageTable = Mmu->pageTableLogical;
2224 index = (mtlb - Mmu->dynamicMappingStart)
2225 * gcdMMU_STLB_4K_ENTRY_NUM
2228 gcmkPRINT(" Page table entry = 0x%08X", _ReadPageEntry(pageTable + index));
2232 gcsMMU_STLB_PTR stlbObj = Mmu->staticSTLB;
2233 gctUINT32 entry = Mmu->mtlbLogical[mtlb];
2235 stlb = (Address & gcdMMU_STLB_64K_MASK) >> gcdMMU_STLB_64K_SHIFT;
2237 entry &= 0xFFFFFFF0;
2242 if (entry == stlbObj->physBase)
2244 gcmkPRINT(" Page table entry = 0x%08X", stlbObj->logical[stlb]);
2248 stlbObj = stlbObj->next;
2254 return gcvSTATUS_OK;
2257 /******************************************************************************
2258 ****************************** T E S T C O D E ******************************
2259 ******************************************************************************/