Skip to content
Snippets Groups Projects
Commit cc17fd4a authored by Dave Airlie's avatar Dave Airlie
Browse files

nouveau/winsys: add support for the vma bind interfaces

parent ef844fc0
No related branches found
No related tags found
Loading
#include "nouveau_bo.h"
#include <nouveau_drm.h>
#include "drm-uapi/nouveau_drm.h"
#include <xf86drm.h>
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <sys/mman.h>
#include "util/u_math.h"
#if NVK_NEW_UAPI == 1
uint64_t
nouveau_ws_alloc_vma(struct nouveau_ws_device *dev,
uint64_t size, uint64_t align,
bool sparse)
{
uint64_t offset;
int ret;
simple_mtx_lock(&dev->vma_mutex);
offset = util_vma_heap_alloc(&dev->vma_heap, size, align);
simple_mtx_unlock(&dev->vma_mutex);
if (dev->debug_flags & NVK_DEBUG_VM)
fprintf(stderr, "alloc vma %lx %lx sparse: %d\n",
offset, size, sparse);
struct drm_nouveau_vm_bind_op newbindop = {
.op = DRM_NOUVEAU_VM_BIND_OP_ALLOC,
.addr = offset,
.range = size,
.flags = sparse ? DRM_NOUVEAU_VM_BIND_SPARSE : 0,
};
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);
return offset;
}
void
nouveau_ws_free_vma(struct nouveau_ws_device *dev,
uint64_t offset, uint64_t size)
{
int ret;
if (dev->debug_flags & NVK_DEBUG_VM)
fprintf(stderr, "free vma %lx %lx\n",
offset, size);
struct drm_nouveau_vm_bind_op newbindop = {
.op = DRM_NOUVEAU_VM_BIND_OP_FREE,
.addr = offset,
.range = size,
};
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);
simple_mtx_lock(&dev->vma_mutex);
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)
{
if (dev->debug_flags & NVK_DEBUG_VM)
fprintf(stderr, "unbind vma %lx %lx\n",
offset, range);
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
nouveau_ws_bo_bind_vma(struct nouveau_ws_device *dev,
uint32_t handle,
uint64_t addr,
uint64_t range,
uint64_t bo_offset,
uint32_t pte_kind)
{
int ret;
if (dev->debug_flags & NVK_DEBUG_VM)
fprintf(stderr, "bind vma %x %lx %lx %lx %d\n",
handle, addr, range, bo_offset, pte_kind);
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 = (uint32_t)pte_kind,
};
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);
}
#endif
struct nouveau_ws_bo *
nouveau_ws_bo_new(struct nouveau_ws_device *dev,
......@@ -50,7 +161,12 @@ nouveau_ws_bo_new_tiled(struct nouveau_ws_device *dev,
if (align == 0)
align = 0x1000;
#if NVK_NEW_UAPI == 0
req.info.domain = NOUVEAU_GEM_TILE_NONCONTIG;
#else
req.info.domain = 0;
#endif
if (flags & NOUVEAU_WS_BO_GART)
req.info.domain |= NOUVEAU_GEM_DOMAIN_GART;
else
......@@ -59,12 +175,14 @@ nouveau_ws_bo_new_tiled(struct nouveau_ws_device *dev,
if (flags & NOUVEAU_WS_BO_MAP)
req.info.domain |= NOUVEAU_GEM_DOMAIN_MAPPABLE;
#if NVK_NEW_UAPI == 0
assert(pte_kind == 0 || !(flags & NOUVEAU_WS_BO_GART));
assert(tile_mode == 0 || !(flags & NOUVEAU_WS_BO_GART));
req.info.tile_flags = (uint32_t)pte_kind << 8;
req.info.tile_mode = tile_mode;
#endif
req.info.size = size;
req.info.size = ALIGN(size, align);
req.align = align;
int ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_NEW, &req, sizeof(req));
......@@ -73,14 +191,27 @@ nouveau_ws_bo_new_tiled(struct nouveau_ws_device *dev,
return NULL;
}
bo->size = req.info.size;
bo->size = size;
bo->align = align;
#if NVK_NEW_UAPI == 0
bo->offset = req.info.offset;
#else
bo->offset = -1ULL;
#endif
bo->handle = req.info.handle;
bo->map_handle = req.info.map_handle;
bo->dev = dev;
bo->flags = flags;
bo->refcnt = 1;
#if NVK_NEW_UAPI == 1
if (!(flags & NOUVEAU_WS_BO_NO_VMA)) {
assert(pte_kind == 0);
uint64_t size = ALIGN(bo->size, 4096);
bo->offset = nouveau_ws_alloc_vma(dev, size, align, false);
nouveau_ws_bo_bind_vma(dev, bo->handle, bo->offset, size, 0, 0);
}
#endif
return bo;
}
......@@ -89,7 +220,14 @@ nouveau_ws_bo_destroy(struct nouveau_ws_bo *bo)
{
if (--bo->refcnt)
return;
#if NVK_NEW_UAPI == 1
if (!(bo->flags & NOUVEAU_WS_BO_NO_VMA)) {
uint64_t size = ALIGN(bo->size, 4096);
nouveau_ws_bo_unbind_vma(bo->dev, bo->offset, size);
nouveau_ws_free_vma(bo->dev, bo->offset, ALIGN(bo->size, bo->align));
} else
assert(bo->offset == -1);
#endif
drmCloseBufferHandle(bo->dev->fd, bo->handle);
FREE(bo);
}
......
......@@ -23,6 +23,7 @@ enum nouveau_ws_bo_flags {
NOUVEAU_WS_BO_LOCAL = 0 << 0,
NOUVEAU_WS_BO_GART = 1 << 0,
NOUVEAU_WS_BO_MAP = 1 << 1,
NOUVEAU_WS_BO_NO_VMA = 1 << 2,
};
enum nouveau_ws_bo_map_flags {
......@@ -34,6 +35,7 @@ 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;
uint32_t handle;
......@@ -41,6 +43,23 @@ struct nouveau_ws_bo {
atomic_uint_fast32_t refcnt;
};
#if NVK_NEW_UAPI == 1
uint64_t nouveau_ws_alloc_vma(struct nouveau_ws_device *dev,
uint64_t size, uint64_t align, bool sparse);
void nouveau_ws_free_vma(struct nouveau_ws_device *dev,
uint64_t offset, uint64_t size);
void nouveau_ws_bo_bind_vma(struct nouveau_ws_device *dev,
uint32_t handle,
uint64_t addr,
uint64_t range,
uint64_t bo_offset,
uint32_t pte_kind);
void nouveau_ws_bo_unbind_vma(struct nouveau_ws_device *dev,
uint64_t offset, uint64_t range);
#endif
struct nouveau_ws_bo *nouveau_ws_bo_new(struct nouveau_ws_device *,
uint64_t size, uint64_t align,
enum nouveau_ws_bo_flags);
......
......@@ -4,6 +4,8 @@
#include <unistd.h>
#include <xf86drm.h>
#include <nouveau_drm.h>
#include "drm-uapi/nouveau_drm.h"
#include <nouveau/nvif/ioctl.h>
#include <nvif/cl0080.h>
#include <nvif/class.h>
......@@ -78,6 +80,7 @@ nouveau_ws_device_set_dbg_flags(struct nouveau_ws_device *dev)
{ "push_dump", NVK_DEBUG_PUSH_DUMP },
{ "push_sync", NVK_DEBUG_PUSH_SYNC },
{ "zero_memory", NVK_DEBUG_ZERO_MEMORY },
{ "vm", NVK_DEBUG_VM },
{ NULL, 0 },
};
......@@ -195,14 +198,35 @@ nouveau_ws_device_new(drmDevicePtr drm_device)
if (!ver)
goto out_err;
#if NVK_NEW_UAPI == 1
const uint64_t TOP = 1ull << 40;
const uint64_t KERN = 1ull << 39;
util_vma_heap_init(&device->vma_heap, 4096, (TOP - KERN) - 4096);
simple_mtx_init(&device->vma_mutex, mtx_plain);
device->vma_heap.alloc_high = false;
#endif
uint32_t version =
ver->version_major << 24 |
ver->version_minor << 8 |
ver->version_patchlevel;
drmFreeVersion(ver);
#if NVK_NEW_UAPI == 1
/* don't work on older kernels */
if (version < 0x01000400)
goto out_err;
#else
if (version < 0x01000301)
goto out_err;
#endif
#if NVK_NEW_UAPI == 1
/* start the new VM mode */
struct drm_nouveau_vm_init vminit = { TOP-KERN, KERN };
ASSERTED int ret = drmCommandWrite(fd, DRM_NOUVEAU_VM_INIT, &vminit, sizeof(vminit));
assert(!ret);
#endif
device->info = (struct nv_device_info) {
.pci_domain = drm_device->businfo.pci->domain,
......@@ -270,7 +294,9 @@ nouveau_ws_device_destroy(struct nouveau_ws_device *device)
{
if (!device)
return;
#if NVK_NEW_UAPI == 1
util_vma_heap_finish(&device->vma_heap);
#endif
close(device->fd);
FREE(device->chipset_name);
FREE(device->device_name);
......
......@@ -4,6 +4,9 @@
#include "nouveau_private.h"
#include "nv_device_info.h"
#include "util/simple_mtx.h"
#include "util/vma.h"
#include <stddef.h>
struct _drmDevice;
......@@ -12,6 +15,8 @@ struct _drmDevice;
extern "C" {
#endif
#define NVK_NEW_UAPI 0
enum nvk_debug {
/* dumps all push buffers after submission */
NVK_DEBUG_PUSH_DUMP = 1ull << 0,
......@@ -26,6 +31,10 @@ enum nvk_debug {
/* Zero all client memory allocations
*/
NVK_DEBUG_ZERO_MEMORY = 1ull << 2,
/* Dump VM bind/unbinds
*/
NVK_DEBUG_VM = 1ull << 3,
};
struct nouveau_ws_device {
......@@ -52,6 +61,10 @@ struct nouveau_ws_device {
uint16_t mp_count;
enum nvk_debug debug_flags;
#if NVK_NEW_UAPI == 1
struct util_vma_heap vma_heap;
simple_mtx_t vma_mutex;
#endif
};
struct nouveau_ws_device *nouveau_ws_device_new(struct _drmDevice *drm_device);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment