📄 mmu.c
字号:
/******************************************************************************
<module>
* Name : mmu.c
* Title : MMU Management
* Author(s) : Imagination Technologies
* Created : 14 May 2003
*
* Copyright : 2003 by Imagination Technologies Limited.
* All rights reserved. No part of this software, either
* material or conceptual may be copied or distributed,
* transmitted, transcribed, stored in a retrieval system
* or translated into any human or computer language in any
* form by any means, electronic, mechanical, manual or
* other-wise, or disclosed to third parties without the
* express written permission of Imagination Technologies
* Limited, Unit 8, HomePark Industrial Estate,
* King's Langley, Hertfordshire, WD4 8LZ, U.K.
*
* Description : Implements basic low level control of MMU.
*
* Platform : ALL
*
</module>
*/
#include "services_headers.h"
#include "buffer_manager.h"
#include "dual_page.h"
#include "hash.h"
#include "ra.h"
#include "hw.h"
#include "mmu.h"
#include "mmu_flush.h"
#include "pool.h"
#include "env.h"
/* determine the page table register offset */
#define ptr_offset(dev_vaddr) \
((dev_vaddr.uiAddr>>(DEV_PAGE_SHIFT+MBX_MMU_TT_SHIFT))&((1<<MBX_MMU_PTR_SHIFT)-1))
/* determine the page table entry */
#define pte_offset(dev_vaddr) \
((dev_vaddr.uiAddr >> DEV_PAGE_SHIFT) & ((1<<MBX_MMU_TT_SHIFT)-1))
struct _MMU_
{
IMG_CPU_VIRTADDR aPageTableCpuVAddr [MBX_MMU_PTRS];
IMG_CPU_PHYADDR aPageTableCpuPAddr [MBX_MMU_PTRS];
struct device_tag *pDev;
/* Resource allocation arenas for address ranges in the device virtual
* address space. For devices which impose different
* address range criteria depending on the use of the buffer, we
* maintain two allocation arenas, one for low addresses, the other
* for high addresses, selection between the two is controlled by the
* presence of the BP_HI_MEMORY allocation flags.
*/
RA_ARENA *pVmaArena;
RA_ARENA *pVmaHiArena;
MMU_FLUSH pFlush;
enum _MMU_FLUSH_MECHANISM_
{
FM_TLB_RELOAD,
#if defined (FIX_HW_PRN_63)
FM_2D_FLUSH
#endif
} eFlushMechanism;
/* Dummy page referenced by unused page table entries */
IMG_CPU_VIRTADDR DummyPageCpuVAddr;
IMG_CPU_PHYADDR DummyPageCpuPAddr;
/* dual page pager for allocating contrigous working memory */
DP_PAGER *pPager;
/* The MMU is currently enabled or disabled */
IMG_BOOL bEnabled;
};
static IMG_UINT32
aPageRegisterOffset [] =
{
MBX1_GLOBREG_MMU_PAGE0_ADDR,
MBX1_GLOBREG_MMU_PAGE1_ADDR,
MBX1_GLOBREG_MMU_PAGE2_ADDR,
MBX1_GLOBREG_MMU_PAGE3_ADDR,
MBX1_GLOBREG_MMU_PAGE4_ADDR,
MBX1_GLOBREG_MMU_PAGE5_ADDR,
MBX1_GLOBREG_MMU_PAGE6_ADDR,
MBX1_GLOBREG_MMU_PAGE7_ADDR
};
/* todo: boilerplate */
static void
_EnableSpinWait (struct device_tag *pDev)
{
IMG_UINT32 uIterations = 0;
while ((HW_ReadReg (pDev, MBX1_GLOBREG_MMU_ENABLE) & MMU_READY_MASK) == 0)
uIterations++;
PVR_DPF ((PVR_DBG_MESSAGE,
"_EnableSpinWait() iterations=%u", uIterations));
}
/* todo: boilerplate */
static void
DisableSpinWait (struct device_tag *pDev)
{
IMG_UINT32 uIterations = 0;
while ((HW_ReadReg (pDev, MBX1_GLOBREG_MMU_ENABLE) & MMU_READY_MASK) != 0)
uIterations++;
PVR_DPF ((PVR_DBG_MESSAGE,
"DisableSpinWait() iterations=%d", uIterations));
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: _FreePageTables
PURPOSE: Free the page tables associated with an MMU.
PARAMETERS: In: pMMU - the mmu
RETURNS: None
</function>
-----------------------------------------------------------------------------*/
static void
_FreePageTables (MMU *pMMU)
{
IMG_UINT32 uPtn;
for (uPtn=0; uPtn<MBX_MMU_PTRS; uPtn++)
{
if (pMMU->aPageTableCpuVAddr[uPtn] != IMG_NULL)
DP_FreeContiguous (pMMU->pPager,
0,
pMMU->aPageTableCpuPAddr [uPtn]);
}
DP_FreeContiguous (pMMU->pPager, 0, pMMU->DummyPageCpuPAddr);
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: _AllocPageTables
PURPOSE: Allocate page tables for an MMU.
PARAMETERS: In: pMMU - the mmu
RETURNS: IMG_TRUE - Success
IMG_FALSE - Failed
</function>
-----------------------------------------------------------------------------*/
static IMG_BOOL
_AllocPageTables (MMU *pMMU)
{
IMG_UINT32 uPtn;
IMG_DEV_PHYADDR DummyPageDevPAddr;
PVR_DPF ((PVR_DBG_MESSAGE, "_AllocPageTables()"));
PVR_ASSERT (pMMU!=IMG_NULL);
PVR_ASSERT (HOST_PAGESIZE() == DEV_PAGE_SIZE);
for (uPtn=0; uPtn<MBX_MMU_PTRS; uPtn++)
{
pMMU->aPageTableCpuVAddr[uPtn] = IMG_NULL;
}
if (!DP_AllocContiguous (pMMU->pPager,
0,
DEV_PAGE_SIZE,
IMG_NULL,
DEV_PAGE_SIZE,
&pMMU->DummyPageCpuVAddr,
&pMMU->DummyPageCpuPAddr))
{
PVR_DPF((PVR_DBG_ERROR, "_AllocPageTables: ERROR call to DP_AllocContiguous failed"));
return IMG_FALSE;
}
PVR_DPF ((PVR_DBG_MESSAGE, "mmu: dummy page cpu_paddr = 0x%x",
pMMU->DummyPageCpuPAddr.uiAddr));
DummyPageDevPAddr = ENV_CpuPAddrToDevPAddr (pMMU->DummyPageCpuPAddr);
for (uPtn=0; uPtn<MBX_MMU_PTRS; uPtn++)
{
IMG_DEV_PHYADDR DevPAddr;
IMG_CPU_PHYADDR CpuPAddr;
IMG_UINT32 uOffset;
if (!DP_AllocContiguous (pMMU->pPager,
0,
MBX_MMU_TT_ENTRIES << 2,
IMG_NULL,
DEV_PAGE_SIZE,
&pMMU->aPageTableCpuVAddr[uPtn],
&pMMU->aPageTableCpuPAddr[uPtn]))
{
PVR_DPF((PVR_DBG_ERROR, "_AllocPageTables: ERROR call to DP_AllocContiguous failed"));
_FreePageTables(pMMU); /* This will also cleanup pMMU->DummyPageCpuVAddr */
return IMG_FALSE;
}
CpuPAddr = pMMU->aPageTableCpuPAddr[uPtn];
DevPAddr = ENV_CpuPAddrToDevPAddr (CpuPAddr);
PVR_DPF ((PVR_DBG_MESSAGE, " ptn=%d dp=0x%x cp=0x%x",
uPtn, DevPAddr.uiAddr, CpuPAddr.uiAddr));
HW_WriteReg (pMMU->pDev, aPageRegisterOffset[uPtn], DevPAddr.uiAddr);
/* TODO: pdump missing */
/* Point all entries at the dummy page */
for (uOffset=0; uOffset<MBX_MMU_TT_ENTRIES; uOffset++)
{
volatile IMG_UINTPTR_T *pt = pMMU->aPageTableCpuVAddr[uPtn];
pt[uOffset] = DummyPageDevPAddr.uiAddr;
}
}
return IMG_TRUE;
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: MMU_Initialise
PURPOSE: Initialise the mmu module.
PARAMETERS: None
RETURNS: IMG_TRUE Success
IMG_FALSE Failed
</function>
-----------------------------------------------------------------------------*/
IMG_BOOL
MMU_Initialise (void)
{
PVR_DPF ((PVR_DBG_MESSAGE, "MMU_Initialise ()"));
return IMG_TRUE;
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: MMU_Finalise
PURPOSE: Finalise the mmu module, deallocate all resources.
PARAMETERS: None.
RETURNS: None.
</function>
-----------------------------------------------------------------------------*/
void
MMU_Finalise (void)
{
PVR_DPF ((PVR_DBG_MESSAGE, "MMU_Finalise ()"));
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: MMU_Create
PURPOSE: Create an mmu device.
PARAMETERS: In: pDev -
In: pRAState -
In: pPager - dual pager pager for working space allocation.
RETURNS:
</function>
-----------------------------------------------------------------------------*/
MMU *
MMU_Create (struct device_tag *pDev,
RA_STATE *pRAState,
DP_PAGER *pPager)
{
MMU *pMMU;
IMG_BOOL bRes;
IMG_SIZE_T uMmuHiArenaSize;
PVR_ASSERT (pDev!=IMG_NULL);
PVR_ASSERT (pRAState!=IMG_NULL);
PVR_DPF ((PVR_DBG_MESSAGE, "MMU_Create (0x%x)", pDev));
HostAllocMem( PVRSRV_HOST_PAGEABLE_HEAP,
sizeof (*pMMU),
(IMG_VOID **)&pMMU, 0);
if (pMMU == IMG_NULL)
{
PVR_DPF((PVR_DBG_ERROR, "MMU_Create: ERROR call to HostAllocMem failed"));
return IMG_NULL;
}
pMMU->bEnabled = IMG_FALSE;
pMMU->pDev = pDev;
pMMU->pPager = pPager;
pMMU->eFlushMechanism = FM_TLB_RELOAD;
#if defined (FIX_HW_PRN_63)
/* For some broken hardware we should be using the 2d flush mechanism, but
fpga images omit the 2D core, in this situation we resort to
the standard flush mechanism and an optimistic outlook */
pMMU->eFlushMechanism = FM_2D_FLUSH;
#endif
bRes = _AllocPageTables (pMMU);
if (!bRes)
{
PVR_DPF((PVR_DBG_ERROR, "MMU_Create: ERROR call to _AllocPageTables failed"));
HostFreeMem (PVRSRV_HOST_PAGEABLE_HEAP, pMMU);
return IMG_NULL;
}
/* Create the arena */
pMMU->pVmaArena = RA_Create (pRAState,
"mmu vma",
MMU_ARENA_BASE,
MMU_ARENA_SIZE,
DEV_PAGE_SIZE,
IMG_NULL,
IMG_NULL,
IMG_NULL);
if (pMMU->pVmaArena == IMG_NULL)
{
PVR_DPF((PVR_DBG_ERROR, "MMU_Create: ERROR call to RA_Create failed"));
_FreePageTables (pMMU);
HostFreeMem (PVRSRV_HOST_PAGEABLE_HEAP, pMMU);
return IMG_NULL;
}
uMmuHiArenaSize = MMU_HI_ARENA_SIZE;
pMMU->pVmaHiArena = IMG_NULL;
if (uMmuHiArenaSize>0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -