summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau
diff options
context:
space:
mode:
authorJérôme Glisse <jglisse@redhat.com>2017-08-03 18:20:55 -0400
committerJérôme Glisse <jglisse@redhat.com>2017-08-29 10:35:00 -0400
commit22ec8ae4d72daabc574b0400848dbff1a9abe698 (patch)
tree5a9913a9fa017d0503c831b918aab3f06f8df9ef /drivers/gpu/drm/nouveau
parent5e6a91b62e3926d3ed26949ddd48597cd9e47f7d (diff)
drm/nouveau/compote: memory allocation ioctl
Add memory allocation ioctl. Very basic and simple linear allocation inside GART. Signed-off-by: Jérôme Glisse <jglisse@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r--drivers/gpu/drm/nouveau/compote/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/compote/compote-driver.c28
-rw-r--r--drivers/gpu/drm/nouveau/compote/compote-memory.c152
-rw-r--r--drivers/gpu/drm/nouveau/compote/compote.h15
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.h3
5 files changed, 198 insertions, 1 deletions
diff --git a/drivers/gpu/drm/nouveau/compote/Kbuild b/drivers/gpu/drm/nouveau/compote/Kbuild
index 89af6841ab15..9c6f3a2ae9de 100644
--- a/drivers/gpu/drm/nouveau/compote/Kbuild
+++ b/drivers/gpu/drm/nouveau/compote/Kbuild
@@ -1,3 +1,4 @@
ifdef CONFIG_DRM_COMPOTE
compote-y := compote/compote-driver.o
+compote-y += compote/compote-memory.o
endif
diff --git a/drivers/gpu/drm/nouveau/compote/compote-driver.c b/drivers/gpu/drm/nouveau/compote/compote-driver.c
index 409e4c803c26..6e05ffc351b3 100644
--- a/drivers/gpu/drm/nouveau/compote/compote-driver.c
+++ b/drivers/gpu/drm/nouveau/compote/compote-driver.c
@@ -18,6 +18,7 @@
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/fs.h>
+#include <uapi/drm/compote-uapi.h>
#include "compote.h"
#include <nvif/driver.h>
@@ -169,7 +170,32 @@ static long compote_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg)
{
- return -EINVAL;
+ struct compote_file *cfile = file->private_data;
+ void __user *uarg = (void __user *)arg;
+ long ret;
+
+ if (!cfile)
+ return -EINVAL;
+
+ ret = pm_runtime_get_sync(cfile->cdevice->nvdrm->dev->dev);
+ if (WARN_ON(ret < 0 && ret != -EACCES))
+ return ret;
+
+ switch (cmd) {
+ case COMPOTE_IOCTL_MEM_ALLOC:
+ ret = compote_ioctl_mem_alloc(cfile, uarg);
+ break;
+ case COMPOTE_IOCTL_MEM_FREE:
+ ret = compote_ioctl_mem_free(cfile, uarg);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ pm_runtime_mark_last_busy(cfile->cdevice->nvdrm->dev->dev);
+ pm_runtime_put_autosuspend(cfile->cdevice->nvdrm->dev->dev);
+ return ret;
}
static const struct file_operations compote_fops = {
diff --git a/drivers/gpu/drm/nouveau/compote/compote-memory.c b/drivers/gpu/drm/nouveau/compote/compote-memory.c
new file mode 100644
index 000000000000..55fca9092846
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/compote/compote-memory.c
@@ -0,0 +1,152 @@
+/*
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <uapi/drm/compote-uapi.h>
+#include "compote.h"
+
+#include <nvif/driver.h>
+#include <nvif/class.h>
+
+#include "nouveau_ttm.h"
+#include "nouveau_usif.h"
+#include "nouveau_abi16.h"
+#include "nouveau_bo.h"
+
+static struct compote_mo *compote_file_mo_find(struct compote_file *cfile,
+ uint64_t foffset)
+{
+ struct ttm_bo_device *bdev = &cfile->cdevice->nvdrm->ttm.bdev;
+ struct drm_vma_offset_node *node;
+ struct compote_mo *mo = NULL;
+
+ drm_vma_offset_lock_lookup(&bdev->vma_manager);
+ node = drm_vma_offset_lookup_locked(&bdev->vma_manager, foffset, 1);
+ if (likely(node)) {
+ struct ttm_buffer_object *bo;
+ struct nouveau_bo *nvbo;
+
+ bo = container_of(node, struct ttm_buffer_object, vma_node);
+ nvbo = nouveau_bo(bo);
+ mo = nvbo->mo;
+ if (!mo || mo->cfile != cfile || !kref_get_unless_zero(&mo->kref))
+ mo = NULL;
+ }
+ drm_vma_offset_unlock_lookup(&bdev->vma_manager);
+
+ return mo;
+}
+
+static int compote_mo_new(struct compote_mo **mop,
+ struct compote_file *cfile,
+ uint64_t nbytes)
+{
+ uint32_t flags, tile_mode, tile_flags;
+ struct compote_mo *mo;
+ int align;
+ int ret;
+
+ mo = kzalloc(sizeof(*mo), GFP_KERNEL);
+ if (mo == NULL)
+ return -ENOMEM;
+
+
+ align = 0;
+ tile_mode = 0;
+ tile_flags = 0;
+ flags = TTM_PL_FLAG_TT;
+ ret = nouveau_bo_new(&cfile->nvclient, nbytes, align, flags, tile_mode,
+ tile_flags, NULL, NULL, &mo->nvbo);
+ if (ret)
+ goto error_bo;
+
+ mo->cfile = cfile;
+ mo->nvbo->mo = mo;
+ kref_init(&mo->kref);
+ mo->npages = PAGE_ALIGN(nbytes);
+ mo->foffset = drm_vma_node_offset_addr(&mo->nvbo->bo.vma_node);
+
+ *mop = mo;
+ return 0;
+
+error_bo:
+ kfree(mo);
+ *mop = NULL;
+ return ret;
+}
+
+static void compote_mo_kref_put(struct kref *kref)
+{
+ struct compote_mo *mo = container_of(kref, struct compote_mo, kref);
+ struct ttm_buffer_object *bo = &mo->nvbo->bo;
+
+ ttm_bo_unref(&bo);
+ kfree(mo);
+}
+
+void compote_mo_ref(struct compote_mo *mo)
+{
+ kref_get(&mo->kref);
+}
+
+void compote_mo_unref(struct compote_mo *mo)
+{
+ kref_put(&mo->kref, compote_mo_kref_put);
+}
+
+long compote_ioctl_mem_alloc(struct compote_file *cfile, void __user *uarg)
+{
+ struct compote_ioctl_mem_alloc arg;
+ struct compote_mo *mo = NULL;
+ int ret;
+
+ ret = copy_from_user(&arg, uarg, sizeof(arg));
+ if (ret)
+ return ret;
+
+ ret = compote_mo_new(&mo, cfile, arg.nbytes);
+
+ arg.foffset = ret ? -1UL : mo->foffset;
+ ret = copy_to_user(uarg, &arg, sizeof(arg));
+ if (ret) {
+ compote_mo_unref(mo);
+ return ret;
+ }
+
+ return 0;
+}
+
+long compote_ioctl_mem_free(struct compote_file *cfile, void __user *uarg)
+{
+ struct compote_ioctl_mem_free arg;
+ struct compote_mo *mo = NULL;
+ int ret;
+
+ ret = copy_from_user(&arg, uarg, sizeof(arg));
+ if (ret)
+ return ret;
+
+ mo = compote_file_mo_find(cfile, arg.foffset);
+ if (mo == NULL)
+ return -EINVAL;
+
+ compote_mo_unref(mo);
+ compote_mo_unref(mo);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/compote/compote.h b/drivers/gpu/drm/nouveau/compote/compote.h
index 40f437703259..c0d59960ceef 100644
--- a/drivers/gpu/drm/nouveau/compote/compote.h
+++ b/drivers/gpu/drm/nouveau/compote/compote.h
@@ -16,6 +16,7 @@
#ifndef COMPOTE_H
#define COMPOTE_H
+#include <linux/list.h>
#include "nouveau_drv.h"
#define COMPOTE_DEVICE_NAME "compote"
@@ -34,4 +35,18 @@ struct compote_file {
struct nouveau_cli nvclient;
};
+struct compote_mo {
+ struct kref kref;
+ struct compote_file *cfile;
+ struct nouveau_bo *nvbo;
+ uint64_t npages;
+ uint64_t foffset;
+};
+
+long compote_ioctl_mem_alloc(struct compote_file *cfile, void __user *uarg);
+long compote_ioctl_mem_free(struct compote_file *cfile, void __user *uarg);
+
+void compote_mo_ref(struct compote_mo *mo);
+void compote_mo_unref(struct compote_mo *mo);
+
#endif /* COMPOTE_H */
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h
index b46f3060b823..1031db2958e7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.h
@@ -41,6 +41,9 @@ struct nouveau_bo {
int pin_refcnt;
struct ttm_bo_kmap_obj dma_buf_vmap;
+
+ /* for compote */
+ void *mo;
};
static inline struct nouveau_bo *