From 0b93c42ba1b95c2ff4a7c9584e39e51ba0c856e1 Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Tue, 2 Jul 2024 11:23:24 -0500 Subject: [PATCH] nvk/nvkmd: Add memory and virtual address interfaces Part-of: --- src/nouveau/vulkan/nvkmd/nvkmd.c | 41 ++++++ src/nouveau/vulkan/nvkmd/nvkmd.h | 243 +++++++++++++++++++++++++++++++ 2 files changed, 284 insertions(+) diff --git a/src/nouveau/vulkan/nvkmd/nvkmd.c b/src/nouveau/vulkan/nvkmd/nvkmd.c index 09044eb43ce..1796db89956 100644 --- a/src/nouveau/vulkan/nvkmd/nvkmd.c +++ b/src/nouveau/vulkan/nvkmd/nvkmd.c @@ -15,3 +15,44 @@ nvkmd_try_create_pdev_for_drm(struct _drmDevice *drm_device, return nvkmd_nouveau_try_create_pdev(drm_device, log_obj, debug_flags, pdev_out); } + +VkResult +nvkmd_dev_alloc_mapped_mem(struct nvkmd_dev *dev, + struct vk_object_base *log_obj, + uint64_t size_B, uint64_t align_B, + enum nvkmd_mem_flags flags, + enum nvkmd_mem_map_flags map_flags, + struct nvkmd_mem **mem_out) +{ + struct nvkmd_mem *mem; + VkResult result; + + result = nvkmd_dev_alloc_mem(dev, log_obj, size_B, align_B, + flags | NVKMD_MEM_CAN_MAP, &mem); + if (result != VK_SUCCESS) + return result; + + assert(!(map_flags & NVKMD_MEM_MAP_FIXED)); + result = mem->ops->map(mem, log_obj, map_flags, NULL); + if (result != VK_SUCCESS) { + mem->ops->free(mem); + return result; + } + + *mem_out = mem; + + return VK_SUCCESS; +} + +void +nvkmd_mem_unref(struct nvkmd_mem *mem) +{ + assert(p_atomic_read(&mem->refcnt) > 0); + if (!p_atomic_dec_zero(&mem->refcnt)) + return; + + if (mem->map != NULL) + mem->ops->unmap(mem); + + mem->ops->free(mem); +} diff --git a/src/nouveau/vulkan/nvkmd/nvkmd.h b/src/nouveau/vulkan/nvkmd/nvkmd.h index 441a4a97a0e..25d57942db4 100644 --- a/src/nouveau/vulkan/nvkmd/nvkmd.h +++ b/src/nouveau/vulkan/nvkmd/nvkmd.h @@ -6,6 +6,8 @@ #define NVKMD_H 1 #include "nv_device_info.h" +#include "util/u_atomic.h" + #include "vulkan/vulkan_core.h" #include "nouveau_device.h" @@ -27,11 +29,38 @@ struct vk_object_base; * Enums */ +enum nvkmd_mem_flags { + /** VRAM on discrete GPUs or GART on integrated */ + NVKMD_MEM_LOCAL = 1 << 0, + NVKMD_MEM_GART = 1 << 1, + NVKMD_MEM_CAN_MAP = 1 << 2, + NVKMD_MEM_NO_SHARE = 1 << 3, +}; + +enum nvkmd_mem_map_flags { + NVKMD_MEM_MAP_RD = 1 << 0, + NVKMD_MEM_MAP_WR = 1 << 1, + NVKMD_MEM_MAP_RDWR = NVKMD_MEM_MAP_RD | NVKMD_MEM_MAP_WR, + NVKMD_MEM_MAP_FIXED = 1 << 2, +}; + +enum nvkmd_va_flags { + /** This VA should be configured for sparse (soft faults) */ + NVKMD_VA_SPARSE = 1 << 0, + + /** This VA should come from the capture/replay pool */ + NVKMD_VA_REPLAY = 1 << 1, + + /** Attempt to place this VA at the requested address and fail otherwise */ + NVKMD_VA_ALLOC_FIXED = 1 << 2, +}; + /* * Structs */ struct nvkmd_info { + bool has_dma_buf; bool has_get_vram_used; bool has_alloc_tiled; bool has_map_fixed; @@ -70,12 +99,89 @@ struct nvkmd_dev_ops { uint64_t (*get_gpu_timestamp)(struct nvkmd_dev *dev); int (*get_drm_fd)(struct nvkmd_dev *dev); + + VkResult (*alloc_mem)(struct nvkmd_dev *dev, + struct vk_object_base *log_obj, + uint64_t size_B, uint64_t align_B, + enum nvkmd_mem_flags flags, + struct nvkmd_mem **mem_out); + + VkResult (*alloc_tiled_mem)(struct nvkmd_dev *dev, + struct vk_object_base *log_obj, + uint64_t size_B, uint64_t align_B, + uint8_t pte_kind, uint16_t tile_mode, + enum nvkmd_mem_flags flags, + struct nvkmd_mem **mem_out); + + VkResult (*import_dma_buf)(struct nvkmd_dev *dev, + struct vk_object_base *log_obj, + int fd, struct nvkmd_mem **mem_out); + + VkResult (*alloc_va)(struct nvkmd_dev *dev, + struct vk_object_base *log_obj, + enum nvkmd_va_flags flags, uint8_t pte_kind, + uint64_t size_B, uint64_t align_B, + uint64_t fixed_addr, struct nvkmd_va **va_out); }; struct nvkmd_dev { const struct nvkmd_dev_ops *ops; }; +struct nvkmd_mem_ops { + void (*free)(struct nvkmd_mem *mem); + + VkResult (*map)(struct nvkmd_mem *mem, + struct vk_object_base *log_obj, + enum nvkmd_mem_map_flags flags, + void *fixed_addr); + + void (*unmap)(struct nvkmd_mem *mem); + + VkResult (*overmap)(struct nvkmd_mem *mem, + struct vk_object_base *log_obj); + + VkResult (*export_dma_buf)(struct nvkmd_mem *mem, + struct vk_object_base *log_obj, + int *fd_out); +}; + +struct nvkmd_mem { + const struct nvkmd_mem_ops *ops; + + uint32_t refcnt; + + enum nvkmd_mem_flags flags; + + uint64_t size_B; + const struct nvkmd_va *va; + void *map; +}; + +struct nvkmd_va_ops { + void (*free)(struct nvkmd_va *va); + + VkResult (*bind_mem)(struct nvkmd_va *va, + struct vk_object_base *log_obj, + uint64_t va_offset_B, + struct nvkmd_mem *mem, + uint64_t mem_offset_B, + uint64_t range_B); + + VkResult (*unbind)(struct nvkmd_va *va, + struct vk_object_base *log_obj, + uint64_t va_offset_B, + uint64_t range_B); +}; + +struct nvkmd_va { + const struct nvkmd_va_ops *ops; + enum nvkmd_va_flags flags; + uint8_t pte_kind; + uint64_t addr; + uint64_t size_B; +}; + /* * Macros * @@ -155,4 +261,141 @@ nvkmd_dev_get_drm_fd(struct nvkmd_dev *dev) return dev->ops->get_drm_fd(dev); } +static inline VkResult MUST_CHECK +nvkmd_dev_alloc_mem(struct nvkmd_dev *dev, + struct vk_object_base *log_obj, + uint64_t size_B, uint64_t align_B, + enum nvkmd_mem_flags flags, + struct nvkmd_mem **mem_out) +{ + return dev->ops->alloc_mem(dev, log_obj, size_B, align_B, flags, mem_out); +} + +static inline VkResult MUST_CHECK +nvkmd_dev_alloc_tiled_mem(struct nvkmd_dev *dev, + struct vk_object_base *log_obj, + uint64_t size_B, uint64_t align_B, + uint8_t pte_kind, uint16_t tile_mode, + enum nvkmd_mem_flags flags, + struct nvkmd_mem **mem_out) +{ + return dev->ops->alloc_tiled_mem(dev, log_obj, size_B, align_B, + pte_kind, tile_mode, flags, mem_out); +} + +/* Implies NVKMD_MEM_CAN_MAP */ +VkResult MUST_CHECK +nvkmd_dev_alloc_mapped_mem(struct nvkmd_dev *dev, + struct vk_object_base *log_obj, + uint64_t size_B, uint64_t align_B, + enum nvkmd_mem_flags flags, + enum nvkmd_mem_map_flags map_flags, + struct nvkmd_mem **mem_out); + +static inline VkResult MUST_CHECK +nvkmd_dev_import_dma_buf(struct nvkmd_dev *dev, + struct vk_object_base *log_obj, + int fd, struct nvkmd_mem **mem_out) +{ + return dev->ops->import_dma_buf(dev, log_obj, fd, mem_out); +} + +static inline VkResult MUST_CHECK +nvkmd_dev_alloc_va(struct nvkmd_dev *dev, + struct vk_object_base *log_obj, + enum nvkmd_va_flags flags, uint8_t pte_kind, + uint64_t size_B, uint64_t align_B, + uint64_t fixed_addr, struct nvkmd_va **va_out) +{ + return dev->ops->alloc_va(dev, log_obj, flags, pte_kind, size_B, align_B, + fixed_addr, va_out); +} + +static inline struct nvkmd_mem * +nvkmd_mem_ref(struct nvkmd_mem *mem) +{ + p_atomic_inc(&mem->refcnt); + return mem; +} + +void nvkmd_mem_unref(struct nvkmd_mem *mem); + +static inline VkResult MUST_CHECK +nvkmd_mem_map(struct nvkmd_mem *mem, struct vk_object_base *log_obj, + enum nvkmd_mem_map_flags flags, void *fixed_addr, + void **map_out) +{ + assert(mem->map == NULL); + + VkResult result = mem->ops->map(mem, log_obj, flags, fixed_addr); + if (result != VK_SUCCESS) + return result; + + *map_out = mem->map; + + return VK_SUCCESS; +} + +static inline void +nvkmd_mem_unmap(struct nvkmd_mem *mem) +{ + assert(mem->map != NULL); + mem->ops->unmap(mem); + assert(mem->map == NULL); +} + +static inline VkResult MUST_CHECK +nvkmd_mem_overmap(struct nvkmd_mem *mem, struct vk_object_base *log_obj) +{ + assert(mem->map != NULL); + VkResult result = mem->ops->overmap(mem, log_obj); + assert(mem->map == NULL); + return result; +} + +static inline VkResult MUST_CHECK +nvkmd_mem_export_dma_buf(struct nvkmd_mem *mem, + struct vk_object_base *log_obj, + int *fd_out) +{ + assert(!(mem->flags & NVKMD_MEM_NO_SHARE)); + + return mem->ops->export_dma_buf(mem, log_obj, fd_out); +} + +static inline void +nvkmd_va_free(struct nvkmd_va *va) +{ + va->ops->free(va); +} + +static inline VkResult MUST_CHECK +nvkmd_va_bind_mem(struct nvkmd_va *va, + struct vk_object_base *log_obj, + uint64_t va_offset_B, + struct nvkmd_mem *mem, + uint64_t mem_offset_B, + uint64_t range_B) +{ + assert(va_offset_B <= va->size_B); + assert(va_offset_B + range_B <= va->size_B); + assert(mem_offset_B <= mem->size_B); + assert(mem_offset_B + range_B <= mem->size_B); + + return va->ops->bind_mem(va, log_obj, va_offset_B, + mem, mem_offset_B, range_B); +} + +static inline VkResult MUST_CHECK +nvkmd_va_unbind(struct nvkmd_va *va, + struct vk_object_base *log_obj, + uint64_t va_offset_B, + uint64_t range_B) +{ + assert(va_offset_B <= va->size_B); + assert(va_offset_B + range_B <= va->size_B); + + return va->ops->unbind(va, log_obj, va_offset_B, range_B); +} + #endif /* NVKMD_H */