summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJérôme Glisse <jglisse@redhat.com>2017-08-10 12:37:42 -0400
committerJérôme Glisse <jglisse@redhat.com>2017-09-05 14:52:36 -0400
commit2d95783f7265e2ffae0aed70d196a495c951e809 (patch)
tree2cc13bc78e890dddd475b573f0d01fcc63949dd5
parent724a59351518914c0b2616a49bf9f4c3a297cf8f (diff)
drm/nouveau/compote: add HMM mirror support
Signed-off-by: Jérôme Glisse <jglisse@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/compote/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/compote/compote-driver.c6
-rw-r--r--drivers/gpu/drm/nouveau/compote/compote-hmm.c113
-rw-r--r--drivers/gpu/drm/nouveau/compote/compote.h6
4 files changed, 126 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/compote/Kbuild b/drivers/gpu/drm/nouveau/compote/Kbuild
index 8aad1e360e23..76de5f87299b 100644
--- a/drivers/gpu/drm/nouveau/compote/Kbuild
+++ b/drivers/gpu/drm/nouveau/compote/Kbuild
@@ -2,4 +2,5 @@ ifdef CONFIG_DRM_COMPOTE
compote-y := compote/compote-driver.o
compote-y += compote/compote-memory.o
compote-y += compote/compote-channel.o
+compote-y += compote/compote-hmm.o
endif
diff --git a/drivers/gpu/drm/nouveau/compote/compote-driver.c b/drivers/gpu/drm/nouveau/compote/compote-driver.c
index 7d58a5de0681..9ffd966546b9 100644
--- a/drivers/gpu/drm/nouveau/compote/compote-driver.c
+++ b/drivers/gpu/drm/nouveau/compote/compote-driver.c
@@ -128,6 +128,10 @@ static int compote_open(struct inode *inode, struct file *file)
goto error_vm;
nvxx_client(&cfile->nvclient.base)->vm = cfile->nvclient.vm;
+ ret = compote_file_hmm_init(cfile);
+ if (ret)
+ goto error_vm;
+
/* share address_space across all char-devs of a single device */
file->f_mapping = cdevice->nvdrm->dev->anon_inode->i_mapping;
@@ -163,6 +167,8 @@ static int compote_close(struct inode *inode, struct file *file)
compote_channel_unref(channel);
}
+ compote_file_hmm_fini(cfile);
+
compote_client_fini(&cfile->nvclient);
cdevice = cfile->cdevice;
kfree(cfile);
diff --git a/drivers/gpu/drm/nouveau/compote/compote-hmm.c b/drivers/gpu/drm/nouveau/compote/compote-hmm.c
new file mode 100644
index 000000000000..0879fead00e1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/compote/compote-hmm.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2017 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Authors: Jérôme Glisse <jglisse@redhat.com>
+ */
+#include <linux/sched/mm.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/hmm.h>
+#include "compote.h"
+
+static void compote_nvkm_vma_unmap(struct compote_file *cfile,
+ struct nvkm_vma *nvvma,
+ unsigned long addr,
+ unsigned long nbytes)
+{
+ unsigned long skip, i;
+ struct device *pdev;
+
+ pdev = nvxx_device(&cfile->cdevice->nvdrm->client.device)->dev;
+
+ skip = addr - nvvma->offset;
+ mutex_lock(&nvvma->mutex);
+ nvkm_vm_unmap_at(nvvma, skip, nbytes);
+ for (i = skip >> 12; i < ((skip + nbytes) >> 12); ++i) {
+ if (!(nvvma->pfns[i] & HMM_PFN_VALID))
+ continue;
+ dma_unmap_page(pdev, nvvma->dmas[i], PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+ nvvma->pfns[i] = 0;
+ nvvma->dmas[i] = 0;
+ if ((--nvvma->refcount) <= 0) {
+ /* This should not happen here ! */
+ BUG();
+ nvkm_vm_put(nvvma);
+ break;
+ }
+ }
+ mutex_unlock(&nvvma->mutex);
+
+ if ((--nvvma->refcount) <= 0) {
+ nvkm_vm_put(nvvma);
+ kfree(nvvma->pfns);
+ kfree(nvvma->dmas);
+ kfree(nvvma);
+ }
+}
+
+static void compote_file_vm_sync_pagetables(struct hmm_mirror *mirror,
+ enum hmm_update_type update,
+ unsigned long start,
+ unsigned long end)
+{
+ struct compote_file *cfile;
+ unsigned long addr;
+
+ cfile = container_of(mirror, struct compote_file, mirror);
+ for (addr = start; addr < end;) {
+ struct nvkm_vma *nvvma;
+ unsigned long length;
+
+ nvvma = nvkm_vm_find(cfile->nvclient.vm, addr, end);
+ if (nvvma == NULL) {
+ break;
+ }
+
+ addr = max(addr, (unsigned long)nvvma->offset);
+ length = nvvma->node->length << 12;
+ length = min(end - addr, length);
+ if (nvvma->pfns == NULL) {
+ addr += length;
+ continue;
+ }
+
+ compote_nvkm_vma_unmap(cfile, nvvma, addr, length);
+ addr += length;
+ }
+}
+
+static const struct hmm_mirror_ops compote_hmm_mirror_ops = {
+ .sync_cpu_device_pagetables = &compote_file_vm_sync_pagetables,
+};
+
+int compote_file_hmm_init(struct compote_file *cfile)
+{
+ struct mm_struct *mm = get_task_mm(current);
+ int ret;
+
+ down_write(&mm->mmap_sem);
+ cfile->mirror.ops = &compote_hmm_mirror_ops;
+ ret = hmm_mirror_register(&cfile->mirror, mm);
+ if (!ret)
+ cfile->mm = mm;
+ up_write(&mm->mmap_sem);
+ mmput(mm);
+
+ return ret;
+}
+
+void compote_file_hmm_fini(struct compote_file *cfile)
+{
+ hmm_mirror_unregister(&cfile->mirror);
+}
diff --git a/drivers/gpu/drm/nouveau/compote/compote.h b/drivers/gpu/drm/nouveau/compote/compote.h
index b76d013c4ba7..23900689409a 100644
--- a/drivers/gpu/drm/nouveau/compote/compote.h
+++ b/drivers/gpu/drm/nouveau/compote/compote.h
@@ -17,6 +17,7 @@
#define COMPOTE_H
#include <linux/list.h>
+#include <linux/hmm.h>
#include "nouveau_drv.h"
#define COMPOTE_DEVICE_NAME "compote"
@@ -35,6 +36,8 @@ struct compote_file {
struct nouveau_cli nvclient;
struct list_head channels;
struct rw_semaphore rwsem;
+ struct mm_struct *mm;
+ struct hmm_mirror mirror;
};
struct compote_mo {
@@ -78,4 +81,7 @@ int compote_mo_mmap(struct compote_file *cfile,
struct vm_area_struct *vma,
struct file *file);
+int compote_file_hmm_init(struct compote_file *cfile);
+void compote_file_hmm_fini(struct compote_file *cfile);
+
#endif /* COMPOTE_H */