diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/nouveau/compote/Kbuild | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/compote/compote-channel.c | 151 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/compote/compote-driver.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/compote/compote.h | 14 |
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, |