diff options
author | Loren Huang <b02279@freescale.com> | 2012-03-16 15:29:06 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2012-07-20 13:24:15 +0800 |
commit | 217856f4c04b3ea8e964cf591414d561c50fb0dd (patch) | |
tree | 7b7b2c70808839658524cfc2170ef2be708ff3cf /drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c | |
parent | b6cd59a82130ec0c7e1ac56deec1b60e02114612 (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.c | 941 |
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 ****************************** |