summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/nouveau/compote/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/compote/compote-channel.c151
-rw-r--r--drivers/gpu/drm/nouveau/compote/compote-driver.c13
-rw-r--r--drivers/gpu/drm/nouveau/compote/compote.h14
4 files changed, 179 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/compote/Kbuild b/drivers/gpu/drm/nouveau/compote/Kbuild
index 9c6f3a2ae9de..8aad1e360e23 100644
--- a/drivers/gpu/drm/nouveau/compote/Kbuild
+++ b/drivers/gpu/drm/nouveau/compote/Kbuild
@@ -1,4 +1,5 @@
ifdef CONFIG_DRM_COMPOTE
compote-y := compote/compote-driver.o
compote-y += compote/compote-memory.o
+compote-y += compote/compote-channel.o
endif
diff --git a/drivers/gpu/drm/nouveau/compote/compote-channel.c b/drivers/gpu/drm/nouveau/compote/compote-channel.c
new file mode 100644
index 000000000000..9b9b30e999cb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/compote/compote-channel.c
@@ -0,0 +1,151 @@
+/*
+ * 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 <nvif/cla06f.h>
+
+#include "nouveau_ttm.h"
+#include "nouveau_chan.h"
+#include "nouveau_usif.h"
+#include "nouveau_abi16.h"
+#include "nouveau_bo.h"
+
+int compote_channel_new(struct compote_channel **channelp,
+ struct compote_file *cfile)
+{
+ uint32_t fb_ctxdma_handle, tt_ctxdma_handle;
+ struct compote_channel *channel;
+ struct nvif_device *nvifdevice;
+ struct nouveau_drm *nvdrm;
+ int ret;
+
+ *channelp = NULL;
+ channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+ if (channel == NULL)
+ return -ENOMEM;
+
+ channel->cfile = cfile;
+ kref_init(&channel->kref);
+
+ /* create channel object and initialise dma and fence management */
+ tt_ctxdma_handle = 0;
+ nvdrm = cfile->cdevice->nvdrm;
+ nvifdevice = &cfile->nvclient.device;
+ fb_ctxdma_handle = NVA06F_V0_ENGINE_GR;
+ ret = nouveau_channel_new(nvdrm, nvifdevice,
+ fb_ctxdma_handle,
+ tt_ctxdma_handle,
+ &channel->nvchan);
+ if (ret)
+ goto error;
+
+ *channelp = channel;
+ return 0;
+
+error:
+ kfree(channel);
+ return ret;
+}
+
+static void compote_channel_kref_put(struct kref *kref)
+{
+ struct compote_channel *channel;
+ struct compote_file *cfile;
+
+ channel = container_of(kref, struct compote_channel, kref);
+ cfile = channel->cfile;
+
+ /*
+ * Wait for all activity to stop before releasing notify object, which
+ * may be still in use.
+ */
+ nouveau_channel_idle(channel->nvchan);
+ nouveau_channel_del(&channel->nvchan);
+
+ down_write(&cfile->rwsem);
+ list_del_init(&channel->list);
+ up_write(&cfile->rwsem);
+
+ kfree(channel);
+}
+
+void compote_channel_ref(struct compote_channel *channel)
+{
+ kref_get(&channel->kref);
+}
+
+void compote_channel_unref(struct compote_channel *channel)
+{
+ kref_put(&channel->kref, compote_channel_kref_put);
+}
+
+int compote_ioctl_channel_alloc(struct compote_file *cfile, void __user *uarg)
+{
+ struct compote_ioctl_channel_alloc arg;
+ struct compote_channel *channel;
+ int ret;
+
+ ret = compote_channel_new(&channel, cfile);
+ if (ret)
+ return ret;
+
+ arg.channel = channel->nvchan->chid;
+ ret = copy_to_user(uarg, &arg, sizeof(arg));
+ if (ret) {
+ compote_channel_unref(channel);
+ return ret;
+ }
+
+ down_write(&cfile->rwsem);
+ list_add_tail(&channel->list, &cfile->channels);
+ up_write(&cfile->rwsem);
+
+ return 0;
+}
+
+int compote_ioctl_channel_free(struct compote_file *cfile,
+ void __user *uarg)
+{
+ struct compote_ioctl_channel_free arg;
+ struct compote_channel *channel;
+ int ret;
+
+ ret = copy_from_user(&arg, uarg, sizeof(arg));
+ if (ret)
+ return ret;
+
+ down_write(&cfile->rwsem);
+ list_for_each_entry (channel, &cfile->channels, list) {
+ if (channel->nvchan->chid == arg.channel) {
+ compote_channel_ref(channel);
+ up_write(&cfile->rwsem);
+ compote_channel_unref(channel);
+ compote_channel_unref(channel);
+ return 0;
+ }
+ }
+ up_write(&cfile->rwsem);
+
+ return -EINVAL;
+}
diff --git a/drivers/gpu/drm/nouveau/compote/compote-driver.c b/drivers/gpu/drm/nouveau/compote/compote-driver.c
index 62b4edd1ca7e..002290d5c9f6 100644
--- a/drivers/gpu/drm/nouveau/compote/compote-driver.c
+++ b/drivers/gpu/drm/nouveau/compote/compote-driver.c
@@ -109,6 +109,8 @@ static int compote_open(struct inode *inode, struct file *file)
snprintf(name, sizeof(name), "%s[%d]", tmpname,
pid_nr(get_pid(task_pid(current))));
+ INIT_LIST_HEAD(&cfile->channels);
+ init_rwsem(&cfile->rwsem);
cfile->cdevice = cdevice;
cfile->file = file;
@@ -149,6 +151,7 @@ error:
static int compote_close(struct inode *inode, struct file *file)
{
struct compote_file *cfile = file->private_data;
+ struct compote_channel *channel, *tmp;
struct compote_device *cdevice;
if(cfile == NULL)
@@ -156,6 +159,10 @@ static int compote_close(struct inode *inode, struct file *file)
pm_runtime_get_sync(cfile->cdevice->nvdrm->dev->dev);
+ list_for_each_entry_safe (channel, tmp, &cfile->channels, list) {
+ compote_channel_unref(channel);
+ }
+
compote_client_fini(&cfile->nvclient);
cdevice = cfile->cdevice;
kfree(cfile);
@@ -213,6 +220,12 @@ static long compote_ioctl(struct file *file,
case COMPOTE_IOCTL_MEM_FREE:
ret = compote_ioctl_mem_free(cfile, uarg);
break;
+ case COMPOTE_IOCTL_CHAN_ALLOC:
+ ret = compote_ioctl_channel_alloc(cfile, uarg);
+ break;
+ case COMPOTE_IOCTL_CHAN_FREE:
+ ret = compote_ioctl_channel_free(cfile, uarg);
+ break;
default:
ret = -EINVAL;
break;
diff --git a/drivers/gpu/drm/nouveau/compote/compote.h b/drivers/gpu/drm/nouveau/compote/compote.h
index 4d9d2166faf4..0a37d0a1922d 100644
--- a/drivers/gpu/drm/nouveau/compote/compote.h
+++ b/drivers/gpu/drm/nouveau/compote/compote.h
@@ -33,6 +33,8 @@ struct compote_file {
struct compote_device *cdevice;
struct file *file;
struct nouveau_cli nvclient;
+ struct list_head channels;
+ struct rw_semaphore rwsem;
};
struct compote_mo {
@@ -53,9 +55,21 @@ struct compote_mo_va {
const struct vm_operations_struct *ttm_vm_ops;
};
+struct compote_channel {
+ struct list_head list;
+ struct compote_file *cfile;
+ struct nouveau_channel *nvchan;
+ struct kref kref;
+};
+
long compote_ioctl_mem_alloc(struct compote_file *cfile, void __user *uarg);
long compote_ioctl_mem_free(struct compote_file *cfile, void __user *uarg);
+int compote_ioctl_channel_alloc(struct compote_file *cfile, void __user *uarg);
+int compote_ioctl_channel_free(struct compote_file *cfile, void __user *uarg);
+void compote_channel_ref(struct compote_channel *channel);
+void compote_channel_unref(struct compote_channel *channel);
+
void compote_mo_ref(struct compote_mo *mo);
void compote_mo_unref(struct compote_mo *mo);
int compote_mo_mmap(struct compote_file *cfile,