diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/compote/compote-channel.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/compote/compote-channel.c | 151 |
1 files changed, 151 insertions, 0 deletions
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; +} |