summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/nouveau/compote/compote-channel.c79
-rw-r--r--drivers/gpu/drm/nouveau/compote/compote-driver.c3
-rw-r--r--drivers/gpu/drm/nouveau/compote/compote.h2
-rw-r--r--include/uapi/drm/compote-uapi.h7
4 files changed, 78 insertions, 13 deletions
diff --git a/drivers/gpu/drm/nouveau/compote/compote-channel.c b/drivers/gpu/drm/nouveau/compote/compote-channel.c
index 9b9b30e999cb..b5a490acf051 100644
--- a/drivers/gpu/drm/nouveau/compote/compote-channel.c
+++ b/drivers/gpu/drm/nouveau/compote/compote-channel.c
@@ -30,6 +30,7 @@
#include "nouveau_usif.h"
#include "nouveau_abi16.h"
#include "nouveau_bo.h"
+#include "nouveau_dma.h"
int compote_channel_new(struct compote_channel **channelp,
struct compote_file *cfile)
@@ -97,9 +98,29 @@ void compote_channel_ref(struct compote_channel *channel)
void compote_channel_unref(struct compote_channel *channel)
{
- kref_put(&channel->kref, compote_channel_kref_put);
+ if (channel)
+ kref_put(&channel->kref, compote_channel_kref_put);
}
+struct compote_channel *compote_file_channel_find(struct compote_file *cfile,
+ uint64_t chid)
+{
+ struct compote_channel *channel;
+
+ down_write(&cfile->rwsem);
+ list_for_each_entry (channel, &cfile->channels, list) {
+ if (channel->nvchan->chid == chid) {
+ compote_channel_ref(channel);
+ up_write(&cfile->rwsem);
+ return channel;
+ }
+ }
+ up_write(&cfile->rwsem);
+
+ return NULL;
+}
+
+
int compote_ioctl_channel_alloc(struct compote_file *cfile, void __user *uarg)
{
struct compote_ioctl_channel_alloc arg;
@@ -135,17 +156,49 @@ int compote_ioctl_channel_free(struct compote_file *cfile,
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);
+ channel = compote_file_channel_find(cfile, arg.channel);
+ compote_channel_unref(channel);
+ compote_channel_unref(channel);
+
+ return channel ? 0 : -EINVAL;
+}
+
+int compote_ioctl_channel_execute(struct compote_file *cfile,
+ void __user *uarg)
+{
+ struct compote_ioctl_channel_execute arg;
+ struct compote_channel *channel;
+ struct nouveau_channel *nvchan;
+ struct nouveau_bo *pb;
+ int ip, ret;
+
+ ret = copy_from_user(&arg, uarg, sizeof(arg));
+ if (ret)
+ return ret;
+
+ if (arg.ndw > 0x003fffff)
+ return -EINVAL;
+
+ channel = compote_file_channel_find(cfile, arg.channel);
+ if (channel == NULL)
+ return -EINVAL;
+ nvchan = channel->nvchan;
- return -EINVAL;
+ ret = nouveau_dma_wait(nvchan, 1, 0);
+ if (ret)
+ return ret;
+
+ pb = nvchan->push.buffer;
+ ip = (nvchan->dma.ib_put * 2) + nvchan->dma.ib_base;
+ nouveau_bo_wr32(pb, ip++, lower_32_bits(arg.addr));
+ nouveau_bo_wr32(pb, ip++, upper_32_bits(arg.addr) | arg.ndw << 10);
+ nvchan->dma.ib_put = (nvchan->dma.ib_put + 1) & nvchan->dma.ib_max;
+ mb();
+ /* Flush writes. */
+ nouveau_bo_rd32(pb, 0);
+ nvif_wr32(&nvchan->user, 0x8c, nvchan->dma.ib_put);
+ nvchan->dma.ib_free--;
+
+ compote_channel_unref(channel);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/compote/compote-driver.c b/drivers/gpu/drm/nouveau/compote/compote-driver.c
index 002290d5c9f6..7d58a5de0681 100644
--- a/drivers/gpu/drm/nouveau/compote/compote-driver.c
+++ b/drivers/gpu/drm/nouveau/compote/compote-driver.c
@@ -226,6 +226,9 @@ static long compote_ioctl(struct file *file,
case COMPOTE_IOCTL_CHAN_FREE:
ret = compote_ioctl_channel_free(cfile, uarg);
break;
+ case COMPOTE_IOCTL_CHAN_EXEC:
+ ret = compote_ioctl_channel_execute(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 0a37d0a1922d..b76d013c4ba7 100644
--- a/drivers/gpu/drm/nouveau/compote/compote.h
+++ b/drivers/gpu/drm/nouveau/compote/compote.h
@@ -67,6 +67,8 @@ 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);
+int compote_ioctl_channel_execute(struct compote_file *cfile,
+ void __user *uarg);
void compote_channel_ref(struct compote_channel *channel);
void compote_channel_unref(struct compote_channel *channel);
diff --git a/include/uapi/drm/compote-uapi.h b/include/uapi/drm/compote-uapi.h
index 83f5e8a3c80a..8b10c1b092c2 100644
--- a/include/uapi/drm/compote-uapi.h
+++ b/include/uapi/drm/compote-uapi.h
@@ -37,10 +37,17 @@ struct compote_ioctl_channel_free {
uint64_t channel;
};
+struct compote_ioctl_channel_execute {
+ uint64_t channel;
+ uint64_t addr;
+ uint32_t ndw;
+};
+
/* Expose the address space of the calling process through hmm dummy dev file */
#define COMPOTE_IOCTL_MEM_ALLOC _IOWR('H', 0x00, struct compote_ioctl_mem_alloc)
#define COMPOTE_IOCTL_MEM_FREE _IOWR('H', 0x01, struct compote_ioctl_mem_free)
#define COMPOTE_IOCTL_CHAN_ALLOC _IOWR('H', 0x02, struct compote_ioctl_channel_alloc)
#define COMPOTE_IOCTL_CHAN_FREE _IOWR('H', 0x03, struct compote_ioctl_channel_free)
+#define COMPOTE_IOCTL_CHAN_EXEC _IOWR('H', 0x04, struct compote_ioctl_channel_execute)
#endif /* COMPOTE_UAPI_H */