nvk: Move Heaps and BO binding into nvkmd
We may want to move this even higher, into NVK at some point. However the wrappers in the winsys layer really aren't doing us much. If anything, now that nvkdm_mem::va is an nvkmd_va *, this actually makes everything simpler because it's allocated through exactly the same paths as sparse VA. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30033>
This commit is contained in:
committed by
Marge Bot
parent
0856c27dd1
commit
d96bf198b4
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "nvkmd/nvkmd.h"
|
||||
#include "vk_drm_syncobj.h"
|
||||
#include "util/simple_mtx.h"
|
||||
#include "util/vma.h"
|
||||
|
||||
#include "drm-uapi/nouveau_drm.h"
|
||||
|
||||
@@ -35,10 +37,20 @@ VkResult nvkmd_nouveau_try_create_pdev(struct _drmDevice *drm_device,
|
||||
enum nvk_debug debug_flags,
|
||||
struct nvkmd_pdev **pdev_out);
|
||||
|
||||
#define NVKMD_NOUVEAU_HEAP_START ((uint64_t)4096)
|
||||
#define NVKMD_NOUVEAU_HEAP_END ((uint64_t)(1ull << 38))
|
||||
#define NVKMD_NOUVEAU_REPLAY_HEAP_START NVKMD_NOUVEAU_HEAP_END
|
||||
#define NVKMD_NOUVEAU_REPLAY_HEAP_END \
|
||||
((uint64_t)NOUVEAU_WS_DEVICE_KERNEL_RESERVATION_START)
|
||||
|
||||
struct nvkmd_nouveau_dev {
|
||||
struct nvkmd_dev base;
|
||||
|
||||
struct nouveau_ws_device *ws_dev;
|
||||
|
||||
simple_mtx_t heap_mutex;
|
||||
struct util_vma_heap heap;
|
||||
struct util_vma_heap replay_heap;
|
||||
};
|
||||
|
||||
NVKMD_DECL_SUBCLASS(dev, nouveau);
|
||||
@@ -75,18 +87,11 @@ VkResult nvkmd_nouveau_import_dma_buf(struct nvkmd_dev *dev,
|
||||
struct nvkmd_nouveau_va {
|
||||
struct nvkmd_va base;
|
||||
|
||||
struct nouveau_ws_device *dev;
|
||||
struct nvkmd_nouveau_dev *dev;
|
||||
};
|
||||
|
||||
NVKMD_DECL_SUBCLASS(va, nouveau);
|
||||
|
||||
/* Internal helper to create a VA object for already allocated VA */
|
||||
VkResult nvkmd_nouveau_va_create(struct nvkmd_nouveau_dev *dev,
|
||||
struct vk_object_base *log_obj,
|
||||
enum nvkmd_va_flags flags, uint8_t pte_kind,
|
||||
uint64_t addr, uint64_t size_B,
|
||||
struct nvkmd_va **va_out);
|
||||
|
||||
VkResult nvkmd_nouveau_alloc_va(struct nvkmd_dev *dev,
|
||||
struct vk_object_base *log_obj,
|
||||
enum nvkmd_va_flags flags, uint8_t pte_kind,
|
||||
|
||||
@@ -39,6 +39,18 @@ nvkmd_nouveau_create_dev(struct nvkmd_pdev *_pdev,
|
||||
"Failed to get DRM device: %m");
|
||||
}
|
||||
|
||||
simple_mtx_init(&dev->heap_mutex, mtx_plain);
|
||||
|
||||
STATIC_ASSERT(NVKMD_NOUVEAU_HEAP_START < NVKMD_NOUVEAU_HEAP_END);
|
||||
util_vma_heap_init(&dev->heap, NVKMD_NOUVEAU_HEAP_START,
|
||||
NVKMD_NOUVEAU_HEAP_END - NVKMD_NOUVEAU_HEAP_START);
|
||||
|
||||
STATIC_ASSERT(NVKMD_NOUVEAU_REPLAY_HEAP_START <
|
||||
NVKMD_NOUVEAU_REPLAY_HEAP_END);
|
||||
util_vma_heap_init(&dev->replay_heap,
|
||||
NVKMD_NOUVEAU_REPLAY_HEAP_START,
|
||||
NVKMD_NOUVEAU_REPLAY_HEAP_END - NVKMD_NOUVEAU_REPLAY_HEAP_START);
|
||||
|
||||
*dev_out = &dev->base;
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
@@ -23,11 +23,12 @@ nvkmd_nouveau_alloc_mem(struct nvkmd_dev *dev,
|
||||
static VkResult
|
||||
create_mem_or_close_bo(struct nvkmd_nouveau_dev *dev,
|
||||
struct vk_object_base *log_obj,
|
||||
uint64_t va_align_B, uint8_t pte_kind,
|
||||
enum nvkmd_mem_flags flags,
|
||||
uint8_t pte_kind,
|
||||
struct nouveau_ws_bo *bo,
|
||||
struct nvkmd_mem **mem_out)
|
||||
{
|
||||
const uint64_t size_B = bo->size;
|
||||
VkResult result;
|
||||
|
||||
struct nvkmd_nouveau_mem *mem = CALLOC_STRUCT(nvkmd_nouveau_mem);
|
||||
@@ -36,23 +37,31 @@ create_mem_or_close_bo(struct nvkmd_nouveau_dev *dev,
|
||||
goto fail_bo;
|
||||
}
|
||||
|
||||
struct nvkmd_va *va;
|
||||
result = nvkmd_nouveau_va_create(dev, log_obj, 0 /* flags */, pte_kind,
|
||||
bo->offset, bo->size, &va);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_mem;
|
||||
|
||||
mem->base.ops = &nvkmd_nouveau_mem_ops;
|
||||
mem->base.refcnt = 1;
|
||||
mem->base.flags = flags;
|
||||
mem->base.size_B = bo->size;
|
||||
mem->base.va = va;
|
||||
mem->base.size_B = size_B;
|
||||
mem->bo = bo;
|
||||
|
||||
result = nvkmd_dev_alloc_va(&dev->base, log_obj,
|
||||
0 /* flags */, pte_kind,
|
||||
size_B, va_align_B,
|
||||
0 /* fixed_addr */,
|
||||
&mem->base.va);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_mem;
|
||||
|
||||
result = nvkmd_va_bind_mem(mem->base.va, log_obj, 0 /* va_offset_B */,
|
||||
&mem->base, 0 /* mem_offset_B */, size_B);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_va;
|
||||
|
||||
*mem_out = &mem->base;
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail_va:
|
||||
nvkmd_va_free(mem->base.va);
|
||||
fail_mem:
|
||||
FREE(mem);
|
||||
fail_bo:
|
||||
@@ -83,8 +92,8 @@ nvkmd_nouveau_alloc_tiled_mem(struct nvkmd_dev *_dev,
|
||||
if (bo == NULL)
|
||||
return vk_errorf(log_obj, VK_ERROR_OUT_OF_DEVICE_MEMORY, "%m");
|
||||
|
||||
return create_mem_or_close_bo(dev, log_obj, flags,
|
||||
pte_kind, bo, mem_out);
|
||||
return create_mem_or_close_bo(dev, log_obj, align_B, pte_kind,
|
||||
flags, bo, mem_out);
|
||||
}
|
||||
|
||||
VkResult
|
||||
@@ -98,8 +107,11 @@ nvkmd_nouveau_import_dma_buf(struct nvkmd_dev *_dev,
|
||||
if (bo == NULL)
|
||||
return vk_errorf(log_obj, VK_ERROR_INVALID_EXTERNAL_HANDLE, "%m");
|
||||
|
||||
return create_mem_or_close_bo(dev, log_obj, (int)bo->flags,
|
||||
0 /* pte_kind */, bo, mem_out);
|
||||
return create_mem_or_close_bo(dev, log_obj,
|
||||
0 /* align_B */,
|
||||
0 /* pte_kind */,
|
||||
(int)bo->flags,
|
||||
bo, mem_out);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -107,7 +119,7 @@ nvkmd_nouveau_mem_free(struct nvkmd_mem *_mem)
|
||||
{
|
||||
struct nvkmd_nouveau_mem *mem = nvkmd_nouveau_mem(_mem);
|
||||
|
||||
FREE((void *)mem->base.va);
|
||||
nvkmd_va_free(mem->base.va);
|
||||
nouveau_ws_bo_destroy(mem->bo);
|
||||
FREE(mem);
|
||||
}
|
||||
|
||||
@@ -6,27 +6,107 @@
|
||||
#include "nvkmd_nouveau.h"
|
||||
|
||||
#include "nouveau_bo.h"
|
||||
#include "util/bitscan.h"
|
||||
#include "vk_log.h"
|
||||
|
||||
VkResult
|
||||
nvkmd_nouveau_va_create(struct nvkmd_nouveau_dev *dev,
|
||||
struct vk_object_base *log_obj,
|
||||
enum nvkmd_va_flags flags, uint8_t pte_kind,
|
||||
uint64_t addr, uint64_t size_B,
|
||||
struct nvkmd_va **va_out)
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <xf86drm.h>
|
||||
|
||||
static VkResult MUST_CHECK
|
||||
alloc_heap_addr_locked(struct nvkmd_nouveau_dev *dev,
|
||||
struct vk_object_base *log_obj,
|
||||
enum nvkmd_va_flags flags,
|
||||
uint64_t size_B, uint64_t align_B,
|
||||
uint64_t fixed_addr, uint64_t *addr_out)
|
||||
{
|
||||
struct nvkmd_nouveau_va *va = CALLOC_STRUCT(nvkmd_nouveau_va);
|
||||
if (va == NULL)
|
||||
return vk_error(log_obj, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
if (flags & NVKMD_VA_ALLOC_FIXED) {
|
||||
assert(flags & NVKMD_VA_REPLAY);
|
||||
if (fixed_addr < NVKMD_NOUVEAU_REPLAY_HEAP_START ||
|
||||
fixed_addr >= NVKMD_NOUVEAU_REPLAY_HEAP_END) {
|
||||
return vk_errorf(log_obj, VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS,
|
||||
"Capture address 0x%" PRIx64 " not in the reaplay "
|
||||
"heap address range [0x%" PRIx64 ", 0x%" PRIx64 ")",
|
||||
fixed_addr, NVKMD_NOUVEAU_REPLAY_HEAP_START,
|
||||
NVKMD_NOUVEAU_REPLAY_HEAP_END);
|
||||
}
|
||||
|
||||
va->base.ops = &nvkmd_nouveau_va_ops;
|
||||
va->base.flags = flags;
|
||||
va->base.pte_kind = pte_kind;
|
||||
va->base.addr = addr;
|
||||
va->base.size_B = size_B;
|
||||
va->dev = dev->ws_dev;
|
||||
if (fixed_addr & (align_B - 1)) {
|
||||
return vk_errorf(log_obj, VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS,
|
||||
"Unaligned capture address: 0x%" PRIx64, fixed_addr);
|
||||
}
|
||||
|
||||
*va_out = &va->base;
|
||||
if (!util_vma_heap_alloc_addr(&dev->replay_heap, fixed_addr, size_B)) {
|
||||
return vk_errorf(log_obj, VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS,
|
||||
"Replay address collision: 0x%" PRIx64, fixed_addr);
|
||||
}
|
||||
|
||||
*addr_out = fixed_addr;
|
||||
} else if (flags & NVKMD_VA_REPLAY) {
|
||||
*addr_out = util_vma_heap_alloc(&dev->replay_heap, size_B, align_B);
|
||||
if (*addr_out == 0)
|
||||
return vk_errorf(log_obj, VK_ERROR_OUT_OF_DEVICE_MEMORY,
|
||||
"Failed to allocate virtual address range");
|
||||
} else {
|
||||
*addr_out = util_vma_heap_alloc(&dev->heap, size_B, align_B);
|
||||
if (*addr_out == 0)
|
||||
return vk_errorf(log_obj, VK_ERROR_OUT_OF_DEVICE_MEMORY,
|
||||
"Failed to allocate virtual address range");
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult MUST_CHECK
|
||||
alloc_heap_addr(struct nvkmd_nouveau_dev *dev,
|
||||
struct vk_object_base *log_obj,
|
||||
enum nvkmd_va_flags flags,
|
||||
uint64_t size_B, uint64_t align_B,
|
||||
uint64_t fixed_addr, uint64_t *addr_out)
|
||||
{
|
||||
simple_mtx_lock(&dev->heap_mutex);
|
||||
VkResult result = alloc_heap_addr_locked(dev, log_obj, flags,
|
||||
size_B, align_B,
|
||||
fixed_addr, addr_out);
|
||||
simple_mtx_unlock(&dev->heap_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
free_heap_addr(struct nvkmd_nouveau_dev *dev,
|
||||
enum nvkmd_va_flags flags,
|
||||
uint64_t addr, uint64_t size_B)
|
||||
{
|
||||
simple_mtx_lock(&dev->heap_mutex);
|
||||
if (flags & NVKMD_VA_REPLAY) {
|
||||
assert(addr >= NVKMD_NOUVEAU_REPLAY_HEAP_START);
|
||||
assert(addr <= NVKMD_NOUVEAU_REPLAY_HEAP_END);
|
||||
assert(addr + size_B <= NVKMD_NOUVEAU_REPLAY_HEAP_END);
|
||||
|
||||
util_vma_heap_free(&dev->replay_heap, addr, size_B);
|
||||
} else {
|
||||
assert(addr >= NVKMD_NOUVEAU_HEAP_START);
|
||||
assert(addr <= NVKMD_NOUVEAU_HEAP_END);
|
||||
assert(addr + size_B <= NVKMD_NOUVEAU_HEAP_END);
|
||||
|
||||
util_vma_heap_free(&dev->heap, addr, size_B);
|
||||
}
|
||||
simple_mtx_unlock(&dev->heap_mutex);
|
||||
}
|
||||
|
||||
static VkResult MUST_CHECK
|
||||
vm_bind(struct nvkmd_nouveau_dev *dev,
|
||||
struct vk_object_base *log_obj,
|
||||
struct drm_nouveau_vm_bind_op *op)
|
||||
{
|
||||
struct drm_nouveau_vm_bind vmbind = {
|
||||
.op_count = 1,
|
||||
.op_ptr = (uint64_t)(uintptr_t)(void *)op,
|
||||
};
|
||||
int err = drmCommandWriteRead(dev->ws_dev->fd, DRM_NOUVEAU_VM_BIND,
|
||||
&vmbind, sizeof(vmbind));
|
||||
if (err)
|
||||
return vk_errorf(log_obj, VK_ERROR_UNKNOWN, "vm_bind failed: %m");
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
@@ -39,43 +119,84 @@ nvkmd_nouveau_alloc_va(struct nvkmd_dev *_dev,
|
||||
uint64_t fixed_addr, struct nvkmd_va **va_out)
|
||||
{
|
||||
struct nvkmd_nouveau_dev *dev = nvkmd_nouveau_dev(_dev);
|
||||
|
||||
assert((fixed_addr == 0) == !(flags & NVKMD_VA_ALLOC_FIXED));
|
||||
VkResult result;
|
||||
|
||||
struct nvkmd_nouveau_va *va = CALLOC_STRUCT(nvkmd_nouveau_va);
|
||||
if (va == NULL)
|
||||
return vk_error(log_obj, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
va->base.addr = nouveau_ws_alloc_vma(dev->ws_dev, fixed_addr,
|
||||
size_B, align_B,
|
||||
flags & NVKMD_VA_REPLAY,
|
||||
flags & NVKMD_VA_SPARSE);
|
||||
if (va->base.addr == 0) {
|
||||
FREE(va);
|
||||
return vk_errorf(log_obj, VK_ERROR_OUT_OF_DEVICE_MEMORY,
|
||||
"Failed to allocate virtual address range: %m");
|
||||
/* if the caller doesn't care, use the GPU page size */
|
||||
if (align_B == 0)
|
||||
align_B = 0x1000;
|
||||
|
||||
assert((fixed_addr == 0) == !(flags & NVKMD_VA_ALLOC_FIXED));
|
||||
|
||||
result = alloc_heap_addr(dev, log_obj, flags, size_B, align_B,
|
||||
fixed_addr, &va->base.addr);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_alloc;
|
||||
|
||||
if (flags & NVKMD_VA_SPARSE) {
|
||||
struct drm_nouveau_vm_bind_op bind = {
|
||||
.op = DRM_NOUVEAU_VM_BIND_OP_MAP,
|
||||
.addr = va->base.addr,
|
||||
.range = size_B,
|
||||
.flags = DRM_NOUVEAU_VM_BIND_SPARSE,
|
||||
};
|
||||
result = vm_bind(dev, log_obj, &bind);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_addr;
|
||||
}
|
||||
|
||||
va->base.ops = &nvkmd_nouveau_va_ops;
|
||||
va->base.flags = flags;
|
||||
va->base.pte_kind = pte_kind;
|
||||
va->base.size_B = size_B;
|
||||
va->dev = dev->ws_dev;
|
||||
va->dev = dev;
|
||||
|
||||
*va_out = &va->base;
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail_addr:
|
||||
free_heap_addr(dev, flags, va->base.addr, size_B);
|
||||
fail_alloc:
|
||||
FREE(va);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
nvkmd_nouveau_va_free(struct nvkmd_va *_va)
|
||||
{
|
||||
struct nvkmd_nouveau_va *va = nvkmd_nouveau_va(_va);
|
||||
VkResult result = VK_SUCCESS;
|
||||
|
||||
STATIC_ASSERT(VK_SUCCESS == 0);
|
||||
|
||||
{
|
||||
struct drm_nouveau_vm_bind_op bind = {
|
||||
.op = DRM_NOUVEAU_VM_BIND_OP_UNMAP,
|
||||
.addr = va->base.addr,
|
||||
.range = va->base.size_B,
|
||||
};
|
||||
result |= vm_bind(va->dev, NULL, &bind);
|
||||
}
|
||||
|
||||
if (va->base.flags & NVKMD_VA_SPARSE) {
|
||||
struct drm_nouveau_vm_bind_op bind = {
|
||||
.op = DRM_NOUVEAU_VM_BIND_OP_UNMAP,
|
||||
.addr = va->base.addr,
|
||||
.range = va->base.size_B,
|
||||
.flags = DRM_NOUVEAU_VM_BIND_SPARSE,
|
||||
};
|
||||
result |= vm_bind(va->dev, NULL, &bind);
|
||||
}
|
||||
|
||||
/* If unbinding fails, we leak the VA range */
|
||||
if (result == VK_SUCCESS)
|
||||
free_heap_addr(va->dev, va->base.flags, va->base.addr, va->base.size_B);
|
||||
|
||||
nouveau_ws_bo_unbind_vma(va->dev, va->base.addr, va->base.size_B);
|
||||
nouveau_ws_free_vma(va->dev, va->base.addr, va->base.size_B,
|
||||
va->base.flags & NVKMD_VA_REPLAY,
|
||||
va->base.flags & NVKMD_VA_SPARSE);
|
||||
FREE(va);
|
||||
}
|
||||
|
||||
@@ -90,12 +211,17 @@ nvkmd_nouveau_va_bind_mem(struct nvkmd_va *_va,
|
||||
struct nvkmd_nouveau_va *va = nvkmd_nouveau_va(_va);
|
||||
struct nvkmd_nouveau_mem *mem = nvkmd_nouveau_mem(_mem);
|
||||
|
||||
assert(va->dev == mem->bo->dev);
|
||||
nouveau_ws_bo_bind_vma(va->dev, mem->bo,
|
||||
va->base.addr + va_offset_B, range_B,
|
||||
mem_offset_B, va->base.pte_kind);
|
||||
assert(mem->bo->dev == va->dev->ws_dev);
|
||||
|
||||
return VK_SUCCESS;
|
||||
struct drm_nouveau_vm_bind_op bind = {
|
||||
.op = DRM_NOUVEAU_VM_BIND_OP_MAP,
|
||||
.handle = mem->bo->handle,
|
||||
.addr = va->base.addr + va_offset_B,
|
||||
.range = range_B,
|
||||
.bo_offset = mem_offset_B,
|
||||
.flags = va->base.pte_kind,
|
||||
};
|
||||
return vm_bind(va->dev, log_obj, &bind);
|
||||
}
|
||||
|
||||
static VkResult
|
||||
@@ -106,9 +232,12 @@ nvkmd_nouveau_va_unbind(struct nvkmd_va *_va,
|
||||
{
|
||||
struct nvkmd_nouveau_va *va = nvkmd_nouveau_va(_va);
|
||||
|
||||
nouveau_ws_bo_unbind_vma(va->dev, va->base.addr + va_offset_B, range_B);
|
||||
|
||||
return VK_SUCCESS;
|
||||
struct drm_nouveau_vm_bind_op bind = {
|
||||
.op = DRM_NOUVEAU_VM_BIND_OP_MAP,
|
||||
.addr = va->base.addr + va_offset_B,
|
||||
.range = range_B,
|
||||
};
|
||||
return vm_bind(va->dev, log_obj, &bind);
|
||||
}
|
||||
|
||||
const struct nvkmd_va_ops nvkmd_nouveau_va_ops = {
|
||||
|
||||
@@ -175,7 +175,7 @@ struct nvkmd_mem {
|
||||
enum nvkmd_mem_flags flags;
|
||||
|
||||
uint64_t size_B;
|
||||
const struct nvkmd_va *va;
|
||||
struct nvkmd_va *va;
|
||||
void *map;
|
||||
};
|
||||
|
||||
|
||||
+27
-150
@@ -13,129 +13,24 @@
|
||||
#include "nvidia/classes/cl9097.h"
|
||||
#include "nvidia/classes/clc597.h"
|
||||
|
||||
static void
|
||||
bo_bind(struct nouveau_ws_device *dev,
|
||||
uint32_t handle, uint64_t addr,
|
||||
uint64_t range, uint64_t bo_offset,
|
||||
uint32_t flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct drm_nouveau_vm_bind_op newbindop = {
|
||||
.op = DRM_NOUVEAU_VM_BIND_OP_MAP,
|
||||
.handle = handle,
|
||||
.addr = addr,
|
||||
.range = range,
|
||||
.bo_offset = bo_offset,
|
||||
.flags = flags,
|
||||
};
|
||||
struct drm_nouveau_vm_bind vmbind = {
|
||||
.op_count = 1,
|
||||
.op_ptr = (uint64_t)(uintptr_t)(void *)&newbindop,
|
||||
};
|
||||
ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_VM_BIND, &vmbind, sizeof(vmbind));
|
||||
if (ret)
|
||||
fprintf(stderr, "vm bind failed %d\n", errno);
|
||||
assert(ret == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
bo_unbind(struct nouveau_ws_device *dev,
|
||||
uint64_t offset, uint64_t range,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct drm_nouveau_vm_bind_op newbindop = {
|
||||
.op = DRM_NOUVEAU_VM_BIND_OP_UNMAP,
|
||||
.addr = offset,
|
||||
.range = range,
|
||||
.flags = flags,
|
||||
};
|
||||
struct drm_nouveau_vm_bind vmbind = {
|
||||
.op_count = 1,
|
||||
.op_ptr = (uint64_t)(uintptr_t)(void *)&newbindop,
|
||||
};
|
||||
ASSERTED int ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_VM_BIND, &vmbind, sizeof(vmbind));
|
||||
assert(ret == 0);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
nouveau_ws_alloc_vma(struct nouveau_ws_device *dev,
|
||||
uint64_t req_addr, uint64_t size, uint64_t align,
|
||||
bool bda_capture_replay,
|
||||
bool sparse_resident)
|
||||
{
|
||||
assert(dev->has_vm_bind);
|
||||
|
||||
/* if the caller doesn't care, use the GPU page size */
|
||||
if (align == 0)
|
||||
align = 0x1000;
|
||||
|
||||
uint64_t offset;
|
||||
simple_mtx_lock(&dev->vma_mutex);
|
||||
if (bda_capture_replay) {
|
||||
if (req_addr != 0) {
|
||||
bool found = util_vma_heap_alloc_addr(&dev->bda_heap, req_addr, size);
|
||||
offset = found ? req_addr : 0;
|
||||
} else {
|
||||
offset = util_vma_heap_alloc(&dev->bda_heap, size, align);
|
||||
}
|
||||
} else {
|
||||
offset = util_vma_heap_alloc(&dev->vma_heap, size, align);
|
||||
}
|
||||
simple_mtx_unlock(&dev->vma_mutex);
|
||||
|
||||
if (offset == 0) {
|
||||
if (dev->debug_flags & NVK_DEBUG_VM) {
|
||||
fprintf(stderr, "alloc vma FAILED: %" PRIx64 " sparse: %d\n",
|
||||
size, sparse_resident);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dev->debug_flags & NVK_DEBUG_VM)
|
||||
fprintf(stderr, "alloc vma %" PRIx64 " %" PRIx64 " sparse: %d\n",
|
||||
offset, size, sparse_resident);
|
||||
|
||||
if (sparse_resident)
|
||||
bo_bind(dev, 0, offset, size, 0, DRM_NOUVEAU_VM_BIND_SPARSE);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_ws_free_vma(struct nouveau_ws_device *dev,
|
||||
uint64_t offset, uint64_t size,
|
||||
bool bda_capture_replay,
|
||||
bool sparse_resident)
|
||||
{
|
||||
assert(dev->has_vm_bind);
|
||||
|
||||
if (dev->debug_flags & NVK_DEBUG_VM)
|
||||
fprintf(stderr, "free vma %" PRIx64 " %" PRIx64 "\n",
|
||||
offset, size);
|
||||
|
||||
if (sparse_resident)
|
||||
bo_unbind(dev, offset, size, DRM_NOUVEAU_VM_BIND_SPARSE);
|
||||
|
||||
simple_mtx_lock(&dev->vma_mutex);
|
||||
if (bda_capture_replay) {
|
||||
util_vma_heap_free(&dev->bda_heap, offset, size);
|
||||
} else {
|
||||
util_vma_heap_free(&dev->vma_heap, offset, size);
|
||||
}
|
||||
simple_mtx_unlock(&dev->vma_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_ws_bo_unbind_vma(struct nouveau_ws_device *dev,
|
||||
uint64_t offset, uint64_t range)
|
||||
{
|
||||
assert(dev->has_vm_bind);
|
||||
|
||||
if (dev->debug_flags & NVK_DEBUG_VM)
|
||||
fprintf(stderr, "unbind vma %" PRIx64 " %" PRIx64 "\n",
|
||||
offset, range);
|
||||
bo_unbind(dev, offset, range, 0);
|
||||
struct drm_nouveau_vm_bind_op newbindop = {
|
||||
.op = DRM_NOUVEAU_VM_BIND_OP_UNMAP,
|
||||
.addr = offset,
|
||||
.range = range,
|
||||
};
|
||||
struct drm_nouveau_vm_bind vmbind = {
|
||||
.op_count = 1,
|
||||
.op_ptr = (uint64_t)(uintptr_t)(void *)&newbindop,
|
||||
};
|
||||
ASSERTED int ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_VM_BIND,
|
||||
&vmbind, sizeof(vmbind));
|
||||
assert(ret == 0);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -148,10 +43,21 @@ nouveau_ws_bo_bind_vma(struct nouveau_ws_device *dev,
|
||||
{
|
||||
assert(dev->has_vm_bind);
|
||||
|
||||
if (dev->debug_flags & NVK_DEBUG_VM)
|
||||
fprintf(stderr, "bind vma %x %" PRIx64 " %" PRIx64 " %" PRIx64 " %d\n",
|
||||
bo->handle, addr, range, bo_offset, pte_kind);
|
||||
bo_bind(dev, bo->handle, addr, range, bo_offset, pte_kind);
|
||||
struct drm_nouveau_vm_bind_op newbindop = {
|
||||
.op = DRM_NOUVEAU_VM_BIND_OP_MAP,
|
||||
.handle = bo->handle,
|
||||
.addr = addr,
|
||||
.range = range,
|
||||
.bo_offset = bo_offset,
|
||||
.flags = pte_kind,
|
||||
};
|
||||
struct drm_nouveau_vm_bind vmbind = {
|
||||
.op_count = 1,
|
||||
.op_ptr = (uint64_t)(uintptr_t)(void *)&newbindop,
|
||||
};
|
||||
ASSERTED int ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_VM_BIND,
|
||||
&vmbind, sizeof(vmbind));
|
||||
assert(ret == 0);
|
||||
}
|
||||
|
||||
struct nouveau_ws_bo *
|
||||
@@ -230,31 +136,15 @@ nouveau_ws_bo_new_tiled_locked(struct nouveau_ws_device *dev,
|
||||
|
||||
struct nouveau_ws_bo *bo = CALLOC_STRUCT(nouveau_ws_bo);
|
||||
bo->size = size;
|
||||
bo->align = align;
|
||||
bo->offset = -1ULL;
|
||||
bo->handle = req.info.handle;
|
||||
bo->map_handle = req.info.map_handle;
|
||||
bo->dev = dev;
|
||||
bo->flags = flags;
|
||||
bo->refcnt = 1;
|
||||
|
||||
if (dev->has_vm_bind) {
|
||||
bo->offset = nouveau_ws_alloc_vma(dev, 0, bo->size, align, false, false);
|
||||
if (bo->offset == 0)
|
||||
goto fail_gem_new;
|
||||
|
||||
nouveau_ws_bo_bind_vma(dev, bo, bo->offset, bo->size, 0, 0);
|
||||
}
|
||||
|
||||
_mesa_hash_table_insert(dev->bos, (void *)(uintptr_t)bo->handle, bo);
|
||||
|
||||
return bo;
|
||||
|
||||
fail_gem_new:
|
||||
drmCloseBufferHandle(dev->fd, req.info.handle);
|
||||
FREE(bo);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nouveau_ws_bo *
|
||||
@@ -320,7 +210,6 @@ nouveau_ws_bo_from_dma_buf_locked(struct nouveau_ws_device *dev, int fd)
|
||||
|
||||
struct nouveau_ws_bo *bo = CALLOC_STRUCT(nouveau_ws_bo);
|
||||
bo->size = info.size;
|
||||
bo->offset = info.offset;
|
||||
bo->handle = info.handle;
|
||||
bo->map_handle = info.map_handle;
|
||||
bo->dev = dev;
|
||||
@@ -333,17 +222,10 @@ nouveau_ws_bo_from_dma_buf_locked(struct nouveau_ws_device *dev, int fd)
|
||||
|
||||
assert(bo->size == align64(bo->size, align));
|
||||
|
||||
bo->offset = nouveau_ws_alloc_vma(dev, 0, bo->size, align, false, false);
|
||||
if (bo->offset == 0)
|
||||
goto fail_calloc;
|
||||
|
||||
nouveau_ws_bo_bind_vma(dev, bo, bo->offset, bo->size, 0, 0);
|
||||
_mesa_hash_table_insert(dev->bos, (void *)(uintptr_t)handle, bo);
|
||||
|
||||
return bo;
|
||||
|
||||
fail_calloc:
|
||||
FREE(bo);
|
||||
fail_fd_to_handle:
|
||||
drmCloseBufferHandle(dev->fd, handle);
|
||||
|
||||
@@ -390,11 +272,6 @@ nouveau_ws_bo_destroy(struct nouveau_ws_bo *bo)
|
||||
if (--bo->refcnt == 0) {
|
||||
_mesa_hash_table_remove_key(dev->bos, (void *)(uintptr_t)bo->handle);
|
||||
|
||||
if (dev->has_vm_bind) {
|
||||
nouveau_ws_bo_unbind_vma(bo->dev, bo->offset, bo->size);
|
||||
nouveau_ws_free_vma(bo->dev, bo->offset, bo->size, false, false);
|
||||
}
|
||||
|
||||
drmCloseBufferHandle(bo->dev->fd, bo->handle);
|
||||
FREE(bo);
|
||||
}
|
||||
|
||||
@@ -33,24 +33,14 @@ enum nouveau_ws_bo_map_flags {
|
||||
};
|
||||
|
||||
struct nouveau_ws_bo {
|
||||
uint64_t size;
|
||||
uint64_t offset;
|
||||
uint64_t align;
|
||||
uint64_t map_handle;
|
||||
struct nouveau_ws_device *dev;
|
||||
uint64_t size;
|
||||
uint64_t map_handle;
|
||||
uint32_t handle;
|
||||
enum nouveau_ws_bo_flags flags;
|
||||
atomic_uint_fast32_t refcnt;
|
||||
};
|
||||
|
||||
uint64_t nouveau_ws_alloc_vma(struct nouveau_ws_device *dev,
|
||||
uint64_t addr, uint64_t size, uint64_t align,
|
||||
bool bda, bool sparse);
|
||||
|
||||
void nouveau_ws_free_vma(struct nouveau_ws_device *dev,
|
||||
uint64_t offset, uint64_t size,
|
||||
bool bda, bool sparse);
|
||||
|
||||
void nouveau_ws_bo_bind_vma(struct nouveau_ws_device *dev,
|
||||
struct nouveau_ws_bo *bo,
|
||||
uint64_t addr,
|
||||
|
||||
@@ -289,17 +289,12 @@ nouveau_ws_device_new(drmDevicePtr drm_device,
|
||||
if (version < 0x01000301)
|
||||
goto out_err;
|
||||
|
||||
const uint64_t BDA = 1ull << 38;
|
||||
const uint64_t KERN = 1ull << 39;
|
||||
const uint64_t KERN = NOUVEAU_WS_DEVICE_KERNEL_RESERVATION_START;
|
||||
const uint64_t TOP = 1ull << 40;
|
||||
struct drm_nouveau_vm_init vminit = { KERN, TOP-KERN };
|
||||
int ret = drmCommandWrite(fd, DRM_NOUVEAU_VM_INIT, &vminit, sizeof(vminit));
|
||||
if (ret == 0) {
|
||||
if (ret == 0)
|
||||
device->has_vm_bind = true;
|
||||
util_vma_heap_init(&device->vma_heap, 4096, BDA - 4096);
|
||||
util_vma_heap_init(&device->bda_heap, BDA, KERN - BDA);
|
||||
simple_mtx_init(&device->vma_mutex, mtx_plain);
|
||||
}
|
||||
|
||||
if (nouveau_ws_device_alloc(fd, device))
|
||||
goto out_err;
|
||||
@@ -384,11 +379,6 @@ nouveau_ws_device_new(drmDevicePtr drm_device,
|
||||
return device;
|
||||
|
||||
out_err:
|
||||
if (device->has_vm_bind) {
|
||||
util_vma_heap_finish(&device->vma_heap);
|
||||
util_vma_heap_finish(&device->bda_heap);
|
||||
simple_mtx_destroy(&device->vma_mutex);
|
||||
}
|
||||
if (ver)
|
||||
drmFreeVersion(ver);
|
||||
out_open:
|
||||
@@ -406,12 +396,6 @@ nouveau_ws_device_destroy(struct nouveau_ws_device *device)
|
||||
_mesa_hash_table_destroy(device->bos, NULL);
|
||||
simple_mtx_destroy(&device->bos_lock);
|
||||
|
||||
if (device->has_vm_bind) {
|
||||
util_vma_heap_finish(&device->vma_heap);
|
||||
util_vma_heap_finish(&device->bda_heap);
|
||||
simple_mtx_destroy(&device->vma_mutex);
|
||||
}
|
||||
|
||||
close(device->fd);
|
||||
FREE(device);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "nouveau_private.h"
|
||||
#include "nv_device_info.h"
|
||||
#include "util/simple_mtx.h"
|
||||
#include "util/vma.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -42,6 +41,8 @@ enum nvk_debug {
|
||||
NVK_DEBUG_NO_CBUF = 1ull << 5,
|
||||
};
|
||||
|
||||
#define NOUVEAU_WS_DEVICE_KERNEL_RESERVATION_START (1ull << 39)
|
||||
|
||||
struct nouveau_ws_device {
|
||||
int fd;
|
||||
|
||||
@@ -56,9 +57,6 @@ struct nouveau_ws_device {
|
||||
struct hash_table *bos;
|
||||
|
||||
bool has_vm_bind;
|
||||
struct util_vma_heap vma_heap;
|
||||
struct util_vma_heap bda_heap;
|
||||
simple_mtx_t vma_mutex;
|
||||
};
|
||||
|
||||
struct nouveau_ws_device *nouveau_ws_device_new(struct _drmDevice *drm_device,
|
||||
|
||||
Reference in New Issue
Block a user