summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Xie <AlexBin.Xie@amd.com>2015-10-29 16:13:45 -0400
committerQiang Yu <Qiang.Yu@amd.com>2017-05-17 10:24:19 +0800
commitfc110c512465e3532765c924326bd9b2961603bf (patch)
tree8514cf3cb7f4e429419f2d90b68bd1a78e9d77fb
parent2740b4d1f14727cf16d24b813ad97909105dabdc (diff)
amdgpu: Implement multiGPU SVM support v3
With this change, if there are multiple GPU devices, SVM range and allocation is global to all GPU devices. This is to meet the OpenCL 2.0 SVM requirement. This is not a perfect solution. But we have not found better solution. Constraints: 1. Application should initialize all relevant devices before allocate SVM address. 2. If devices do not have similar GPU VM configuration, libdrm can disable SVM when new device are initialized. v3: a912dddb82071781c21265725556404ee2837e5e undo reference counter when SVM init fails 869a8f1c8a73aeddaf9439796df89955044553fb fix to free va for svm at deinit 885418a66eb9922f416ce2551bac9f1297599af9 Mark SVM invalid when deinit SVM in any GPU device. To make SVM valid again, application should deinte all devices and re-initialize all GPU devices again. v2: 1. Put svm_refcount and svm_valid as a field of amdgpu_bo_va_mgr. 2. Adjust title. Signed-off-by: Alex Xie <AlexBin.Xie@amd.com> Reviewed-by: Jammy Zhou <Jammy.Zhou@amd.com> Reviewed-by: Christian K├Ânig <christian.koenig@amd.com> Signed-off-by: Xiaojie Yuan <Xiaojie.Yuan@amd.com>
-rw-r--r--amdgpu/amdgpu_device.c2
-rw-r--r--amdgpu/amdgpu_internal.h8
-rw-r--r--amdgpu/amdgpu_vamgr.c75
3 files changed, 63 insertions, 22 deletions
diff --git a/amdgpu/amdgpu_device.c b/amdgpu/amdgpu_device.c
index f473d2da..807f63ed 100644
--- a/amdgpu/amdgpu_device.c
+++ b/amdgpu/amdgpu_device.c
@@ -267,6 +267,8 @@ int amdgpu_device_initialize(int fd,
amdgpu_vamgr_init(&dev->vamgr_32, start, max,
dev->dev_info.virtual_address_alignment);
+ dev->svm_allocated = false;
+
*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 0cad6b61..f4fbd13b 100644
--- a/amdgpu/amdgpu_internal.h
+++ b/amdgpu/amdgpu_internal.h
@@ -60,6 +60,10 @@ struct amdgpu_bo_va_mgr {
struct list_head va_holes;
pthread_mutex_t bo_va_mutex;
uint32_t va_alignment;
+ /* reference count. It is used by SVM for mulit GPU.*/
+ atomic_t refcount;
+ /* Is the VM manager valid. It is used by SVM for mulit GPU.*/
+ bool valid;
};
struct amdgpu_va {
@@ -89,8 +93,8 @@ struct amdgpu_device {
struct amdgpu_bo_va_mgr vamgr;
/** The VA manager for the 32bit address space */
struct amdgpu_bo_va_mgr vamgr_32;
- /** The VA manager for SVM address space */
- struct amdgpu_bo_va_mgr *vamgr_svm;
+ /** svm range allocated */
+ bool svm_allocated;
};
struct amdgpu_bo {
diff --git a/amdgpu/amdgpu_vamgr.c b/amdgpu/amdgpu_vamgr.c
index 2a9f28a1..54711ee5 100644
--- a/amdgpu/amdgpu_vamgr.c
+++ b/amdgpu/amdgpu_vamgr.c
@@ -33,6 +33,9 @@
#include "amdgpu_internal.h"
#include "util_math.h"
+/* Devices share SVM range. So a global SVM VAM manager is needed. */
+static struct amdgpu_bo_va_mgr vamgr_svm;
+
int amdgpu_va_range_query(amdgpu_device_handle dev,
enum amdgpu_gpu_va_range type, uint64_t *start, uint64_t *end)
{
@@ -42,9 +45,9 @@ int amdgpu_va_range_query(amdgpu_device_handle dev,
*end = dev->dev_info.virtual_address_max;
return 0;
case amdgpu_gpu_va_range_svm:
- if (dev->vamgr_svm) {
- *start = dev->vamgr_svm->va_min;
- *end = dev->vamgr_svm->va_max;
+ if (vamgr_svm.valid) {
+ *start = vamgr_svm.va_min;
+ *end = vamgr_svm.va_max;
} else {
*start = 0ULL;
*end = 0ULL;
@@ -248,8 +251,8 @@ int amdgpu_va_range_alloc(amdgpu_device_handle dev,
struct amdgpu_bo_va_mgr *vamgr;
if (amdgpu_gpu_va_range_svm == va_range_type) {
- vamgr = dev->vamgr_svm;
- if (!vamgr)
+ vamgr = &vamgr_svm;
+ if (!vamgr->valid)
return -EINVAL;
}
else if (flags & AMDGPU_VA_RANGE_32_BIT)
@@ -329,6 +332,27 @@ int amdgpu_svm_init(amdgpu_device_handle dev)
/* return value of this function. */
int ret;
+ if (atomic_inc_return(&vamgr_svm.refcount) != 1) {
+ /* This is not the first time to initialize SVM in this process. */
+ if (!vamgr_svm.valid) {
+ atomic_dec(&vamgr_svm.refcount, 1);
+ return -ENOSPC;
+ }
+
+ start = amdgpu_vamgr_find_va(&dev->vamgr,
+ vamgr_svm.va_max - vamgr_svm.va_min,
+ dev->dev_info.virtual_address_alignment, vamgr_svm.va_min);
+
+ if (start != vamgr_svm.va_min) {
+ atomic_dec(&vamgr_svm.refcount, 1);
+ vamgr_svm.valid = false;
+ return -ENOSPC;
+ }
+
+ dev->svm_allocated = true;
+ return 0;
+ }
+
ret = amdgpu_va_range_query(dev, amdgpu_gpu_va_range_general, &start, &end);
if (ret)
return ret;
@@ -356,16 +380,9 @@ int amdgpu_svm_init(amdgpu_device_handle dev)
cpu_address = mmap((void *)start, size, PROT_NONE,
MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS, -1, 0);
if (cpu_address == (void *)start) {
- dev->vamgr_svm = calloc(1, sizeof(struct amdgpu_bo_va_mgr));
- if (dev->vamgr_svm == NULL) {
- amdgpu_vamgr_free_va(&dev->vamgr, start, size);
- munmap(cpu_address, size);
- ret = -ENOMEM;
- } else {
- amdgpu_vamgr_init(dev->vamgr_svm, start, start + size,
- dev->dev_info.virtual_address_alignment);
- ret = 0;
- }
+ amdgpu_vamgr_init(&vamgr_svm, start, start + size,
+ dev->dev_info.virtual_address_alignment);
+ ret = 0;
break;
} else if (cpu_address == MAP_FAILED) {
/* Probably there is no space in this process's address space for
@@ -382,17 +399,35 @@ int amdgpu_svm_init(amdgpu_device_handle dev)
}
}
+ if (!ret) {
+ dev->svm_allocated = true;
+ vamgr_svm.valid = true;
+ }
+
return ret;
}
void amdgpu_svm_deinit(amdgpu_device_handle dev)
{
- if (dev->vamgr_svm) {
- amdgpu_vamgr_deinit(dev->vamgr_svm);
- munmap((void *)dev->vamgr_svm->va_min,
- dev->vamgr_svm->va_max - dev->vamgr_svm->va_min);
- free(dev->vamgr_svm);
+ if (dev->svm_allocated) {
+ amdgpu_vamgr_free_va(&dev->vamgr, vamgr_svm.va_min,
+ vamgr_svm.va_max - vamgr_svm.va_min);
+ dev->svm_allocated = false;
+
+ if (atomic_dec_and_test(&vamgr_svm.refcount)) {
+ /* This is the last device referencing SVM. */
+ amdgpu_vamgr_deinit(&vamgr_svm);
+ munmap((void *)vamgr_svm.va_min,
+ vamgr_svm.va_max - vamgr_svm.va_min);
+ vamgr_svm.va_max = 0;
+ }
}
+
+ /* Mark SVM invalid when deinitialize SVM in any GPU device.
+ * To make SVM valid again, application should deinte all devices and
+ * re-initialize all GPU devices again.
+ */
+ vamgr_svm.valid = false;
}
int amdgpu_svm_commit(amdgpu_va_handle va_range_handle,