summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Mao <david.mao@amd.com>2016-12-07 14:25:55 +0800
committerQiang Yu <Qiang.Yu@amd.com>2017-05-17 11:15:03 +0800
commitc644ffdca6263e0200c4d7e03c9123f052d664fd (patch)
tree7c28d6d03a8672d7fa5a858a52f44e46f55d3d1c
parentb9a7c402812a21be74ab76b19e38ee81d69c2d4c (diff)
amdgpu: Sparse resource support for Vulkan v2
v2: 4836092b3c2ae93a1970a343137da6a6a8658152 forget to clean up the va remaps if the sparse image/buffer is going to be destroyed 7d339e3d804f23e4a1e72a82302e5e976b4d5794 [Xiaojie Yuan] fix null ptr dereference in va range free 6c11e6bffd882ae40784ed5d8822be0ae9295249 [Monk Liu] fix incorrect use on the remap_mutex In order to support sparse resource required by Vulkan, some changes are applied to libdrm. - va_map/unmap need to inc/dec the ref count of the buffer object, otherwise, the buffer may be freed ahead of va unmapping. - UMD want to unmap the va range without passing in the bo handle, libdrm have to maintain the mapping between va/offset/size and amdgpu_bo_handle. the remap_list is added to each device to maintain the va mapping. - It is a valid use case to remap the va to different bo. but Kernel did not support that. Therefore, I modify the libdrm to find the overlapped va and unmap the va first before mapping the va to the new bo. After these changes, dEQP-VK.api.buffer_[0,1,5,7] test are passed now. Signed-off-by: David Mao <david.mao@amd.com> Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com> Signed-off-by: Monk Liu <Monk.Liu@amd.com> Signed-off-by: Xiaojie Yuan <Xiaojie.Yuan@amd.com>
-rw-r--r--amdgpu/amdgpu.h22
-rw-r--r--amdgpu/amdgpu_bo.c101
-rw-r--r--amdgpu/amdgpu_device.c11
-rw-r--r--amdgpu/amdgpu_internal.h11
-rw-r--r--amdgpu/amdgpu_vamgr.c29
5 files changed, 174 insertions, 0 deletions
diff --git a/amdgpu/amdgpu.h b/amdgpu/amdgpu.h
index 233533a3..eab20c65 100644
--- a/amdgpu/amdgpu.h
+++ b/amdgpu/amdgpu.h
@@ -1479,6 +1479,28 @@ int amdgpu_bo_va_op_raw(amdgpu_device_handle dev,
uint32_t ops);
/**
+ * VA mapping/unmapping for the buffer object
+ *
+ * \param dev = \c [in] Device handle.
+ * \param bo - \c [in] BO handle
+ * \param offset - \c [in] Start offset to map
+ * \param size - \c [in] Size to map
+ * \param addr - \c [in] Start virtual address.
+ * \param flags - \c [in] Supported flags for mapping/unmapping
+ * \param ops - \c [in] AMDGPU_VA_OP_MAP or AMDGPU_VA_OP_UNMAP
+ *
+ * \return 0 on success\n
+ * <0 - Negative POSIX Error code
+ */
+int amdgpu_bo_va_op_refcounted(amdgpu_device_handle dev,
+ amdgpu_bo_handle bo,
+ uint64_t offset,
+ uint64_t size,
+ uint64_t addr,
+ uint64_t flags,
+ uint32_t ops);
+
+/**
* Reserve the virtual address range for SVM support
*
* \param amdgpu_device_handle
diff --git a/amdgpu/amdgpu_bo.c b/amdgpu/amdgpu_bo.c
index 5a9cdbe2..9534c404 100644
--- a/amdgpu/amdgpu_bo.c
+++ b/amdgpu/amdgpu_bo.c
@@ -968,3 +968,104 @@ int amdgpu_bo_va_op_raw(amdgpu_device_handle dev,
return r;
}
+
+int amdgpu_bo_va_op_refcounted(amdgpu_device_handle dev,
+ amdgpu_bo_handle ibo,
+ uint64_t offset,
+ uint64_t size,
+ uint64_t addr,
+ uint64_t flags,
+ uint32_t ops)
+{
+ amdgpu_bo_handle bo = ibo;
+ struct drm_amdgpu_gem_va va;
+ struct amdgpu_va_remap* vao = NULL;
+ struct amdgpu_va_remap* vahandle;
+
+ int r;
+
+ if (bo) {
+ if (bo->dev != dev)
+ return -EINVAL;
+ }
+
+ pthread_mutex_lock(&dev->remap_mutex);
+
+ /* find the previous mapped va object and its bo and unmap it*/
+ if (ops == AMDGPU_VA_OP_MAP) {
+ LIST_FOR_EACH_ENTRY(vahandle, &dev->remap_list, list) {
+ /* check whether the remap list alraedy have va that overlap with current request */
+ if (((vahandle->address <= addr) && (vahandle->address + vahandle->size) > addr) ||
+ ((vahandle->address > addr) && (vahandle->address < (addr + size)))) {
+ /* the overlap va mapping which need to be unmapped first */
+ vao = vahandle;
+ r = amdgpu_bo_va_op(vao->bo, vao->offset, vao->size, vao->address, flags, AMDGPU_VA_OP_UNMAP);
+ if (r) {
+ pthread_mutex_unlock(&dev->remap_mutex);
+ return -EINVAL;
+ }
+
+ /* Just drop the reference. */
+ amdgpu_bo_reference(&vao->bo, NULL);
+ /* remove the remap from list */
+ list_del(&vao->list);
+ free(vao);
+ }
+ }
+ vao = NULL;
+ } else if (ops == AMDGPU_VA_OP_UNMAP) {
+ LIST_FOR_EACH_ENTRY(vahandle, &dev->remap_list, list) {
+ if (vahandle->address == addr &&
+ vahandle->size == size &&
+ vahandle->offset == offset) {
+ vao = vahandle;
+ break;
+ }
+ }
+ if (vao) {
+ if (bo && (bo != vao->bo)) {
+ pthread_mutex_unlock(&dev->remap_mutex);
+ return -EINVAL;
+ }
+ } else {
+ pthread_mutex_unlock(&dev->remap_mutex);
+ return -EINVAL;
+ }
+ } else {
+ pthread_mutex_unlock(&dev->remap_mutex);
+ return -EINVAL;
+ }
+
+ /* we only allow null bo for unmap operation */
+ if (!bo)
+ bo = vao->bo;
+
+ r = amdgpu_bo_va_op(bo, offset, size, addr, flags, ops);
+ if (r == 0) {
+ /* unref the bo right after the unmap call */
+ if (ops == AMDGPU_VA_OP_UNMAP) {
+ /* Just drop the reference. */
+ amdgpu_bo_reference(&bo, NULL);
+ /* remove the remap from list */
+ list_del(&vao->list);
+ free(vao);
+ } else if (ops == AMDGPU_VA_OP_MAP) {
+ /* bump the refcount of bo! */
+ atomic_inc(&bo->refcount);
+ /* add the remap to list and vao should be NULL for map */
+ vao = (struct amdgpu_va_remap*)calloc(1, sizeof(struct amdgpu_va_remap));
+ if (!vao) {
+ pthread_mutex_unlock(&dev->remap_mutex);
+ return -ENOMEM;
+ }
+ vao->address = addr;
+ vao->size = size;
+ vao->offset = offset;
+ vao->bo = bo;
+ list_add(&vao->list, &dev->remap_list);
+ }
+ }
+ pthread_mutex_unlock(&dev->remap_mutex);
+ return r;
+}
+
diff --git a/amdgpu/amdgpu_device.c b/amdgpu/amdgpu_device.c
index 5d2a15ee..34585225 100644
--- a/amdgpu/amdgpu_device.c
+++ b/amdgpu/amdgpu_device.c
@@ -131,11 +131,19 @@ int amdgpu_get_auth(int fd, int *auth)
static void amdgpu_device_free_internal(amdgpu_device_handle dev)
{
+ struct amdgpu_va_remap* vao;
amdgpu_vamgr_deinit(&dev->vamgr_32);
amdgpu_vamgr_deinit(&dev->vamgr);
util_hash_table_destroy(dev->bo_flink_names);
util_hash_table_destroy(dev->bo_handles);
pthread_mutex_destroy(&dev->bo_table_mutex);
+
+ pthread_mutex_destroy(&dev->remap_mutex);
+ LIST_FOR_EACH_ENTRY(vao, &dev->remap_list, list) {
+ list_del(&vao->list);
+ free(vao);
+ }
+
util_hash_table_remove(fd_tab, UINT_TO_PTR(dev->fd));
close(dev->fd);
if ((dev->flink_fd >= 0) && (dev->fd != dev->flink_fd))
@@ -269,6 +277,9 @@ int amdgpu_device_initialize(int fd,
dev->svm_allocated = false;
+ pthread_mutex_init(&dev->remap_mutex, NULL);
+ list_inithead(&dev->remap_list);
+
*major_version = dev->major_version;
*minor_version = dev->minor_version;
*device_handle = dev;
diff --git a/amdgpu/amdgpu_internal.h b/amdgpu/amdgpu_internal.h
index 899909b0..9aa345bf 100644
--- a/amdgpu/amdgpu_internal.h
+++ b/amdgpu/amdgpu_internal.h
@@ -74,6 +74,14 @@ struct amdgpu_va {
struct amdgpu_bo_va_mgr *vamgr;
};
+struct amdgpu_va_remap{
+ uint64_t address;
+ uint64_t size;
+ uint64_t offset;
+ amdgpu_bo_handle bo;
+ struct list_head list;
+};
+
struct amdgpu_device {
atomic_t refcount;
int fd;
@@ -95,6 +103,9 @@ struct amdgpu_device {
struct amdgpu_bo_va_mgr vamgr_32;
/** svm range allocated */
bool svm_allocated;
+ /** The VA remapped list*/
+ pthread_mutex_t remap_mutex;
+ struct list_head remap_list;
};
struct amdgpu_bo {
diff --git a/amdgpu/amdgpu_vamgr.c b/amdgpu/amdgpu_vamgr.c
index 63124a4e..5c91d58f 100644
--- a/amdgpu/amdgpu_vamgr.c
+++ b/amdgpu/amdgpu_vamgr.c
@@ -475,9 +475,38 @@ int amdgpu_va_range_alloc_in_range(amdgpu_device_handle dev,
int amdgpu_va_range_free(amdgpu_va_handle va_range_handle)
{
+ amdgpu_device_handle dev;
+ uint64_t address;
+ uint64_t size;
+ struct amdgpu_va_remap* vahandle;
+ int r = 0;
+
if(!va_range_handle || !va_range_handle->address)
return 0;
+ dev = va_range_handle->dev;
+ address = va_range_handle->address;
+ size = va_range_handle->size;
+
+ pthread_mutex_lock(&dev->remap_mutex);
+ /* clean up previous mapping if it is used for virtual allocation */
+ LIST_FOR_EACH_ENTRY(vahandle, &dev->remap_list, list) {
+ /* check whether the remap list alraedy have va that overlap with current request */
+ if (((vahandle->address <= address) && (vahandle->address + vahandle->size) > address) ||
+ ((vahandle->address > address) && (vahandle->address < (address + size)))) {
+ /* the overlap va mapping which need to be unmapped first */
+ r = amdgpu_bo_va_op(vahandle->bo, vahandle->offset, vahandle->size, vahandle->address, 0, AMDGPU_VA_OP_UNMAP);
+ if (r)
+ return -EINVAL;
+ /* Just drop the reference. */
+ amdgpu_bo_reference(&vahandle->bo, NULL);
+ /* remove the remap from list */
+ list_del(&vahandle->list);
+ free(vahandle);
+ }
+ }
+ pthread_mutex_unlock(&dev->remap_mutex);
+
amdgpu_vamgr_free_va(va_range_handle->vamgr,
va_range_handle->address,
va_range_handle->size);