From 85a20f43dcd49e7667e4e0beda7573600efdb838 Mon Sep 17 00:00:00 2001 From: fincs Date: Wed, 31 Oct 2018 16:32:10 +0100 Subject: [PATCH] NvAddressSpace: major overhaul, see details: - Now contains a 'page_size' field, used throughout the functions - Removed NvPageSize - Removed nvAddressSpaceReserveAlign/AtFixedAddr/Full - Added nvAddressSpaceAlloc/AllocFixed/Free (replacing above functions) - Removed nvAddressSpaceMapBuffer/UnmapBuffer - Added nvAddressSpaceMap/MapFixed/Modify/Unmap (replacing above functions) - Adapted NvBuffer/NvGpu to use the new functions --- nx/include/switch/nvidia/address_space.h | 20 ++++--- nx/source/nvidia/address_space.c | 68 +++++++++++++++++------- nx/source/nvidia/buffer.c | 10 ++-- nx/source/nvidia/gpu/gpu.c | 5 +- 4 files changed, 64 insertions(+), 39 deletions(-) diff --git a/nx/include/switch/nvidia/address_space.h b/nx/include/switch/nvidia/address_space.h index be920b13..dc51ef30 100644 --- a/nx/include/switch/nvidia/address_space.h +++ b/nx/include/switch/nvidia/address_space.h @@ -3,23 +3,21 @@ typedef struct NvAddressSpace { u32 fd; + u32 page_size; bool has_init; } NvAddressSpace; -typedef enum { - NvPageSize_4K = 0x1000, - NvPageSize_64K = 0x10000 -} NvPageSize; - -Result nvAddressSpaceCreate(NvAddressSpace* a); +Result nvAddressSpaceCreate(NvAddressSpace* a, u32 page_size); void nvAddressSpaceClose(NvAddressSpace* a); -Result nvAddressSpaceReserveAlign(NvAddressSpace* a, NvPageSize align, u32 pages, NvPageSize page_sz, iova_t* iova_out); -Result nvAddressSpaceReserveAtFixedAddr(NvAddressSpace* a, iova_t addr, u32 pages, NvPageSize page_sz); -Result nvAddressSpaceReserveFull(NvAddressSpace* a); +Result nvAddressSpaceAlloc(NvAddressSpace* a, bool sparse, u64 size, iova_t* iova_out); +Result nvAddressSpaceAllocFixed(NvAddressSpace* a, bool sparse, u64 size, iova_t iova); +Result nvAddressSpaceFree(NvAddressSpace* a, iova_t iova, u64 size); -Result nvAddressSpaceMapBuffer(NvAddressSpace* a, u32 fd, u32 flags, NvKind kind, iova_t* iova_out); -Result nvAddressSpaceUnmapBuffer(NvAddressSpace* a, iova_t iova); +Result nvAddressSpaceMap(NvAddressSpace* a, u32 nvmap_handle, bool is_gpu_cacheable, NvKind kind, iova_t* iova_out); +Result nvAddressSpaceMapFixed(NvAddressSpace* a, u32 nvmap_handle, bool is_gpu_cacheable, NvKind kind, iova_t iova); +Result nvAddressSpaceModify(NvAddressSpace* a, iova_t iova, u64 offset, u64 size, NvKind kind); +Result nvAddressSpaceUnmap(NvAddressSpace* a, iova_t iova); struct NvChannel; Result nvAddressSpaceBindToChannel(NvAddressSpace* a, struct NvChannel* channel); diff --git a/nx/source/nvidia/address_space.c b/nx/source/nvidia/address_space.c index 0d29eaaf..9badc09e 100644 --- a/nx/source/nvidia/address_space.c +++ b/nx/source/nvidia/address_space.c @@ -9,11 +9,12 @@ #include "nvidia/channel.h" #include "nvidia/address_space.h" -Result nvAddressSpaceCreate(NvAddressSpace* a) +Result nvAddressSpaceCreate(NvAddressSpace* a, u32 page_size) { Result rc; a->has_init = true; + a->page_size = page_size; rc = nvOpen(&a->fd, "/dev/nvhost-as-gpu"); @@ -21,7 +22,7 @@ Result nvAddressSpaceCreate(NvAddressSpace* a) a->fd = -1; if (R_SUCCEEDED(rc)) - rc = nvioctlNvhostAsGpu_InitializeEx(a->fd, 1, 0x10000); + rc = nvioctlNvhostAsGpu_InitializeEx(a->fd, 1, 0x10000); // Official sw uses hardcoded size if (R_FAILED(rc)) nvAddressSpaceClose(a); @@ -38,34 +39,65 @@ void nvAddressSpaceClose(NvAddressSpace* a) nvClose(a->fd); a->fd = -1; + a->has_init = false; } -Result nvAddressSpaceReserveAlign( - NvAddressSpace* a, NvPageSize align, u32 pages, NvPageSize page_sz, - iova_t* iova_out) { - return nvioctlNvhostAsGpu_AllocSpace(a->fd, pages, page_sz, 0, align, iova_out); +Result nvAddressSpaceAlloc(NvAddressSpace* a, bool sparse, u64 size, iova_t* iova_out) +{ + u32 num_pages = (size + a->page_size - 1) / a->page_size; // Round up to page size + return nvioctlNvhostAsGpu_AllocSpace(a->fd, num_pages, a->page_size, + sparse ? NvAllocSpaceFlags_Sparse : 0, a->page_size, iova_out); } -Result nvAddressSpaceReserveAtFixedAddr( - NvAddressSpace* a, iova_t addr, u32 pages, NvPageSize page_sz) { - return nvioctlNvhostAsGpu_AllocSpace(a->fd, pages, page_sz, 1, addr, NULL); +Result nvAddressSpaceAllocFixed(NvAddressSpace* a, bool sparse, u64 size, iova_t iova) +{ + if (iova & (a->page_size - 1)) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + u32 num_pages = size / a->page_size; // Round down + return nvioctlNvhostAsGpu_AllocSpace(a->fd, num_pages, a->page_size, + NvMapBufferFlags_FixedOffset | (sparse ? NvAllocSpaceFlags_Sparse : 0), iova, NULL); } -Result nvAddressSpaceReserveFull(NvAddressSpace* a) { - return nvAddressSpaceReserveAlign(a, NvPageSize_64K, 0x10000, NvPageSize_64K, NULL); +Result nvAddressSpaceFree(NvAddressSpace* a, iova_t iova, u64 size) +{ + if (iova & (a->page_size - 1)) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + u32 num_pages = size / a->page_size; // Round down + return nvioctlNvhostAsGpu_FreeSpace(a->fd, iova, num_pages, a->page_size); } -Result nvAddressSpaceMapBuffer( - NvAddressSpace* a, u32 fd, u32 flags, NvKind kind, - iova_t* iova_out) { - return nvioctlNvhostAsGpu_MapBufferEx( - a->fd, flags, kind, fd, 0x10000, 0, 0, 0, iova_out); +Result nvAddressSpaceMap(NvAddressSpace* a, u32 nvmap_handle, bool is_gpu_cacheable, NvKind kind, iova_t* iova_out) +{ + return nvioctlNvhostAsGpu_MapBufferEx(a->fd, + is_gpu_cacheable ? NvMapBufferFlags_IsCacheable : 0, kind, + nvmap_handle, a->page_size, 0, 0, 0, iova_out); } -Result nvAddressSpaceUnmapBuffer(NvAddressSpace* a, iova_t iova) { +Result nvAddressSpaceMapFixed(NvAddressSpace* a, u32 nvmap_handle, bool is_gpu_cacheable, NvKind kind, iova_t iova) +{ + if (iova & (a->page_size - 1)) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + return nvioctlNvhostAsGpu_MapBufferEx(a->fd, + NvMapBufferFlags_FixedOffset | (is_gpu_cacheable ? NvMapBufferFlags_IsCacheable : 0), kind, + nvmap_handle, a->page_size, 0, 0, iova, NULL); +} + +Result nvAddressSpaceModify(NvAddressSpace* a, iova_t iova, u64 offset, u64 size, NvKind kind) +{ + if (iova & (a->page_size - 1)) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + u64 end_offset = (offset + size + a->page_size - 1) &~ (a->page_size - 1); + offset &= a->page_size - 1; + size = end_offset - offset; + return nvioctlNvhostAsGpu_MapBufferEx(a->fd, NvMapBufferFlags_Modify, kind, 0, 0, offset, size, iova, NULL); +} + +Result nvAddressSpaceUnmap(NvAddressSpace* a, iova_t iova) +{ return nvioctlNvhostAsGpu_UnmapBuffer(a->fd, iova); } -Result nvAddressSpaceBindToChannel(NvAddressSpace* a, NvChannel* channel) { +Result nvAddressSpaceBindToChannel(NvAddressSpace* a, NvChannel* channel) +{ return nvioctlNvhostAsGpu_BindChannel(a->fd, channel->fd); } diff --git a/nx/source/nvidia/buffer.c b/nx/source/nvidia/buffer.c index dfd149e6..4f836039 100644 --- a/nx/source/nvidia/buffer.c +++ b/nx/source/nvidia/buffer.c @@ -76,8 +76,7 @@ Result nvBufferCreate( } if (R_SUCCEEDED(rc)) - rc = nvAddressSpaceMapBuffer(as, m->fd, - is_gpu_cacheable ? NvMapBufferFlags_IsCacheable : 0, NvKind_Pitch, &m->gpu_addr); + rc = nvAddressSpaceMap(as, m->fd, is_gpu_cacheable, NvKind_Pitch, &m->gpu_addr); if (R_FAILED(rc)) nvBufferFree(m); @@ -91,12 +90,12 @@ void nvBufferFree(NvBuffer* m) return; if (m->gpu_addr_texture) { - nvAddressSpaceUnmapBuffer(m->addr_space, m->gpu_addr_texture); + nvAddressSpaceUnmap(m->addr_space, m->gpu_addr_texture); m->gpu_addr_texture = 0; } if (m->gpu_addr) { - nvAddressSpaceUnmapBuffer(m->addr_space, m->gpu_addr); + nvAddressSpaceUnmap(m->addr_space, m->gpu_addr); m->gpu_addr = 0; } @@ -125,8 +124,7 @@ iova_t nvBufferGetGpuAddr(NvBuffer* m) { } Result nvBufferMapAsTexture(NvBuffer* m, NvKind kind) { - return nvAddressSpaceMapBuffer(m->addr_space, m->fd, - m->is_gpu_cacheable ? NvMapBufferFlags_IsCacheable : 0, kind, &m->gpu_addr_texture); + return nvAddressSpaceMap(m->addr_space, m->fd, m->is_gpu_cacheable, kind, &m->gpu_addr_texture); } iova_t nvBufferGetGpuAddrTexture(NvBuffer* m) { diff --git a/nx/source/nvidia/gpu/gpu.c b/nx/source/nvidia/gpu/gpu.c index c13d0b06..34faade1 100644 --- a/nx/source/nvidia/gpu/gpu.c +++ b/nx/source/nvidia/gpu/gpu.c @@ -33,10 +33,7 @@ Result nvGpuCreate(NvGpu* g) rc = nvChannelCreate(&g->gpu_channel, "/dev/nvhost-gpu"); if (R_SUCCEEDED(rc)) - rc = nvAddressSpaceCreate(&g->addr_space); - - if (R_SUCCEEDED(rc)) - rc = nvAddressSpaceReserveFull(&g->addr_space); + rc = nvAddressSpaceCreate(&g->addr_space, nvInfoGetGpuCharacteristics()->big_page_size); if (R_SUCCEEDED(rc)) rc = nvAddressSpaceBindToChannel(&g->addr_space, &g->gpu_channel);