summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_chan.c
diff options
context:
space:
mode:
authorBen Skeggs2014-08-09 20:10:25 +0200
committerBen Skeggs2014-08-09 21:28:04 +0200
commitbbf8906b2cad17cf9530b06db7509d0e39b02d16 (patch)
tree8b0ac662278cd6ea528c619d4ebd932f67a29fe3 /drivers/gpu/drm/nouveau/nouveau_chan.c
parentdrm/nouveau/device: audit and version NVIF_CONTROL class and methods (diff)
downloadkernel-qcow2-linux-bbf8906b2cad17cf9530b06db7509d0e39b02d16.tar.gz
kernel-qcow2-linux-bbf8906b2cad17cf9530b06db7509d0e39b02d16.tar.xz
kernel-qcow2-linux-bbf8906b2cad17cf9530b06db7509d0e39b02d16.zip
drm/nouveau/fifo: audit and version fifo channel classes
The full object interfaces are about to be exposed to userspace, so we need to check for any security-related issues and version the structs to make it easier to handle any changes we may need in the future. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_chan.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_chan.c62
1 files changed, 43 insertions, 19 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
index 5ce2110b31f3..ab2d9ff45a44 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -187,14 +187,18 @@ static int
nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
u32 handle, u32 engine, struct nouveau_channel **pchan)
{
- static const u16 oclasses[] = { NVE0_CHANNEL_IND_CLASS,
- NVC0_CHANNEL_IND_CLASS,
- NV84_CHANNEL_IND_CLASS,
- NV50_CHANNEL_IND_CLASS,
+ static const u16 oclasses[] = { KEPLER_CHANNEL_GPFIFO_A,
+ FERMI_CHANNEL_GPFIFO,
+ G82_CHANNEL_GPFIFO,
+ NV50_CHANNEL_GPFIFO,
0 };
const u16 *oclass = oclasses;
- struct nve0_channel_ind_class args;
+ union {
+ struct nv50_channel_gpfifo_v0 nv50;
+ struct kepler_channel_gpfifo_a_v0 kepler;
+ } args, *retn;
struct nouveau_channel *chan;
+ u32 size;
int ret;
/* allocate dma push buffer */
@@ -204,16 +208,32 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
return ret;
/* create channel object */
- args.pushbuf = chan->push.ctxdma.handle;
- args.ioffset = 0x10000 + chan->push.vma.offset;
- args.ilength = 0x02000;
- args.engine = engine;
-
do {
+ if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) {
+ args.kepler.version = 0;
+ args.kepler.engine = engine;
+ args.kepler.pushbuf = chan->push.ctxdma.handle;
+ args.kepler.ilength = 0x02000;
+ args.kepler.ioffset = 0x10000 + chan->push.vma.offset;
+ size = sizeof(args.kepler);
+ } else {
+ args.nv50.version = 0;
+ args.nv50.pushbuf = chan->push.ctxdma.handle;
+ args.nv50.ilength = 0x02000;
+ args.nv50.ioffset = 0x10000 + chan->push.vma.offset;
+ size = sizeof(args.nv50);
+ }
+
ret = nvif_object_new(nvif_object(device), handle, *oclass++,
- &args, sizeof(args), &chan->object);
- if (ret == 0)
+ &args, size, &chan->object);
+ if (ret == 0) {
+ retn = chan->object->data;
+ if (chan->object->oclass >= KEPLER_CHANNEL_GPFIFO_A)
+ chan->chid = retn->kepler.chid;
+ else
+ chan->chid = retn->nv50.chid;
return ret;
+ }
} while (*oclass);
nouveau_channel_del(pchan);
@@ -224,13 +244,13 @@ static int
nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device,
u32 handle, struct nouveau_channel **pchan)
{
- static const u16 oclasses[] = { NV40_CHANNEL_DMA_CLASS,
- NV17_CHANNEL_DMA_CLASS,
- NV10_CHANNEL_DMA_CLASS,
- NV03_CHANNEL_DMA_CLASS,
+ static const u16 oclasses[] = { NV40_CHANNEL_DMA,
+ NV17_CHANNEL_DMA,
+ NV10_CHANNEL_DMA,
+ NV03_CHANNEL_DMA,
0 };
const u16 *oclass = oclasses;
- struct nv03_channel_dma_class args;
+ struct nv03_channel_dma_v0 args, *retn;
struct nouveau_channel *chan;
int ret;
@@ -241,14 +261,18 @@ nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device,
return ret;
/* create channel object */
+ args.version = 0;
args.pushbuf = chan->push.ctxdma.handle;
args.offset = chan->push.vma.offset;
do {
ret = nvif_object_new(nvif_object(device), handle, *oclass++,
- &args, sizeof(args), &chan->object);
- if (ret == 0)
+ &args, sizeof(args), &chan->object);
+ if (ret == 0) {
+ retn = chan->object->data;
+ chan->chid = retn->chid;
return ret;
+ }
} while (ret && *oclass);
nouveau_channel_del(pchan);