]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/gpu/drm/nouveau/nouveau_svm.c
drm/nouveau/svm: new ioctl to migrate process memory to GPU memory
[linux.git] / drivers / gpu / drm / nouveau / nouveau_svm.c
index 3ba980d80a1a1231f1e860efb1758cda9f3fe93e..93ed43c413f0bbff28c393675b527376518c4319 100644 (file)
@@ -22,6 +22,7 @@
 #include "nouveau_svm.h"
 #include "nouveau_drv.h"
 #include "nouveau_chan.h"
+#include "nouveau_dmem.h"
 
 #include <nvif/notify.h>
 #include <nvif/object.h>
@@ -104,6 +105,101 @@ struct nouveau_svmm {
 #define SVMM_ERR(s,f,a...)                                                     \
        NV_WARN((s)->vmm->cli->drm, "svm-%p: "f"\n", (s), ##a)
 
+int
+nouveau_svmm_bind(struct drm_device *dev, void *data,
+                 struct drm_file *file_priv)
+{
+       struct nouveau_cli *cli = nouveau_cli(file_priv);
+       struct drm_nouveau_svm_bind *args = data;
+       unsigned target, cmd, priority;
+       unsigned long addr, end, size;
+       struct mm_struct *mm;
+
+       args->va_start &= PAGE_MASK;
+       args->va_end &= PAGE_MASK;
+
+       /* Sanity check arguments */
+       if (args->reserved0 || args->reserved1)
+               return -EINVAL;
+       if (args->header & (~NOUVEAU_SVM_BIND_VALID_MASK))
+               return -EINVAL;
+       if (args->va_start >= args->va_end)
+               return -EINVAL;
+       if (!args->npages)
+               return -EINVAL;
+
+       cmd = args->header >> NOUVEAU_SVM_BIND_COMMAND_SHIFT;
+       cmd &= NOUVEAU_SVM_BIND_COMMAND_MASK;
+       switch (cmd) {
+       case NOUVEAU_SVM_BIND_COMMAND__MIGRATE:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       priority = args->header >> NOUVEAU_SVM_BIND_PRIORITY_SHIFT;
+       priority &= NOUVEAU_SVM_BIND_PRIORITY_MASK;
+
+       /* FIXME support CPU target ie all target value < GPU_VRAM */
+       target = args->header >> NOUVEAU_SVM_BIND_TARGET_SHIFT;
+       target &= NOUVEAU_SVM_BIND_TARGET_MASK;
+       switch (target) {
+       case NOUVEAU_SVM_BIND_TARGET__GPU_VRAM:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * FIXME: For now refuse non 0 stride, we need to change the migrate
+        * kernel function to handle stride to avoid to create a mess within
+        * each device driver.
+        */
+       if (args->stride)
+               return -EINVAL;
+
+       size = ((unsigned long)args->npages) << PAGE_SHIFT;
+       if ((args->va_start + size) <= args->va_start)
+               return -EINVAL;
+       if ((args->va_start + size) > args->va_end)
+               return -EINVAL;
+
+       /*
+        * Ok we are ask to do something sane, for now we only support migrate
+        * commands but we will add things like memory policy (what to do on
+        * page fault) and maybe some other commands.
+        */
+
+       mm = get_task_mm(current);
+       down_read(&mm->mmap_sem);
+
+       for (addr = args->va_start, end = args->va_start + size; addr < end;) {
+               struct vm_area_struct *vma;
+               unsigned long next;
+
+               vma = find_vma_intersection(mm, addr, end);
+               if (!vma)
+                       break;
+
+               next = min(vma->vm_end, end);
+               /* This is a best effort so we ignore errors */
+               nouveau_dmem_migrate_vma(cli->drm, vma, addr, next);
+               addr = next;
+       }
+
+       /*
+        * FIXME Return the number of page we have migrated, again we need to
+        * update the migrate API to return that information so that we can
+        * report it to user space.
+        */
+       args->result = 0;
+
+       up_read(&mm->mmap_sem);
+       mmput(mm);
+
+       return 0;
+}
+
 /* Unlink channel instance from SVMM. */
 void
 nouveau_svmm_part(struct nouveau_svmm *svmm, u64 inst)