summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c82
1 files changed, 67 insertions, 15 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c
index fac9fc41847c..d5e18daed79f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c
@@ -24,7 +24,7 @@
#include <core/oproxy.h>
#include <core/ramht.h>
-#include <nvif/cl507d.h>
+#include <nvif/if0014.h>
static int
nvkm_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data)
@@ -55,7 +55,7 @@ nvkm_disp_chan_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **pe
struct nvkm_disp *disp = chan->disp;
switch (type) {
- case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT:
+ case 0:
*pevent = &disp->uevent;
return 0;
default:
@@ -174,8 +174,10 @@ nvkm_disp_chan_dtor(struct nvkm_object *object)
struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
struct nvkm_disp *disp = chan->disp;
- if (chan->chid.user >= 0)
+ spin_lock(&disp->client.lock);
+ if (disp->chan[chan->chid.user] == chan)
disp->chan[chan->chid.user] = NULL;
+ spin_unlock(&disp->client.lock);
nvkm_memory_unref(&chan->memory);
return chan;
@@ -193,31 +195,81 @@ nvkm_disp_chan = {
.sclass = nvkm_disp_chan_child_get,
};
-int
-nvkm_disp_chan_new_(const struct nvkm_disp_chan_func *func,
- const struct nvkm_disp_chan_mthd *mthd,
- struct nvkm_disp *disp, int ctrl, int user, int head,
- const struct nvkm_oclass *oclass,
- struct nvkm_object **pobject)
+static int
+nvkm_disp_chan_new_(struct nvkm_disp *disp, int nr, const struct nvkm_oclass *oclass,
+ void *argv, u32 argc, struct nvkm_object **pobject)
{
+ const struct nvkm_disp_chan_user *user = NULL;
struct nvkm_disp_chan *chan;
+ union nvif_disp_chan_args *args = argv;
+ int ret, i;
+
+ for (i = 0; disp->func->user[i].ctor; i++) {
+ if (disp->func->user[i].base.oclass == oclass->base.oclass) {
+ user = disp->func->user[i].chan;
+ break;
+ }
+ }
+
+ if (WARN_ON(!user))
+ return -EINVAL;
+
+ if (argc != sizeof(args->v0) || args->v0.version != 0)
+ return -ENOSYS;
+ if (args->v0.id >= nr || !args->v0.pushbuf != !user->func->push)
+ return -EINVAL;
if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
return -ENOMEM;
*pobject = &chan->object;
nvkm_object_ctor(&nvkm_disp_chan, oclass, &chan->object);
- chan->func = func;
- chan->mthd = mthd;
+ chan->func = user->func;
+ chan->mthd = user->mthd;
chan->disp = disp;
- chan->chid.ctrl = ctrl;
- chan->chid.user = user;
- chan->head = head;
+ chan->chid.ctrl = user->ctrl + args->v0.id;
+ chan->chid.user = user->user + args->v0.id;
+ chan->head = args->v0.id;
+
+ if (chan->func->push) {
+ ret = chan->func->push(chan, args->v0.pushbuf);
+ if (ret)
+ return ret;
+ }
+ spin_lock(&disp->client.lock);
if (disp->chan[chan->chid.user]) {
- chan->chid.user = -1;
+ spin_unlock(&disp->client.lock);
return -EBUSY;
}
disp->chan[chan->chid.user] = chan;
+ spin_unlock(&disp->client.lock);
return 0;
}
+
+int
+nvkm_disp_wndw_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
+
+ return nvkm_disp_chan_new_(disp, disp->wndw.nr, oclass, argv, argc, pobject);
+}
+
+int
+nvkm_disp_chan_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
+
+ return nvkm_disp_chan_new_(disp, disp->head.nr, oclass, argv, argc, pobject);
+}
+
+int
+nvkm_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
+
+ return nvkm_disp_chan_new_(disp, 1, oclass, argv, argc, pobject);
+}