summaryrefslogtreecommitdiff
path: root/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c
diff options
context:
space:
mode:
authorLoren Huang <b02279@freescale.com>2012-03-16 15:29:06 +0800
committerJason Liu <r64343@freescale.com>2012-07-20 13:24:15 +0800
commit217856f4c04b3ea8e964cf591414d561c50fb0dd (patch)
tree7b7b2c70808839658524cfc2170ef2be708ff3cf /drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c
parentb6cd59a82130ec0c7e1ac56deec1b60e02114612 (diff)
ENGR00177048 Merge vivante 4.6.6 kernel part code
Merge vivante 4.6.6 kernel part code Signed-off-by: Loren Huang <b02279@freescale.com> Acked-by: Lily Zhang
Diffstat (limited to 'drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c')
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c941
1 files changed, 407 insertions, 534 deletions
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c
index b25e2ef460da..cf34118d5c66 100644
--- a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c
@@ -27,14 +27,25 @@
typedef enum _gceMMU_TYPE
{
- gcvMMU_USED = 0,
- gcvMMU_SINGLE,
- gcvMMU_FREE,
+ gcvMMU_USED = (0 << 4),
+ gcvMMU_SINGLE = (1 << 4),
+ gcvMMU_FREE = (2 << 4),
}
gceMMU_TYPE;
+#define gcmENTRY_TYPE(x) (x & 0xF0)
+
#define gcdMMU_TABLE_DUMP 0
+/*
+ gcdMMU_CLEAR_VALUE
+
+ The clear value for the entry of the old MMU.
+*/
+#ifndef gcdMMU_CLEAR_VALUE
+# define gcdMMU_CLEAR_VALUE 0x00000ABC
+#endif
+
typedef struct _gcsMMU_STLB *gcsMMU_STLB_PTR;
typedef struct _gcsMMU_STLB
@@ -49,140 +60,22 @@ typedef struct _gcsMMU_STLB
gcsMMU_STLB_PTR next;
} gcsMMU_STLB;
-#define gcvMMU_STLB_SIZE gcmALIGN(sizeof(gcsMMU_STLB), 4)
-
#if gcdSHARED_PAGETABLE
typedef struct _gcsSharedPageTable * gcsSharedPageTable_PTR;
typedef struct _gcsSharedPageTable
{
- /* Logical of shared pagetable. */
- gctPOINTER logical;
-
- /* Physical of shared pagetable. */
- gctPHYS_ADDR physical;
-
- /* Number of cores use this shared pagetable. */
- gctUINT32 reference;
-
- /* Mutex to protect this shared pagetable. */
- gctPOINTER mutex;
+ /* Shared gckMMU object. */
+ gckMMU mmu;
/* Hardwares which use this shared pagetable. */
gckHARDWARE hardwares[gcdCORE_COUNT];
- /* flat mapping flags. Only useful for new MMU. */
- gctBOOL flatMappingSetup;
+ /* Number of cores use this shared pagetable. */
+ gctUINT32 reference;
}
gcsSharedPageTable;
static gcsSharedPageTable_PTR sharedPageTable = gcvNULL;
-
-static gceSTATUS
-_Free(
- IN gckMMU Mmu
- )
-{
- sharedPageTable->reference--;
-
- if (sharedPageTable->reference == 0)
- {
- if (sharedPageTable->logical)
- {
- gcmkVERIFY_OK(
- gckOS_FreeContiguous(Mmu->os,
- sharedPageTable->physical,
- (gctPOINTER) sharedPageTable->logical,
- Mmu->pageTableSize));
- }
-
- if (sharedPageTable->mutex)
- {
- gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, sharedPageTable->mutex));
- }
-
- gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, sharedPageTable));
- }
-
- return gcvSTATUS_OK;
-}
-
-static gceSTATUS
-_Construct(
- IN gckMMU Mmu
- )
-{
- gceSTATUS status;
- gctPOINTER pointer;
- gctPHYS_ADDR physical;
-
- gcmkHEADER_ARG("Mmu=%lu", Mmu);
-
- if (sharedPageTable == gcvNULL)
- {
- gcmkONERROR(
- gckOS_Allocate(Mmu->os,
- sizeof(struct _gcsSharedPageTable),
- &pointer));
- sharedPageTable = pointer;
-
- gcmkONERROR(
- gckOS_ZeroMemory(sharedPageTable,
- sizeof(struct _gcsSharedPageTable)));
-
- /* Create shared page table. */
- gcmkONERROR(
- gckOS_AllocateContiguous(Mmu->os,
- gcvFALSE,
- &Mmu->pageTableSize,
- &physical,
- &pointer));
-
- sharedPageTable->logical = pointer;
- sharedPageTable->physical = physical;
-
- /* Create the page table mutex. */
- gcmkONERROR(gckOS_CreateMutex(Mmu->os, &sharedPageTable->mutex));
-
- /* Invalid all the entries. */
- gcmkONERROR(
- gckOS_ZeroMemory(sharedPageTable->logical, Mmu->pageTableSize));
- }
-
- Mmu->pageTableLogical = sharedPageTable->logical;
- Mmu->pageTablePhysical = sharedPageTable->physical;
- Mmu->pageTableMutex = sharedPageTable->mutex;
-
- sharedPageTable->hardwares[sharedPageTable->reference] = Mmu->hardware;
-
- sharedPageTable->reference++;
-
- gcmkFOOTER_ARG("sharedPageTable->reference=%lu", sharedPageTable->reference);
- return gcvSTATUS_OK;
-
-OnError:
- if (sharedPageTable)
- {
- if (sharedPageTable->logical)
- {
- gcmkVERIFY_OK(
- gckOS_FreeContiguous(Mmu->os,
- sharedPageTable->physical,
- (gctPOINTER) sharedPageTable->logical,
- Mmu->pageTableSize));
- }
-
- if (sharedPageTable->mutex)
- {
- gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, sharedPageTable->mutex));
- }
-
- gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, sharedPageTable));
- }
-
- gcmkFOOTER();
- return status;
-}
-
#endif
static gceSTATUS
@@ -203,7 +96,7 @@ _Link(
gctUINT32_PTR pageTable = Mmu->pageTableLogical;
/* Dispatch on node type. */
- switch (pageTable[Index] & 0xFF)
+ switch (gcmENTRY_TYPE(pageTable[Index]))
{
case gcvMMU_SINGLE:
/* Set single index. */
@@ -260,10 +153,6 @@ _Collect(
gceSTATUS status;
gctUINT32 i, previous, start = 0, count = 0;
- /* Flush the MMU cache. */
- gcmkONERROR(
- gckHARDWARE_FlushMMU(Mmu->hardware));
-
previous = Mmu->heapList = ~0U;
Mmu->freeNodes = gcvFALSE;
@@ -271,7 +160,7 @@ _Collect(
for (i = 0; i < Mmu->pageTableEntries; ++i)
{
/* Dispatch based on type of page. */
- switch (pageTable[i] & 0xFF)
+ switch (gcmENTRY_TYPE(pageTable[i]))
{
case gcvMMU_USED:
/* Used page, so close any open node. */
@@ -334,78 +223,6 @@ OnError:
return status;
}
-static gceSTATUS
-_GetStlb(
- IN gckMMU Mmu,
- IN gctSIZE_T PageCount,
- OUT gcsMMU_STLB_PTR *Stlb
- )
-{
- gceSTATUS status;
- gcsMMU_STLB_PTR stlb = gcvNULL;
- gctPHYS_ADDR physical;
- gctPOINTER logical = gcvNULL;
- gctSIZE_T size = (PageCount << 2) + gcvMMU_STLB_SIZE;
- gctUINT32 address;
-
- gcmkONERROR(
- gckOS_AllocateContiguous(Mmu->os,
- gcvFALSE,
- &size,
- &physical,
- &logical));
-
- gcmkONERROR(gckOS_ZeroMemory(logical, size));
-
- /* Convert logical address into a physical address. */
- gcmkONERROR(
- gckOS_GetPhysicalAddress(Mmu->os, logical, &address));
-
- stlb = (gcsMMU_STLB_PTR)logical;
- stlb->pageCount = PageCount;
- stlb->logical = logical;
- stlb->physical = physical;
- stlb->physBase = address;
- stlb->size = size;
- stlb->mtlbIndex = ~0U;
- stlb->mtlbEntryNum = 0;
- stlb->next = gcvNULL;
-
- *Stlb = stlb;
-
- return gcvSTATUS_OK;
-
-OnError:
-
- if (logical != gcvNULL)
- {
- gckOS_FreeContiguous(
- Mmu->os,
- physical,
- logical,
- size
- );
- }
-
- return status;
-}
-
-static gceSTATUS
-_PutStlb(
- IN gckMMU Mmu,
- IN gcsMMU_STLB_PTR Stlb
- )
-{
- gcmkASSERT(Stlb->logical == (gctPOINTER)Stlb);
-
- return gckOS_FreeContiguous(
- Mmu->os,
- Stlb->physical,
- Stlb,
- Stlb->size
- );
-}
-
static gctUINT32
_SetPage(gctUINT32 PageAddress)
{
@@ -435,15 +252,6 @@ _FillFlatMapping(
gctUINT32 sStart = (start & gcdMMU_STLB_64K_MASK) >> gcdMMU_STLB_64K_SHIFT;
gctUINT32 sEnd = (end & gcdMMU_STLB_64K_MASK) >> gcdMMU_STLB_64K_SHIFT;
-#if gcdSHARED_PAGETABLE
- if (sharedPageTable->flatMappingSetup == gcvTRUE)
- {
- gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_MMU,
- "flat mapping has been created by another core");
- return gcvSTATUS_OK;
- }
-#endif
-
/* Grab the mutex. */
gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
mutex = gcvTRUE;
@@ -451,7 +259,7 @@ _FillFlatMapping(
while (mStart <= mEnd)
{
gcmkASSERT(mStart < gcdMMU_MTLB_ENTRY_NUM);
- if (*(Mmu->pageTableLogical + mStart) == 0)
+ if (*(Mmu->mtlbLogical + mStart) == 0)
{
gcsMMU_STLB_PTR stlb;
gctPOINTER pointer = gcvNULL;
@@ -497,7 +305,7 @@ _FillFlatMapping(
gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
}
- *(Mmu->pageTableLogical + mStart)
+ *(Mmu->mtlbLogical + mStart)
= stlb->physBase
/* 64KB page size */
| (1 << 2)
@@ -509,7 +317,7 @@ _FillFlatMapping(
gckOS_Print("%s(%d): insert MTLB[%d]: %08x\n",
__FUNCTION__, __LINE__,
mStart,
- *(Mmu->pageTableLogical + mStart));
+ *(Mmu->mtlbLogical + mStart));
#endif
stlb->mtlbIndex = mStart;
@@ -553,7 +361,7 @@ _FillFlatMapping(
}
else
{
- gcmkASSERT(pre == gcvNULL);
+ gcmkASSERT(pre == gcvNULL);
gcmkASSERT(pre->next == gcvNULL);
pre->next = Mmu->staticSTLB;
Mmu->staticSTLB = head;
@@ -562,9 +370,6 @@ _FillFlatMapping(
/* Release the mutex. */
gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
-#if gcdSHARED_PAGETABLE
- sharedPageTable->flatMappingSetup = gcvTRUE;
-#endif
return gcvSTATUS_OK;
OnError:
@@ -587,7 +392,7 @@ OnError:
if (pre->mtlbEntryNum != 0)
{
gcmkASSERT(pre->mtlbEntryNum == 1);
- *(Mmu->pageTableLogical + pre->mtlbIndex) = 0;
+ *(Mmu->mtlbLogical + pre->mtlbIndex) = 0;
}
gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, pre));
@@ -602,9 +407,109 @@ OnError:
return status;
}
+static gceSTATUS
+_SetupDynamicSpace(
+ IN gckMMU Mmu
+ )
+{
+ gceSTATUS status;
+ gctINT i;
+ gctUINT32 physical;
+ gctINT numEntries;
+ gctUINT32_PTR pageTable;
+ gctBOOL acquired = gcvFALSE;
+
+ /* find the start of dynamic address space. */
+ for (i = 0; i < gcdMMU_MTLB_ENTRY_NUM; i++)
+ {
+ if (!Mmu->mtlbLogical[i])
+ {
+ break;
+ }
+ }
+
+ Mmu->dynamicMappingStart = i;
+
+ /* Number of entries in Master TLB for dynamic mapping. */
+ numEntries = gcdMMU_MTLB_ENTRY_NUM - i;
+
+ Mmu->pageTableSize = numEntries * 4096;
+
+ Mmu->pageTableEntries = Mmu->pageTableSize / gcmSIZEOF(gctUINT32);
+
+ /* Construct Slave TLB. */
+ gcmkONERROR(gckOS_AllocateContiguous(Mmu->os,
+ gcvFALSE,
+ &Mmu->pageTableSize,
+ &Mmu->pageTablePhysical,
+ (gctPOINTER)&Mmu->pageTableLogical));
+
+ /* Invalidate all entries. */
+ gcmkONERROR(gckOS_ZeroMemory(Mmu->pageTableLogical,
+ Mmu->pageTableSize));
+
+ /* Initilization. */
+ pageTable = Mmu->pageTableLogical;
+ pageTable[0] = (Mmu->pageTableEntries << 8) | gcvMMU_FREE;
+ pageTable[1] = ~0U;
+ Mmu->heapList = 0;
+ Mmu->freeNodes = gcvFALSE;
+
+ gcmkONERROR(gckOS_GetPhysicalAddress(Mmu->os,
+ Mmu->pageTableLogical,
+ &physical));
+
+ /* Grab the mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Map to Master TLB. */
+ for (; i < gcdMMU_MTLB_ENTRY_NUM; i++)
+ {
+ Mmu->mtlbLogical[i] = physical
+ /* 4KB page size */
+ | (0 << 2)
+ /* Ignore exception */
+ | (0 << 1)
+ /* Present */
+ | (1 << 0);
+#if gcdMMU_TABLE_DUMP
+ gckOS_Print("%s(%d): insert MTLB[%d]: %08x\n",
+ __FUNCTION__, __LINE__,
+ i,
+ *(Mmu->mtlbLogical + i));
+#endif
+ physical += gcdMMU_STLB_4K_SIZE;
+ }
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (Mmu->pageTableLogical)
+ {
+ /* Free the page table. */
+ gcmkVERIFY_OK(
+ gckOS_FreeContiguous(Mmu->os,
+ Mmu->pageTablePhysical,
+ (gctPOINTER) Mmu->pageTableLogical,
+ Mmu->pageTableSize));
+ }
+
+ if (acquired)
+ {
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+ }
+
+ return status;
+}
+
/*******************************************************************************
**
-** gckMMU_Construct
+** _Construct
**
** Construct a new gckMMU object.
**
@@ -622,7 +527,7 @@ OnError:
** Pointer to a variable that receives the gckMMU object pointer.
*/
gceSTATUS
-gckMMU_Construct(
+_Construct(
IN gckKERNEL Kernel,
IN gctSIZE_T MmuSize,
OUT gckMMU * Mmu
@@ -661,6 +566,7 @@ gckMMU_Construct(
mmu->hardware = hardware;
mmu->pageTableMutex = gcvNULL;
mmu->pageTableLogical = gcvNULL;
+ mmu->mtlbLogical = gcvNULL;
mmu->staticSTLB = gcvNULL;
mmu->enabled = gcvFALSE;
#ifdef __QNXNTO__
@@ -668,10 +574,8 @@ gckMMU_Construct(
mmu->nodeMutex = gcvNULL;
#endif
-#if !gcdSHARED_PAGETABLE
/* Create the page table mutex. */
gcmkONERROR(gckOS_CreateMutex(os, &mmu->pageTableMutex));
-#endif
#ifdef __QNXNTO__
/* Create the node list mutex. */
@@ -680,12 +584,8 @@ gckMMU_Construct(
if (hardware->mmuVersion == 0)
{
- /* Allocate the page table (not more than 256 kB). */
- mmu->pageTableSize = gcmMIN(MmuSize, 256 << 10);
+ mmu->pageTableSize = MmuSize;
-#if gcdSHARED_PAGETABLE
- _Construct(mmu);
-#else
gcmkONERROR(
gckOS_AllocateContiguous(os,
gcvFALSE,
@@ -694,13 +594,24 @@ gckMMU_Construct(
&pointer));
mmu->pageTableLogical = pointer;
-#endif
/* Compute number of entries in page table. */
mmu->pageTableEntries = mmu->pageTableSize / sizeof(gctUINT32);
/* Mark all pages as free. */
pageTable = mmu->pageTableLogical;
+
+#if gcdMMU_CLEAR_VALUE
+ {
+ gctUINT32 i;
+
+ for (i = 0; i < mmu->pageTableEntries; ++i)
+ {
+ pageTable[i] = gcdMMU_CLEAR_VALUE;
+ }
+ }
+#endif
+
pageTable[0] = (mmu->pageTableEntries << 8) | gcvMMU_FREE;
pageTable[1] = ~0U;
mmu->heapList = 0;
@@ -713,24 +624,20 @@ gckMMU_Construct(
else
{
/* Allocate the 4K mode MTLB table. */
- mmu->pageTableSize = gcdMMU_MTLB_SIZE + 64;
+ mmu->mtlbSize = gcdMMU_MTLB_SIZE + 64;
-#if gcdSHARED_PAGETABLE
- _Construct(mmu);
-#else
gcmkONERROR(
gckOS_AllocateContiguous(os,
gcvFALSE,
- &mmu->pageTableSize,
- &mmu->pageTablePhysical,
+ &mmu->mtlbSize,
+ &mmu->mtlbPhysical,
&pointer));
- mmu->pageTableLogical = pointer;
+ mmu->mtlbLogical = pointer;
/* Invalid all the entries. */
gcmkONERROR(
- gckOS_ZeroMemory(pointer, mmu->pageTableSize));
-#endif
+ gckOS_ZeroMemory(pointer, mmu->mtlbSize));
}
/* Return the gckMMU object pointer. */
@@ -747,18 +654,23 @@ OnError:
if (mmu->pageTableLogical != gcvNULL)
{
/* Free the page table. */
-#if gcdSHARED_PAGETABLE
- _Free(mmu);
-#else
gcmkVERIFY_OK(
gckOS_FreeContiguous(os,
mmu->pageTablePhysical,
(gctPOINTER) mmu->pageTableLogical,
mmu->pageTableSize));
-#endif
}
+ if (mmu->mtlbLogical != gcvNULL)
+ {
+ gcmkVERIFY_OK(
+ gckOS_FreeContiguous(os,
+ mmu->mtlbPhysical,
+ (gctPOINTER) mmu->mtlbLogical,
+ mmu->mtlbSize));
+ }
+
if (mmu->pageTableMutex != gcvNULL)
{
/* Delete the mutex. */
@@ -789,7 +701,7 @@ OnError:
/*******************************************************************************
**
-** gckMMU_Destroy
+** _Destroy
**
** Destroy a gckMMU object.
**
@@ -803,7 +715,7 @@ OnError:
** Nothing.
*/
gceSTATUS
-gckMMU_Destroy(
+_Destroy(
IN gckMMU Mmu
)
{
@@ -842,7 +754,7 @@ gckMMU_Destroy(
if (pre->mtlbEntryNum != 0)
{
gcmkASSERT(pre->mtlbEntryNum == 1);
- *(Mmu->pageTableLogical + pre->mtlbIndex) = 0;
+ *(Mmu->mtlbLogical + pre->mtlbIndex) = 0;
#if gcdMMU_TABLE_DUMP
gckOS_Print("%s(%d): clean MTLB[%d]\n",
__FUNCTION__, __LINE__,
@@ -853,26 +765,29 @@ gckMMU_Destroy(
gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, pre));
}
+ if (Mmu->hardware->mmuVersion != 0)
+ {
+ gcmkVERIFY_OK(
+ gckOS_FreeContiguous(Mmu->os,
+ Mmu->mtlbPhysical,
+ (gctPOINTER) Mmu->mtlbLogical,
+ Mmu->mtlbSize));
+ }
+
/* Free the page table. */
-#if gcdSHARED_PAGETABLE
- _Free(Mmu);
-#else
gcmkVERIFY_OK(
- gckOS_FreeContiguous(Mmu->os,
- Mmu->pageTablePhysical,
- (gctPOINTER) Mmu->pageTableLogical,
- Mmu->pageTableSize));
-#endif
+ gckOS_FreeContiguous(Mmu->os,
+ Mmu->pageTablePhysical,
+ (gctPOINTER) Mmu->pageTableLogical,
+ Mmu->pageTableSize));
#ifdef __QNXNTO__
/* Delete the node list mutex. */
gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->nodeMutex));
#endif
-#if !gcdSHARED_PAGETABLE
/* Delete the page table mutex. */
gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->pageTableMutex));
-#endif
/* Mark the gckMMU object as unknown. */
Mmu->object.type = gcvOBJ_UNKNOWN;
@@ -885,6 +800,85 @@ gckMMU_Destroy(
return gcvSTATUS_OK;
}
+gceSTATUS
+gckMMU_Construct(
+ IN gckKERNEL Kernel,
+ IN gctSIZE_T MmuSize,
+ OUT gckMMU * Mmu
+ )
+{
+#if gcdSHARED_PAGETABLE
+ gceSTATUS status;
+ gctPOINTER pointer;
+
+ gcmkHEADER_ARG("Kernel=0x%08x", Kernel);
+
+ if (sharedPageTable == gcvNULL)
+ {
+ gcmkONERROR(
+ gckOS_Allocate(Kernel->os,
+ sizeof(struct _gcsSharedPageTable),
+ &pointer));
+ sharedPageTable = pointer;
+
+ gcmkONERROR(
+ gckOS_ZeroMemory(sharedPageTable,
+ sizeof(struct _gcsSharedPageTable)));
+
+ gcmkONERROR(_Construct(Kernel, MmuSize, &sharedPageTable->mmu));
+ }
+
+ *Mmu = sharedPageTable->mmu;
+
+ sharedPageTable->hardwares[sharedPageTable->reference] = Kernel->hardware;
+
+ sharedPageTable->reference++;
+
+ gcmkFOOTER_ARG("sharedPageTable->reference=%lu", sharedPageTable->reference);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (sharedPageTable)
+ {
+ if (sharedPageTable->mmu)
+ {
+ gcmkVERIFY_OK(gckMMU_Destroy(sharedPageTable->mmu));
+ }
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, sharedPageTable));
+ }
+
+ gcmkFOOTER();
+ return status;
+#else
+ return _Construct(Kernel, MmuSize, Mmu);
+#endif
+}
+
+gceSTATUS
+gckMMU_Destroy(
+ IN gckMMU Mmu
+ )
+{
+#if gcdSHARED_PAGETABLE
+ sharedPageTable->reference--;
+
+ if (sharedPageTable->reference == 0)
+ {
+ if (sharedPageTable->mmu)
+ {
+ gcmkVERIFY_OK(_Destroy(Mmu));
+ }
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, sharedPageTable));
+ }
+
+ return gcvSTATUS_OK;
+#else
+ return _Destroy(Mmu);
+#endif
+}
+
/*******************************************************************************
**
** gckMMU_AllocatePages
@@ -930,231 +924,145 @@ gckMMU_AllocatePages(
gcmkVERIFY_ARGUMENT(PageCount > 0);
gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
- if (Mmu->hardware->mmuVersion == 0)
+ if (PageCount > Mmu->pageTableEntries)
{
- if (PageCount > Mmu->pageTableEntries)
- {
- /* Not enough pages avaiable. */
- gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
- }
+ /* Not enough pages avaiable. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
- /* Grab the mutex. */
- gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
- mutex = gcvTRUE;
+ /* Grab the mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
+ mutex = gcvTRUE;
- /* Cast pointer to page table. */
- for (pageTable = Mmu->pageTableLogical, gotIt = gcvFALSE; !gotIt;)
+ /* Cast pointer to page table. */
+ for (pageTable = Mmu->pageTableLogical, gotIt = gcvFALSE; !gotIt;)
+ {
+ /* Walk the heap list. */
+ for (index = Mmu->heapList; !gotIt && (index < Mmu->pageTableEntries);)
{
- /* Walk the heap list. */
- for (index = Mmu->heapList; !gotIt && (index < Mmu->pageTableEntries);)
+ /* Check the node type. */
+ switch (gcmENTRY_TYPE(pageTable[index]))
{
- /* Check the node type. */
- switch (pageTable[index] & 0xFF)
+ case gcvMMU_SINGLE:
+ /* Single odes are valid if we only need 1 page. */
+ if (PageCount == 1)
{
- case gcvMMU_SINGLE:
- /* Single odes are valid if we only need 1 page. */
- if (PageCount == 1)
- {
- gotIt = gcvTRUE;
- }
- else
- {
- /* Move to next node. */
- previous = index;
- index = pageTable[index] >> 8;
- }
- break;
-
- case gcvMMU_FREE:
- /* Test if the node has enough space. */
- if (PageCount <= (pageTable[index] >> 8))
- {
- gotIt = gcvTRUE;
- }
- else
- {
- /* Move to next node. */
- previous = index;
- index = pageTable[index + 1];
- }
- break;
-
- default:
- gcmkFATAL("MMU table correcupted at index %u!", index);
- gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ gotIt = gcvTRUE;
}
- }
+ else
+ {
+ /* Move to next node. */
+ previous = index;
+ index = pageTable[index] >> 8;
+ }
+ break;
- /* Test if we are out of memory. */
- if (index >= Mmu->pageTableEntries)
- {
- if (Mmu->freeNodes)
+ case gcvMMU_FREE:
+ /* Test if the node has enough space. */
+ if (PageCount <= (pageTable[index] >> 8))
{
- /* Time to move out the trash! */
- gcmkONERROR(_Collect(Mmu));
+ gotIt = gcvTRUE;
}
else
{
- /* Out of resources. */
- gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ /* Move to next node. */
+ previous = index;
+ index = pageTable[index + 1];
}
- }
- }
-
- switch (pageTable[index] & 0xFF)
- {
- case gcvMMU_SINGLE:
- /* Unlink single node from free list. */
- gcmkONERROR(
- _Link(Mmu, previous, pageTable[index] >> 8));
- break;
-
- case gcvMMU_FREE:
- /* Check how many pages will be left. */
- left = (pageTable[index] >> 8) - PageCount;
- switch (left)
- {
- case 0:
- /* The entire node is consumed, just unlink it. */
- gcmkONERROR(
- _Link(Mmu, previous, pageTable[index + 1]));
- break;
-
- case 1:
- /* One page will remain. Convert the node to a single node and
- ** advance the index. */
- pageTable[index] = (pageTable[index + 1] << 8) | gcvMMU_SINGLE;
- index ++;
break;
default:
- /* Enough pages remain for a new node. However, we will just adjust
- ** the size of the current node and advance the index. */
- pageTable[index] = (left << 8) | gcvMMU_FREE;
- index += left;
- break;
+ gcmkFATAL("MMU table correcupted at index %u!", index);
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
}
- break;
}
- /* Mark node as used. */
- pageTable[index] = gcvMMU_USED;
-
- /* Return pointer to page table. */
- *PageTable = &pageTable[index];
-
- /* Build virtual address. */
- gcmkONERROR(
- gckHARDWARE_BuildVirtualAddress(Mmu->hardware, index, 0, &address));
-
- if (Address != gcvNULL)
+ /* Test if we are out of memory. */
+ if (index >= Mmu->pageTableEntries)
{
- *Address = address;
+ if (Mmu->freeNodes)
+ {
+ /* Time to move out the trash! */
+ gcmkONERROR(_Collect(Mmu));
+ }
+ else
+ {
+ /* Out of resources. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
}
-
- /* Release the mutex. */
- gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
-
- /* Success. */
- gcmkFOOTER_ARG("*PageTable=0x%x *Address=%08x",
- *PageTable, gcmOPT_VALUE(Address));
- return gcvSTATUS_OK;
}
- else
- {
- gctUINT i, j;
- gctUINT32 addr;
- gctBOOL succeed = gcvFALSE;
- gcsMMU_STLB_PTR stlb = gcvNULL;
- gctUINT nMtlbEntry =
- gcmALIGN(PageCount, gcdMMU_STLB_4K_ENTRY_NUM) / gcdMMU_STLB_4K_ENTRY_NUM;
-
- if (Mmu->enabled == gcvFALSE)
- {
- gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_MMU,
- "gckMMU_AllocatePages(New MMU): failed by the MMU not enabled");
-
- gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
- }
- /* Grab the mutex. */
- gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
- mutex = gcvTRUE;
+ switch (gcmENTRY_TYPE(pageTable[index]))
+ {
+ case gcvMMU_SINGLE:
+ /* Unlink single node from free list. */
+ gcmkONERROR(
+ _Link(Mmu, previous, pageTable[index] >> 8));
+ break;
- for (i = 0; i < gcdMMU_MTLB_ENTRY_NUM; i++)
+ case gcvMMU_FREE:
+ /* Check how many pages will be left. */
+ left = (pageTable[index] >> 8) - PageCount;
+ switch (left)
{
- if (*(Mmu->pageTableLogical + i) == 0)
- {
- succeed = gcvTRUE;
-
- for (j = 1; j < nMtlbEntry; j++)
- {
- if (*(Mmu->pageTableLogical + i + j) != 0)
- {
- succeed = gcvFALSE;
- break;
- }
- }
+ case 0:
+ /* The entire node is consumed, just unlink it. */
+ gcmkONERROR(
+ _Link(Mmu, previous, pageTable[index + 1]));
+ break;
- if (succeed == gcvTRUE)
- {
- break;
- }
- }
- }
+ case 1:
+ /* One page will remain. Convert the node to a single node and
+ ** advance the index. */
+ pageTable[index] = (pageTable[index + 1] << 8) | gcvMMU_SINGLE;
+ index ++;
+ break;
- if (succeed == gcvFALSE)
- {
- gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ default:
+ /* Enough pages remain for a new node. However, we will just adjust
+ ** the size of the current node and advance the index. */
+ pageTable[index] = (left << 8) | gcvMMU_FREE;
+ index += left;
+ break;
}
+ break;
+ }
- gcmkONERROR(_GetStlb(Mmu, PageCount, &stlb));
+ /* Mark node as used. */
+ pageTable[index] = gcvMMU_USED;
- stlb->mtlbIndex = i;
- stlb->mtlbEntryNum = nMtlbEntry;
+ /* Return pointer to page table. */
+ *PageTable = &pageTable[index];
- addr = stlb->physBase;
- for (j = 0; j < nMtlbEntry; j++)
- {
- gcmkASSERT(!(addr & (gcdMMU_STLB_4K_SIZE - 1)));
- *(Mmu->pageTableLogical + i + j) = addr
- /* 4KB page size */
- | (0 << 2)
- /* Ignore exception */
- | (0 << 1)
- /* Present */
- | (1 << 0);
-#if gcdMMU_TABLE_DUMP
- gckOS_Print("%s(%d): insert MTLB[%d]: %08x\n",
- __FUNCTION__, __LINE__,
- i + j,
- *(Mmu->pageTableLogical + i + j));
-#endif
- addr += gcdMMU_STLB_4K_SIZE;
- }
-
- /* Release the mutex. */
- gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+ /* Build virtual address. */
+ if (Mmu->hardware->mmuVersion == 0)
+ {
+ gcmkONERROR(
+ gckHARDWARE_BuildVirtualAddress(Mmu->hardware, index, 0, &address));
+ }
+ else
+ {
+ gctUINT32 masterOffset = index / gcdMMU_STLB_4K_ENTRY_NUM
+ + Mmu->dynamicMappingStart;
+ gctUINT32 slaveOffset = index % gcdMMU_STLB_4K_ENTRY_NUM;
- *PageTable = (gctUINT8_PTR)stlb + gcvMMU_STLB_SIZE;
+ address = (masterOffset << gcdMMU_MTLB_SHIFT)
+ | (slaveOffset << gcdMMU_STLB_4K_SHIFT);
+ }
- if (Address != gcvNULL)
- {
- *Address = (i << gcdMMU_MTLB_SHIFT)
- | (gcvMMU_STLB_SIZE << 10);
- }
+ if (Address != gcvNULL)
+ {
+ *Address = address;
+ }
-#if !gcdSHARED_PAGETABLE
- /* Flush the MMU cache. */
- gcmkONERROR(
- gckHARDWARE_FlushMMU(Mmu->hardware));
-#endif
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
- /* Success. */
- gcmkFOOTER_ARG("*PageTable=0x%x *Address=%08x",
- *PageTable, gcmOPT_VALUE(Address));
- return gcvSTATUS_OK;
- }
+ /* Success. */
+ gcmkFOOTER_ARG("*PageTable=0x%x *Address=%08x",
+ *PageTable, gcmOPT_VALUE(Address));
+ return gcvSTATUS_OK;
OnError:
@@ -1197,8 +1105,7 @@ gckMMU_FreePages(
IN gctSIZE_T PageCount
)
{
- gceSTATUS status;
- gctBOOL mutex = gcvFALSE;
+ gctUINT32_PTR pageTable;
gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=%lu",
Mmu, PageTable, PageCount);
@@ -1208,90 +1115,38 @@ gckMMU_FreePages(
gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
gcmkVERIFY_ARGUMENT(PageCount > 0);
- if (Mmu->hardware->mmuVersion == 0)
- {
- gctUINT32_PTR pageTable;
-
- /* Convert the pointer. */
- pageTable = (gctUINT32_PTR) PageTable;
-
- if (PageCount == 1)
- {
- /* Single page node. */
- pageTable[0] = (~((1U<<8)-1)) | gcvMMU_SINGLE;
- }
- else
- {
- /* Mark the node as free. */
- pageTable[0] = (PageCount << 8) | gcvMMU_FREE;
- pageTable[1] = ~0U;
- }
-
- /* We have free nodes. */
- Mmu->freeNodes = gcvTRUE;
+ /* Convert the pointer. */
+ pageTable = (gctUINT32_PTR) PageTable;
- /* Success. */
- gcmkFOOTER_NO();
- return gcvSTATUS_OK;
- }
- else
+#if gcdMMU_CLEAR_VALUE
{
- gcsMMU_STLB_PTR stlb = (gcsMMU_STLB_PTR)((gctUINT8_PTR) PageTable - gcvMMU_STLB_SIZE);
gctUINT32 i;
- if (Mmu->enabled == gcvFALSE)
- {
- gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_MMU,
- "gckMMU_FreePages(New MMU): failed by the MMU not enabled");
-
- gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
- }
-
- if ((stlb->logical != (gctPOINTER)stlb)
- || (stlb->pageCount != PageCount)
- || (stlb->mtlbIndex >= gcdMMU_MTLB_ENTRY_NUM)
- || (stlb->mtlbEntryNum == 0))
+ for (i = 0; i < PageCount; ++i)
{
- gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ pageTable[i] = gcdMMU_CLEAR_VALUE;
}
-
- /* Grab the mutex. */
- gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
- mutex = gcvTRUE;
-
- for (i = 0; i < stlb->mtlbEntryNum; i++)
- {
- /* clean the MTLB entries. */
- gcmkASSERT((*(Mmu->pageTableLogical + stlb->mtlbIndex + i) & 7) == 1);
- *(Mmu->pageTableLogical + stlb->mtlbIndex + i) = 0;
-#if gcdMMU_TABLE_DUMP
- gckOS_Print("%s(%d): clean MTLB[%d]\n",
- __FUNCTION__, __LINE__,
- stlb->mtlbIndex + i);
+ }
#endif
- }
-
- /* Release the mutex. */
- gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
- mutex = gcvFALSE;
- gcmkONERROR(_PutStlb(Mmu, stlb));
-
- /* Success. */
- gcmkFOOTER_NO();
- return gcvSTATUS_OK;
+ if (PageCount == 1)
+ {
+ /* Single page node. */
+ pageTable[0] = (~((1U<<8)-1)) | gcvMMU_SINGLE;
}
-
-OnError:
- if (mutex)
+ else
{
- /* Release the mutex. */
- gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+ /* Mark the node as free. */
+ pageTable[0] = (PageCount << 8) | gcvMMU_FREE;
+ pageTable[1] = ~0U;
}
- /* Return the status. */
- gcmkFOOTER();
- return status;
+ /* We have free nodes. */
+ Mmu->freeNodes = gcvTRUE;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
}
gceSTATUS
@@ -1308,6 +1163,14 @@ gckMMU_Enable(
/* Verify the arguments. */
gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+#if gcdSHARED_PAGETABLE
+ if (Mmu->enabled)
+ {
+ gcmkFOOTER_ARG("Status=%d", gcvSTATUS_SKIP);
+ return gcvSTATUS_SKIP;
+ }
+#endif
+
if (Mmu->hardware->mmuVersion == 0)
{
/* Success. */
@@ -1325,13 +1188,15 @@ gckMMU_Enable(
));
}
+ gcmkONERROR(_SetupDynamicSpace(Mmu));
+
gcmkONERROR(
gckHARDWARE_SetMMUv2(
Mmu->hardware,
gcvTRUE,
- Mmu->pageTableLogical,
+ Mmu->mtlbLogical,
gcvMMU_MODE_4K,
- (gctUINT8_PTR)Mmu->pageTableLogical + gcdMMU_MTLB_SIZE,
+ (gctUINT8_PTR)Mmu->mtlbLogical + gcdMMU_MTLB_SIZE,
gcvFALSE
));
@@ -1500,30 +1365,38 @@ OnError:
}
#endif
-#if gcdSHARED_PAGETABLE
gceSTATUS
-gckMMU_FlushAllMmuCache(
- void
+gckMMU_Flush(
+ IN gckMMU Mmu
)
{
- gceSTATUS status;
+ gckHARDWARE hardware;
+#if gcdSHARED_PAGETABLE
gctINT i;
for (i = 0; i < gcdCORE_COUNT; i++)
{
- if (sharedPageTable->hardwares[i])
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ continue;
+ }
+#endif
+ hardware = sharedPageTable->hardwares[i];
+ if (hardware)
{
- gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_MMU,
- "Flush MMU Cache for hardware=0x%x",
- sharedPageTable->hardwares[i]);
- gcmkONERROR(gckHARDWARE_FlushMMU(sharedPageTable->hardwares[i]));
+ /* Notify cores who use this page table. */
+ gcmkVERIFY_OK(
+ gckOS_AtomSet(hardware->os, hardware->pageTableDirty, 1));
}
}
+#else
+ hardware = Mmu->hardware;
+ gcmkVERIFY_OK(
+ gckOS_AtomSet(hardware->os, hardware->pageTableDirty, 1));
+#endif
return gcvSTATUS_OK;
-OnError:
- return status;
}
-#endif
/******************************************************************************
****************************** T E S T C O D E ******************************