summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Xie <AlexBin.Xie@amd.com>2015-10-20 11:47:14 -0400
committerQiang Yu <Qiang.Yu@amd.com>2017-05-17 10:24:19 +0800
commitfd4ae170ff97e62f2685563bd07ec15b5567380c (patch)
tree3ef77f067cfaf148d2b159df4c68f5a8ba635ca0
parent41be41f99eb53bd4998b1cd930fa63f0e552d971 (diff)
amdgpu: Implement SVM v3
SWDEV-75927: Coarse Grain SVM support for OpenCL 2.0 Add SVM API. Implement SVM to reserve CPU and GPU VM address space for SVM. Implement commit/uncommit function for SVM. v3: 2f8e2d2e4a406bc290986eac600f4263259b5ac5 [Jammy Zhou] reserve SVM range explicitly by clients The SVM range is only used by OCL 2.0 now, and it shouldn't be reserved when only other clients are used. With this change: amdgpu_svm_init() should be called to reserve the SVM range amdgpu_svm_deinit() should be called to unreserve this range v2: 1. Merge patch1 and patch2. 2. Update description of the commit. 3. Address review comments on coding style. 4. Update comments in source code. 5. Fix one issue in function amdgpu_va_range_query. The start of the range should be dev->vamgr_svm->va_min. 6. Fix an error code. Signed-off-by: Alex Xie <AlexBin.Xie@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Jammy Zhou <Jammy.Zhou@amd.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com>
-rw-r--r--amdgpu/amdgpu.h50
-rw-r--r--amdgpu/amdgpu_internal.h3
-rw-r--r--amdgpu/amdgpu_vamgr.c145
3 files changed, 193 insertions, 5 deletions
diff --git a/amdgpu/amdgpu.h b/amdgpu/amdgpu.h
index 1901fa8c..1cec608f 100644
--- a/amdgpu/amdgpu.h
+++ b/amdgpu/amdgpu.h
@@ -91,7 +91,9 @@ enum amdgpu_bo_handle_type {
enum amdgpu_gpu_va_range
{
/** Allocate from "normal"/general range */
- amdgpu_gpu_va_range_general = 0
+ amdgpu_gpu_va_range_general = 0,
+ /** Allocate from svm range */
+ amdgpu_gpu_va_range_svm = 1
};
/*--------------------------------------------------------------------------*/
@@ -1249,7 +1251,6 @@ int amdgpu_bo_va_op(amdgpu_bo_handle bo,
* <0 - Negative POSIX Error code
*
*/
-
int amdgpu_bo_va_op_raw(amdgpu_device_handle dev,
amdgpu_bo_handle bo,
uint64_t offset,
@@ -1259,6 +1260,51 @@ int amdgpu_bo_va_op_raw(amdgpu_device_handle dev,
uint32_t ops);
/**
+ * Reserve the virtual address range for SVM support
+ *
+ * \param amdgpu_device_handle
+ *
+ * \return 0 on success\n
+ * <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_svm_init(amdgpu_device_handle dev);
+
+/**
+ * Free the virtual address range for SVM support
+ *
+ * \param amdgpu_device_handle
+ *
+ * \return
+ *
+*/
+void amdgpu_svm_deinit(amdgpu_device_handle dev);
+
+/**
+ * Commit SVM allocation in a process
+ *
+ * \param va_range_handle - \c [in] Handle of SVM allocation
+ * \param cpu - \c [out] CPU pointer. The value is equal to GPU VM address.
+ *
+ * \return 0 on success\n
+ * <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_svm_commit(amdgpu_va_handle va_range_handle,
+ void **cpu);
+
+/**
+ * Uncommit SVM alloation in process's CPU_VM
+ *
+ * \param va_range_handle - \c [in] Handle of SVM allocation
+ *
+ * \return 0 on success\n
+ * <0 - Negative POSIX Error code
+ *
+*/
+int amdgpu_svm_uncommit(amdgpu_va_handle va_range_handle);
+
+/**
* create semaphore
*
* \param sem - \c [out] semaphore handle
diff --git a/amdgpu/amdgpu_internal.h b/amdgpu/amdgpu_internal.h
index cf119a53..0cad6b61 100644
--- a/amdgpu/amdgpu_internal.h
+++ b/amdgpu/amdgpu_internal.h
@@ -55,6 +55,7 @@ struct amdgpu_bo_va_hole {
struct amdgpu_bo_va_mgr {
/* the start virtual address */
uint64_t va_offset;
+ uint64_t va_min;
uint64_t va_max;
struct list_head va_holes;
pthread_mutex_t bo_va_mutex;
@@ -88,6 +89,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;
};
struct amdgpu_bo {
diff --git a/amdgpu/amdgpu_vamgr.c b/amdgpu/amdgpu_vamgr.c
index 2b1388ed..2a9f28a1 100644
--- a/amdgpu/amdgpu_vamgr.c
+++ b/amdgpu/amdgpu_vamgr.c
@@ -36,18 +36,30 @@
int amdgpu_va_range_query(amdgpu_device_handle dev,
enum amdgpu_gpu_va_range type, uint64_t *start, uint64_t *end)
{
- if (type == amdgpu_gpu_va_range_general) {
+ switch (type) {
+ case amdgpu_gpu_va_range_general:
*start = dev->dev_info.virtual_address_offset;
*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;
+ } else {
+ *start = 0ULL;
+ *end = 0ULL;
+ }
+ return 0;
+ default:
+ return -EINVAL;
}
- return -EINVAL;
}
drm_private void amdgpu_vamgr_init(struct amdgpu_bo_va_mgr *mgr, uint64_t start,
uint64_t max, uint64_t alignment)
{
mgr->va_offset = start;
+ mgr->va_min = start;
mgr->va_max = max;
mgr->va_alignment = alignment;
@@ -235,7 +247,12 @@ int amdgpu_va_range_alloc(amdgpu_device_handle dev,
{
struct amdgpu_bo_va_mgr *vamgr;
- if (flags & AMDGPU_VA_RANGE_32_BIT)
+ if (amdgpu_gpu_va_range_svm == va_range_type) {
+ vamgr = dev->vamgr_svm;
+ if (!vamgr)
+ return -EINVAL;
+ }
+ else if (flags & AMDGPU_VA_RANGE_32_BIT)
vamgr = &dev->vamgr_32;
else
vamgr = &dev->vamgr;
@@ -285,3 +302,125 @@ int amdgpu_va_range_free(amdgpu_va_handle va_range_handle)
free(va_range_handle);
return 0;
}
+
+/**
+ * Initialize SVM VAM manager.
+ * When this function return error, future SVM allocation will fail.
+ * Caller may ignore the error code returned by this function.
+ *
+ * \param dev - \c [in] amdgpu_device pointer
+ *
+ * \return 0 on success\n
+ * <0 - Negative POSIX Error code
+ *
+ */
+int amdgpu_svm_init(amdgpu_device_handle dev)
+{
+ uint64_t start;
+ uint64_t end;
+ /* size of SVM range */
+ uint64_t size;
+ uint64_t base_required;
+ /* Size of step when looking for SVM range. */
+ uint64_t step;
+ /*Will not search less than this address. */
+ uint64_t min_base_required;
+ void * cpu_address;
+ /* return value of this function. */
+ int ret;
+
+ ret = amdgpu_va_range_query(dev, amdgpu_gpu_va_range_general, &start, &end);
+ if (ret)
+ return ret;
+
+ /* size of the general VM */
+ size = end - start;
+ /* size of SVM range */
+ size = size / 4;
+ /* at least keep lower 4G for process usage in CPU address space*/
+ min_base_required = 4ULL * 1024ULL * 1024ULL * 1024ULL;
+ step = size / 8;
+
+ ret = -ENOSPC;
+ /* We try to find a hole both in CPU/GPU VM address space for SVM from top
+ * to bottom.
+ */
+ for (base_required = end - size; base_required >= min_base_required;
+ base_required -= step) {
+ start = amdgpu_vamgr_find_va(&dev->vamgr, size,
+ dev->dev_info.virtual_address_alignment, base_required);
+ if (start != base_required)
+ continue;
+
+ /* Try to map the SVM range in CPU VM */
+ 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;
+ }
+ break;
+ } else if (cpu_address == MAP_FAILED) {
+ /* Probably there is no space in this process's address space for
+ such size of SVM range. This is very rare for 64 bit CPU.
+ */
+ amdgpu_vamgr_free_va(&dev->vamgr, start, size);
+ ret = -ENOMEM;
+ break;
+ } else { /* cpu_address != (void *)start */
+ /* This CPU VM address (start) is not available*/
+ amdgpu_vamgr_free_va(&dev->vamgr, start, size);
+ munmap(cpu_address, size);
+ base_required -= step;
+ }
+ }
+
+ 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);
+ }
+}
+
+int amdgpu_svm_commit(amdgpu_va_handle va_range_handle,
+ void **cpu)
+{
+ if (!va_range_handle || !va_range_handle->address)
+ return -EINVAL;
+ if (va_range_handle->range != amdgpu_gpu_va_range_svm)
+ return -EINVAL;
+
+ if (mprotect((void *)va_range_handle->address,
+ va_range_handle->size, PROT_READ | PROT_WRITE) == 0) {
+ *cpu = (void *)va_range_handle->address;
+ return 0;
+ } else
+ return errno;
+}
+
+int amdgpu_svm_uncommit(amdgpu_va_handle va_range_handle)
+{
+ if (!va_range_handle || !va_range_handle->address)
+ return -EINVAL;
+ if (va_range_handle->range != amdgpu_gpu_va_range_svm)
+ return -EINVAL;
+
+ if (mprotect((void *)va_range_handle->address,
+ va_range_handle->size, PROT_NONE) == 0) {
+ return 0;
+ } else
+ return errno;
+}