📄 dual_buffer.c
字号:
/* -*- c-file-style: "img" -*-
<module>
* Name : dual_buffer.c
* Title : Dual Space Buffer Management.
* Author : Marcus Shawcroft
* 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 : Manages buffers mapped into two virtual memory spaces,
* cpu and device.
*
* Platform : ALL
*
</module>
********************************************************************************/
#include "services_headers.h"
#include "buffer_manager.h"
#include "hash.h"
#include "ra.h"
#include "dual_buffer.h"
#include "dual_page.h"
#include "hash.h"
#include "pool.h"
#include "hw.h"
struct _DB_STATE_
{
/* Resource allocation arena of dual mapped pages. For devices
where the hardware imposes different constraints on the valid
device virtual address range depending on the use of the buffer
we maintain two allocation arenas, one low address range, the
other high. For devices without such a constrain we do not
create the high arena, instead all allocations come from the
low arena. */
RA_ARENA *pDualPageArena;
RA_ARENA *pDualPageHiArena;
struct device_tag device;
DP_PAGER *pDualPager;
HASH_TABLE *pDualPageHash;
POOL *pMemBufPool;
HASH_STATE *pHashState;
RA_STATE *pRAState;
DP_STATE *pDPState;
};
/*----------------------------------------------------------------------------
<function>
FUNCTION: AllocMemory
PURPOSE: Allocate a buffer mapped into both cpu and device virtual
address spaces.
PARAMETERS: In: pDBState - dual buffer state (from DB_Initialise())
In: size - requested buffer size in bytes.
In: buffer_props - property flags for the buffer.
In: uDevVAddrAlignment - required device virtual address
alignment, or 0.
Out: pBuf - receives a pointer to a descriptor of the allocated
buffer.
RETURNS: IMG_TRUE - Success
IMG_FALSE - Failed.
</function>
-----------------------------------------------------------------------------*/
static IMG_BOOL
AllocMemory (DB_STATE *pDBState,
IMG_SIZE_T uSize,
IMG_UINT32 uFlags,
IMG_UINT32 uDevVAddrAlignment,
BM_BUF *pBuf)
{
IMG_DEV_VIRTADDR DevVAddr = {0};
DP_MAPPING *pMapping;
IMG_UINTPTR_T uOffset;
PVR_ASSERT (pDBState != IMG_NULL);
PVR_ASSERT (pBuf != IMG_NULL);
PVR_DPF ((PVR_DBG_MESSAGE,
"dual_buffer:AllocMemory (pDBState=0x%x, uSize=0x%lx, uFlags=0x%x, align=0x%x, pBuf=0x%x)",
pDBState, uSize, uFlags, uDevVAddrAlignment, pBuf));
uSize = HOST_PAGEALIGN (uSize);
/* if there is no pDualPageArena then all allocations are taken
from the contiguous memory pool, this happens when there is no
hardware MMU support */
if (pDBState->pDualPageArena == IMG_NULL || (uFlags & BP_CONTIGUOUS))
{
IMG_BOOL bResult;
pBuf->pArena = IMG_NULL;
bResult = DP_Alloc (pDBState->pDualPager,
uSize,
IMG_NULL,
(void*) &pMapping,
uFlags,
uDevVAddrAlignment,
&(DevVAddr.uiAddr));
if (!bResult)
{
PVR_DPF((PVR_DBG_ERROR, "AllocMemory: ERROR DP_Alloc FAILED"));
return bResult;
}
}
else
{
if ((uFlags & BP_HI_MEMORY) && DP_HaveHiArena (pDBState->pDualPager))
pBuf->pArena = pDBState->pDualPageHiArena;
else
pBuf->pArena = pDBState->pDualPageArena;
if (!RA_Alloc (pBuf->pArena,
uSize,
IMG_NULL,
(void*) &pMapping,
uFlags,
uDevVAddrAlignment,
0,
&(DevVAddr.uiAddr)))
{
PVR_DPF((PVR_DBG_ERROR, "AllocMemory: ERROR RA_Alloc FAILED"));
return IMG_FALSE;
}
}
/* determine the offset of this allocation within the underlying
dual mapped chunk of memory, we can assume that all three
addresses associated with this allocation are placed at the same
offset within the underlying chunk. */
uOffset = DevVAddr.uiAddr - pMapping->DevVAddr.uiAddr;
pBuf->pRef = pMapping;
if (pMapping->CpuPAddr.uiAddr==0)
pBuf->CpuPAddr.uiAddr = 0;
else
pBuf->CpuPAddr.uiAddr = pMapping->CpuPAddr.uiAddr + uOffset;
pBuf->CpuVAddr = (void*) ((IMG_UINTPTR_T)pMapping->CpuVAddr + uOffset);
pBuf->DevVAddr.uiAddr = pMapping->DevVAddr.uiAddr + uOffset;
PVR_DPF ((PVR_DBG_MESSAGE,
"dual_buffer:AllocMemory () = (hv=0x%lx dv=0x%lx hp=0x%lx)",
pBuf->CpuVAddr, pBuf->DevVAddr.uiAddr, pBuf->CpuPAddr.uiAddr));
return IMG_TRUE;
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: WrapMemory
PURPOSE: Allocate a buffer mapped into both cpu and device virtual
address spaces.
PARAMETERS: In: pDBState - dual buffer state (from DB_Initialise())
In: base - address of memory to wrap
In: uSize - requested buffer size in bytes.
In: uBufferProps - property flags for the buffer.
In: uDevVAddrAlignment - required device virtual address
alignment, or 0.
Out: pBuf - receives a pointer to a descriptor of the allocated
buffer.
RETURNS: IMG_TRUE - Success
IMG_FALSE - Failed.
</function>
-----------------------------------------------------------------------------*/
static IMG_BOOL
WrapMemory (DB_STATE *pDBState,
IMG_SYS_PHYADDR base,
IMG_SIZE_T uSize,
IMG_UINT32 uFlags,
IMG_UINT32 uDevVAddrAlignment,
BM_BUF *pBuf)
{
IMG_DEV_VIRTADDR DevVAddr = {0};
DP_MAPPING *pMapping;
IMG_UINTPTR_T uOffset;
IMG_BOOL bResult;
PVR_DPF ((PVR_DBG_MESSAGE,
"dual_buffer:WrapMemory(base=0x%x, uSize=0x%x)", base, uSize));
PVR_ASSERT (pBuf != IMG_NULL);
#if 0
IMG_SIZE_T uBaseOffset = 0;
/* we may have been asked to wrap non page aligned memory, we
force the wrap to be page aligned by rounding base down to the
nearest page and increasing size by the corresponding
amount. The rounding offset will be added back into each of the
wrapped buffer addresses. */
uBaseOffset = base.uiAddr & (HOST_PAGE_SIZE - 1);
base.addr -= uBaseOffset;
uSize += uBaseOffset;
#endif
uSize = HOST_PAGEALIGN (uSize);
pBuf->pArena = IMG_NULL;
bResult = DP_Wrap (pDBState->pDualPager,
base,
uSize,
IMG_NULL,
(void*) &pMapping,
uFlags,
uDevVAddrAlignment,
&(DevVAddr.uiAddr));
if (!bResult) return IMG_FALSE;
/* determine the offset of this allocation within the underlying
dual mapped chunk of memory, we can assume that all three
addresses associated with this allocation are placed at the same
offset within the underlying chunk. */
uOffset = DevVAddr.uiAddr - pMapping->DevVAddr.uiAddr;
pBuf->pRef = pMapping;
if (pMapping->CpuPAddr.uiAddr==0)
pBuf->CpuPAddr.uiAddr = 0;
else
pBuf->CpuPAddr.uiAddr = pMapping->CpuPAddr.uiAddr + uOffset;
pBuf->CpuVAddr = (void*) ((IMG_UINTPTR_T)pMapping->CpuVAddr + uOffset);
pBuf->DevVAddr.uiAddr = pMapping->DevVAddr.uiAddr + uOffset;
return IMG_TRUE;
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: DB_Initialise
PURPOSE: To initialise the dual buffer module, must be called before
any other function within dual buffer.
PARAMETERS: In: pRegisters - cpu virtual address for the device registers.
In: pSlaveports - cpu virtual address for the device slaveports
Out: ppState - receives the dual buffer state
RETURNS: IMG_TRUE - success
IMG_FALSE - failed
</function>
-----------------------------------------------------------------------------*/
IMG_BOOL
DB_Initialise ( IMG_CPU_VIRTADDR pRegisters,
IMG_CPU_VIRTADDR pSlavePorts,
IMG_UINT32 ui32CoreConfig,
DB_STATE **ppState)
{
DB_STATE *pDBState = IMG_NULL;
PVR_DPF ((PVR_DBG_MESSAGE,
"DB_Initialise (registers=0x%x)", pRegisters));
PVR_ASSERT (ppState!=IMG_NULL);
if (HostAllocMem (PVRSRV_HOST_PAGEABLE_HEAP,
sizeof (*pDBState),
(IMG_VOID **)&pDBState,
0) != PVRSRV_OK)
{
goto cleanup;
}
HostMemSet (pDBState, 0, sizeof (DB_STATE));
HW_Define (&pDBState->device, pRegisters, pSlavePorts, ui32CoreConfig);
if (!HASH_Initialise (&pDBState->pHashState))
goto cleanup;
if (!RA_Initialise (pDBState->pHashState, &pDBState->pRAState))
goto cleanup;
if (!DP_Initialise (pDBState->pRAState, &pDBState->pDPState))
goto cleanup;
pDBState->pMemBufPool = POOL_Create ("mem_buf", sizeof (BM_BUF));
if (pDBState->pMemBufPool==IMG_NULL) goto cleanup;
pDBState->pDualPageHash = HASH_Create (pDBState->pHashState, 32);
if (pDBState->pDualPageHash==IMG_NULL) goto cleanup;
pDBState->pDualPager = DP_Create (pDBState->pDPState, &pDBState->device);
if (pDBState->pDualPager==IMG_NULL) goto cleanup;
/* if we have MMU hardware then we create arenas to manage mapped
* memory
*/
if (pDBState->device.bHaveMMU && (SysMMUMode () == SYS_MMU_NORMAL))
{
pDBState->pDualPageArena = RA_Create (pDBState->pRAState,
"dual page", 0, 0,
HOST_PAGESIZE(),
DP_AllocMany,
DP_Free,
pDBState->pDualPager);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -