blob: ee16293744a57f5dc119868912cbcb659a78fe11 [file] [log] [blame]
/*************************************************************************/ /*!
@File
@Title Implementation of PMR functions for OS managed memory
@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
@Description Part of the memory management. This module is responsible for
implementing the function callbacks for physical memory borrowed
from that normally managed by the operating system.
@License MIT
The contents of this file are subject to the MIT license as set out below.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
This License is also included in this distribution in the file called
"MIT-COPYING".
EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ /**************************************************************************/
/* include/ */
#include <vector>
extern "C" {
#include "rgx_heaps.h"
#include "img_types.h"
#include "pvrsrv_error.h"
#include "pvrsrv_memallocflags.h"
/* services/server/include/ */
#include "allocmem.h"
#include "osfunc.h"
#include "pmr.h"
#include "pmr_impl.h"
#include "devicemem_server_utils.h"
/* ourselves */
#include "physmem_osmem.h"
}
#include "fuchsia/msd_img_device.h"
#include "magma_util/macros.h"
#include "platform_buffer.h"
#include "platform_bus_mapper.h"
#define NOT_IMPLEMENTED() fprintf(stderr, "msd-img-rgx-mtk: Not implemented in %s:%s:%d\n", __func__, __FILE__, __LINE__);
struct MagmaPhysicalMemoryResource
{
PVRSRV_DEVICE_NODE *psDevNode;
std::unique_ptr<magma::PlatformBuffer> buffer;
std::unique_ptr<magma::PlatformBusMapper::BusMapping> bus_mapping;
};
static PVRSRV_ERROR
LockPhysAddresses(PMR_IMPL_PRIVDATA data)
{
MagmaPhysicalMemoryResource *pmr = reinterpret_cast<MagmaPhysicalMemoryResource *>(data);
auto device = MsdImgDevice::cast(pmr->psDevNode->psDevConfig->pvOSDevice);
pmr->bus_mapping =
device->bus_mapper()->MapPageRangeBus(pmr->buffer.get(), 0, pmr->buffer->size() / magma::page_size());
if (!pmr->bus_mapping)
{
// Could instead be PVRSRV_ERROR_DEVICEMEM_OUT_OF_RANGE, or similar.
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
return PVRSRV_OK;
}
static PVRSRV_ERROR
UnlockPhysAddresses(PMR_IMPL_PRIVDATA data)
{
MagmaPhysicalMemoryResource *pmr = reinterpret_cast<MagmaPhysicalMemoryResource *>(data);
pmr->bus_mapping.reset();
return PVRSRV_OK;
}
static PVRSRV_ERROR
DevPhysAddr(PMR_IMPL_PRIVDATA pvPriv,
IMG_UINT32 ui32Log2PageSize,
IMG_UINT32 ui32NumOfAddr,
IMG_DEVMEM_OFFSET_T *puiOffset,
IMG_BOOL *pbValid,
IMG_DEV_PHYADDR *psDevAddrPtr)
{
MagmaPhysicalMemoryResource *pmr = reinterpret_cast<MagmaPhysicalMemoryResource *>(pvPriv);
if (ui32Log2PageSize != magma::page_shift())
{
NOT_IMPLEMENTED();
return PVRSRV_ERROR_NOT_SUPPORTED;
}
for (uint32_t i = 0; i < ui32NumOfAddr; i++)
{
if (pbValid[i])
{
uint64_t page_index = puiOffset[i] >> magma::page_shift();
uint64_t in_page_offset = puiOffset[i] & (magma::page_size() - 1);
psDevAddrPtr[i].uiAddr = pmr->bus_mapping->Get()[page_index] + in_page_offset;
}
}
return PVRSRV_OK;
}
struct MapHandle
{
uint32_t unused;
};
static PVRSRV_ERROR
AcquireKernelMappingData(PMR_IMPL_PRIVDATA pvPriv,
size_t uiOffset,
size_t uiSize,
void **ppvKernelAddressOut,
IMG_HANDLE *phHandleOut,
PMR_FLAGS_T ulFlags)
{
MagmaPhysicalMemoryResource *pmr = reinterpret_cast<MagmaPhysicalMemoryResource *>(pvPriv);
void *cpu_map;
// Map entire buffer for now. Also ignore flags.
if (!pmr->buffer->MapCpu(&cpu_map))
{
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
*ppvKernelAddressOut = reinterpret_cast<uint8_t *>(cpu_map) + uiOffset;
*phHandleOut = new MapHandle;
return PVRSRV_OK;
}
static void
ReleaseKernelMappingData(PMR_IMPL_PRIVDATA pvPriv, IMG_HANDLE hHandle)
{
MagmaPhysicalMemoryResource *pmr = reinterpret_cast<MagmaPhysicalMemoryResource *>(pvPriv);
pmr->buffer->UnmapCpu();
delete reinterpret_cast<MapHandle *>(hHandle);
}
static PVRSRV_ERROR
ChangeSparseMem(PMR_IMPL_PRIVDATA pPriv,
const PMR *psPMR,
IMG_UINT32 ui32AllocPageCount,
IMG_UINT32 *pai32AllocIndices,
IMG_UINT32 ui32FreePageCount,
IMG_UINT32 *pai32FreeIndices,
IMG_UINT32 uiFlags)
{
NOT_IMPLEMENTED();
return PVRSRV_ERROR_NOT_SUPPORTED;
}
static PVRSRV_ERROR
ChangeSparseMemCpuMap(PMR_IMPL_PRIVDATA pPriv,
const PMR *psPMR,
IMG_UINT64 sCpuVAddrBase,
IMG_UINT32 ui32AllocPageCount,
IMG_UINT32 *pai32AllocIndices,
IMG_UINT32 ui32FreePageCount,
IMG_UINT32 *pai32FreeIndices)
{
NOT_IMPLEMENTED();
return PVRSRV_ERROR_NOT_SUPPORTED;
}
static PVRSRV_ERROR
Finalize(PMR_IMPL_PRIVDATA data)
{
MagmaPhysicalMemoryResource *pmr = reinterpret_cast<MagmaPhysicalMemoryResource *>(data);
delete pmr;
return PVRSRV_OK;
}
static const PMR_IMPL_FUNCTAB kPmrTable = {
.pfnLockPhysAddresses = LockPhysAddresses,
.pfnUnlockPhysAddresses = UnlockPhysAddresses,
.pfnDevPhysAddr = DevPhysAddr,
.pfnAcquireKernelMappingData = AcquireKernelMappingData,
.pfnReleaseKernelMappingData = ReleaseKernelMappingData,
.pfnChangeSparseMem = ChangeSparseMem,
.pfnChangeSparseMemCPUMap = ChangeSparseMemCpuMap,
.pfnFinalize = Finalize,
};
PVRSRV_ERROR
PhysmemNewOSRamBackedPMR(PVRSRV_DEVICE_NODE *psDevNode,
IMG_DEVMEM_SIZE_T uiSize,
IMG_DEVMEM_SIZE_T uiChunkSize,
IMG_UINT32 ui32NumPhysChunks,
IMG_UINT32 ui32NumVirtChunks,
IMG_UINT32 *puiAllocIndices,
IMG_UINT32 uiLog2AllocPageSize,
PVRSRV_MEMALLOCFLAGS_T uiFlags,
const IMG_CHAR *pszAnnotation,
IMG_PID uiPid,
PMR **ppsPMRPtr)
{
auto pmr = std::make_unique<MagmaPhysicalMemoryResource>();
// This may be called before the pvOSDevice is initialized, so store the
// entire device node for use later.
pmr->psDevNode = psDevNode;
pmr->buffer = magma::PlatformBuffer::Create(uiSize, pszAnnotation);
uint32_t cpu_cache_flags;
PVRSRV_ERROR eError;
eError = DevmemCPUCacheMode(psDevNode, uiFlags, &cpu_cache_flags);
if (eError != PVRSRV_OK)
{
return DRET(eError);
}
if (PVRSRV_CHECK_CPU_UNCACHED(cpu_cache_flags))
{
if (!pmr->buffer->SetCachePolicy(MAGMA_CACHE_POLICY_UNCACHED))
{
return DRET(PVRSRV_ERROR_OUT_OF_MEMORY);
}
}
else if (PVRSRV_CHECK_CPU_WRITE_COMBINE(cpu_cache_flags))
{
if (!pmr->buffer->SetCachePolicy(MAGMA_CACHE_POLICY_WRITE_COMBINING))
{
return DRET(PVRSRV_ERROR_OUT_OF_MEMORY);
}
}
else if (PVRSRV_CHECK_CPU_CACHE_CLEAN(uiFlags))
{
if (!pmr->buffer->CleanCache(0u, pmr->buffer->size(), true))
{
return DRET(PVRSRV_ERROR_OUT_OF_MEMORY);
}
}
PHYS_HEAP *psPhysHeap = psDevNode->apsPhysHeap[PVRSRV_DEVICE_PHYS_HEAP_CPU_LOCAL];
return PMRCreatePMR(psDevNode,
psPhysHeap,
uiSize,
uiChunkSize,
ui32NumPhysChunks,
ui32NumVirtChunks,
puiAllocIndices,
magma::page_shift(),
0,
pszAnnotation,
&kPmrTable,
pmr.release(),
PMR_TYPE_OSMEM,
ppsPMRPtr,
0);
}