drm/amdgpu: add a VM mapping replace operation v2
authorChristian König <christian.koenig@amd.com>
Mon, 13 Mar 2017 09:13:39 +0000 (10:13 +0100)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 30 Mar 2017 03:54:01 +0000 (23:54 -0400)
Add a new operation to replace mappings in a VM with a new one.

v2: Fix Jerry's comment, separate out clear operation.

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
include/uapi/drm/amdgpu_drm.h

index b311b389bd5a45114ab5637e0d70dbef6489fef5..c71c087727b89b99023b35ffebadda3d75044ced 100644 (file)
@@ -544,7 +544,8 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
        if (r)
                goto error;
 
-       if (operation == AMDGPU_VA_OP_MAP)
+       if (operation == AMDGPU_VA_OP_MAP ||
+           operation == AMDGPU_VA_OP_REPLACE)
                r = amdgpu_vm_bo_update(adev, bo_va, false);
 
 error:
@@ -595,6 +596,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
        case AMDGPU_VA_OP_MAP:
        case AMDGPU_VA_OP_UNMAP:
        case AMDGPU_VA_OP_CLEAR:
+       case AMDGPU_VA_OP_REPLACE:
                break;
        default:
                dev_err(&dev->pdev->dev, "unsupported operation %d\n",
@@ -656,6 +658,17 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
                                                args->va_address,
                                                args->map_size);
                break;
+       case AMDGPU_VA_OP_REPLACE:
+               r = amdgpu_vm_alloc_pts(adev, bo_va->vm, args->va_address,
+                                       args->map_size);
+               if (r)
+                       goto error_backoff;
+
+               va_flags = amdgpu_vm_get_pte_flags(adev, args->flags);
+               r = amdgpu_vm_bo_replace_map(adev, bo_va, args->va_address,
+                                            args->offset_in_bo, args->map_size,
+                                            va_flags);
+               break;
        default:
                break;
        }
index b67e94e25cfcbf2e10a83b0e9d84a2a77b161b1d..2da08027ff29b68ec84c7c5e394f18bb638e2dbc 100644 (file)
@@ -1560,6 +1560,70 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
        return 0;
 }
 
+/**
+ * amdgpu_vm_bo_replace_map - map bo inside a vm, replacing existing mappings
+ *
+ * @adev: amdgpu_device pointer
+ * @bo_va: bo_va to store the address
+ * @saddr: where to map the BO
+ * @offset: requested offset in the BO
+ * @flags: attributes of pages (read/write/valid/etc.)
+ *
+ * Add a mapping of the BO at the specefied addr into the VM. Replace existing
+ * mappings as we do so.
+ * Returns 0 for success, error for failure.
+ *
+ * Object has to be reserved and unreserved outside!
+ */
+int amdgpu_vm_bo_replace_map(struct amdgpu_device *adev,
+                            struct amdgpu_bo_va *bo_va,
+                            uint64_t saddr, uint64_t offset,
+                            uint64_t size, uint64_t flags)
+{
+       struct amdgpu_bo_va_mapping *mapping;
+       struct amdgpu_vm *vm = bo_va->vm;
+       uint64_t eaddr;
+       int r;
+
+       /* validate the parameters */
+       if (saddr & AMDGPU_GPU_PAGE_MASK || offset & AMDGPU_GPU_PAGE_MASK ||
+           size == 0 || size & AMDGPU_GPU_PAGE_MASK)
+               return -EINVAL;
+
+       /* make sure object fit at this offset */
+       eaddr = saddr + size - 1;
+       if (saddr >= eaddr ||
+           (bo_va->bo && offset + size > amdgpu_bo_size(bo_va->bo)))
+               return -EINVAL;
+
+       /* Allocate all the needed memory */
+       mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
+       if (!mapping)
+               return -ENOMEM;
+
+       r = amdgpu_vm_bo_clear_mappings(adev, bo_va->vm, saddr, size);
+       if (r) {
+               kfree(mapping);
+               return r;
+       }
+
+       saddr /= AMDGPU_GPU_PAGE_SIZE;
+       eaddr /= AMDGPU_GPU_PAGE_SIZE;
+
+       mapping->it.start = saddr;
+       mapping->it.last = eaddr;
+       mapping->offset = offset;
+       mapping->flags = flags;
+
+       list_add(&mapping->list, &bo_va->invalids);
+       interval_tree_insert(&mapping->it, &vm->va);
+
+       if (flags & AMDGPU_PTE_PRT)
+               amdgpu_vm_prt_get(adev);
+
+       return 0;
+}
+
 /**
  * amdgpu_vm_bo_unmap - remove bo mapping from vm
  *
index 95fe47733b7fb02285a98a823c9d0ef8b13068a2..ab0429d12992fc3d549502d3471f958b5bad17ff 100644 (file)
@@ -207,6 +207,10 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
                     struct amdgpu_bo_va *bo_va,
                     uint64_t addr, uint64_t offset,
                     uint64_t size, uint64_t flags);
+int amdgpu_vm_bo_replace_map(struct amdgpu_device *adev,
+                            struct amdgpu_bo_va *bo_va,
+                            uint64_t addr, uint64_t offset,
+                            uint64_t size, uint64_t flags);
 int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
                       struct amdgpu_bo_va *bo_va,
                       uint64_t addr);
index 199f1b46fd2c11405ee1250f94b825ae310da136..37e2c0da01fb7c91d573b994e3acb8e945fd4168 100644 (file)
@@ -351,6 +351,7 @@ struct drm_amdgpu_gem_op {
 #define AMDGPU_VA_OP_MAP                       1
 #define AMDGPU_VA_OP_UNMAP                     2
 #define AMDGPU_VA_OP_CLEAR                     3
+#define AMDGPU_VA_OP_REPLACE                   4
 
 /* Delay the page table update till the next CS */
 #define AMDGPU_VM_DELAY_UPDATE         (1 << 0)