1f5e45689SBen Skeggs /*
2f5e45689SBen Skeggs  * Copyright 2021 Red Hat Inc.
3f5e45689SBen Skeggs  *
4f5e45689SBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
5f5e45689SBen Skeggs  * copy of this software and associated documentation files (the "Software"),
6f5e45689SBen Skeggs  * to deal in the Software without restriction, including without limitation
7f5e45689SBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8f5e45689SBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
9f5e45689SBen Skeggs  * Software is furnished to do so, subject to the following conditions:
10f5e45689SBen Skeggs  *
11f5e45689SBen Skeggs  * The above copyright notice and this permission notice shall be included in
12f5e45689SBen Skeggs  * all copies or substantial portions of the Software.
13f5e45689SBen Skeggs  *
14f5e45689SBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15f5e45689SBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16f5e45689SBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17f5e45689SBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18f5e45689SBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19f5e45689SBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20f5e45689SBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
21f5e45689SBen Skeggs  */
22f5e45689SBen Skeggs #define nvkm_uchan(p) container_of((p), struct nvkm_uchan, object)
2306db7fdeSBen Skeggs #include "priv.h"
24f5e45689SBen Skeggs #include "cgrp.h"
25f5e45689SBen Skeggs #include "chan.h"
2667059b9fSBen Skeggs #include "chid.h"
270fc72ee9SBen Skeggs #include "runl.h"
28f5e45689SBen Skeggs 
298ab849d6SBen Skeggs #include <core/gpuobj.h>
30f5e45689SBen Skeggs #include <core/oproxy.h>
3106db7fdeSBen Skeggs #include <subdev/mmu.h>
3206db7fdeSBen Skeggs #include <engine/dma.h>
33f5e45689SBen Skeggs 
34f5e45689SBen Skeggs #include <nvif/if0020.h>
35f5e45689SBen Skeggs 
36f5e45689SBen Skeggs struct nvkm_uchan {
37f5e45689SBen Skeggs 	struct nvkm_object object;
38f5e45689SBen Skeggs 	struct nvkm_chan *chan;
39f5e45689SBen Skeggs };
40f5e45689SBen Skeggs 
41f5e45689SBen Skeggs static int
nvkm_uchan_uevent(struct nvkm_object * object,void * argv,u32 argc,struct nvkm_uevent * uevent)42f5e45689SBen Skeggs nvkm_uchan_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_uevent *uevent)
43f5e45689SBen Skeggs {
44f5e45689SBen Skeggs 	struct nvkm_chan *chan = nvkm_uchan(object)->chan;
45d67f3b96SBen Skeggs 	struct nvkm_runl *runl = chan->cgrp->runl;
46f5e45689SBen Skeggs 	union nvif_chan_event_args *args = argv;
47f5e45689SBen Skeggs 
48f5e45689SBen Skeggs 	if (!uevent)
49f5e45689SBen Skeggs 		return 0;
50f5e45689SBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
51f5e45689SBen Skeggs 		return -ENOSYS;
52f5e45689SBen Skeggs 
53f5e45689SBen Skeggs 	switch (args->v0.type) {
54f5e45689SBen Skeggs 	case NVIF_CHAN_EVENT_V0_NON_STALL_INTR:
55*55e1a599SBen Skeggs 		return nvkm_uevent_add(uevent, &runl->fifo->nonstall.event, runl->id,
56d67f3b96SBen Skeggs 				       NVKM_FIFO_NONSTALL_EVENT, NULL);
57f5e45689SBen Skeggs 	case NVIF_CHAN_EVENT_V0_KILLED:
5867059b9fSBen Skeggs 		return nvkm_uevent_add(uevent, &runl->chid->event, chan->id,
5967059b9fSBen Skeggs 				       NVKM_CHAN_EVENT_ERRORED, NULL);
60f5e45689SBen Skeggs 	default:
61f5e45689SBen Skeggs 		break;
62f5e45689SBen Skeggs 	}
63f5e45689SBen Skeggs 
64f5e45689SBen Skeggs 	return -ENOSYS;
65f5e45689SBen Skeggs }
66f5e45689SBen Skeggs 
67f5e45689SBen Skeggs struct nvkm_uobj {
68f5e45689SBen Skeggs 	struct nvkm_oproxy oproxy;
69f5e45689SBen Skeggs 	struct nvkm_chan *chan;
70f48dd293SBen Skeggs 	struct nvkm_cctx *cctx;
717ac29332SBen Skeggs 	int hash;
72f5e45689SBen Skeggs };
73f5e45689SBen Skeggs 
74f48dd293SBen Skeggs static int
nvkm_uchan_object_fini_1(struct nvkm_oproxy * oproxy,bool suspend)75f48dd293SBen Skeggs nvkm_uchan_object_fini_1(struct nvkm_oproxy *oproxy, bool suspend)
76f48dd293SBen Skeggs {
77f48dd293SBen Skeggs 	struct nvkm_uobj *uobj = container_of(oproxy, typeof(*uobj), oproxy);
78f48dd293SBen Skeggs 	struct nvkm_chan *chan = uobj->chan;
79f48dd293SBen Skeggs 	struct nvkm_cctx *cctx = uobj->cctx;
808ab849d6SBen Skeggs 	struct nvkm_ectx *ectx = cctx->vctx->ectx;
818ab849d6SBen Skeggs 
828ab849d6SBen Skeggs 	if (!ectx->object)
838ab849d6SBen Skeggs 		return 0;
84f48dd293SBen Skeggs 
85f48dd293SBen Skeggs 	/* Unbind engine context from channel, if no longer required. */
86f48dd293SBen Skeggs 	if (refcount_dec_and_mutex_lock(&cctx->uses, &chan->cgrp->mutex)) {
878ab849d6SBen Skeggs 		nvkm_chan_cctx_bind(chan, ectx->engn, NULL);
888ab849d6SBen Skeggs 
898ab849d6SBen Skeggs 		if (refcount_dec_and_test(&ectx->uses))
908ab849d6SBen Skeggs 			nvkm_object_fini(ectx->object, false);
91f48dd293SBen Skeggs 		mutex_unlock(&chan->cgrp->mutex);
92f48dd293SBen Skeggs 	}
93f48dd293SBen Skeggs 
94f48dd293SBen Skeggs 	return 0;
95f48dd293SBen Skeggs }
96f48dd293SBen Skeggs 
97f48dd293SBen Skeggs static int
nvkm_uchan_object_init_0(struct nvkm_oproxy * oproxy)98f48dd293SBen Skeggs nvkm_uchan_object_init_0(struct nvkm_oproxy *oproxy)
99f48dd293SBen Skeggs {
100f48dd293SBen Skeggs 	struct nvkm_uobj *uobj = container_of(oproxy, typeof(*uobj), oproxy);
101f48dd293SBen Skeggs 	struct nvkm_chan *chan = uobj->chan;
102f48dd293SBen Skeggs 	struct nvkm_cctx *cctx = uobj->cctx;
1038ab849d6SBen Skeggs 	struct nvkm_ectx *ectx = cctx->vctx->ectx;
104f48dd293SBen Skeggs 	int ret = 0;
105f48dd293SBen Skeggs 
1068ab849d6SBen Skeggs 	if (!ectx->object)
1078ab849d6SBen Skeggs 		return 0;
1088ab849d6SBen Skeggs 
109f48dd293SBen Skeggs 	/* Bind engine context to channel, if it hasn't been already. */
110f48dd293SBen Skeggs 	if (!refcount_inc_not_zero(&cctx->uses)) {
111f48dd293SBen Skeggs 		mutex_lock(&chan->cgrp->mutex);
112f48dd293SBen Skeggs 		if (!refcount_inc_not_zero(&cctx->uses)) {
1138ab849d6SBen Skeggs 			if (!refcount_inc_not_zero(&ectx->uses)) {
1148ab849d6SBen Skeggs 				ret = nvkm_object_init(ectx->object);
1158ab849d6SBen Skeggs 				if (ret == 0)
1168ab849d6SBen Skeggs 					refcount_set(&ectx->uses, 1);
1178ab849d6SBen Skeggs 			}
1188ab849d6SBen Skeggs 
119f48dd293SBen Skeggs 			if (ret == 0) {
1208ab849d6SBen Skeggs 				nvkm_chan_cctx_bind(chan, ectx->engn, cctx);
121f48dd293SBen Skeggs 				refcount_set(&cctx->uses, 1);
122f48dd293SBen Skeggs 			}
123f48dd293SBen Skeggs 		}
124f48dd293SBen Skeggs 		mutex_unlock(&chan->cgrp->mutex);
125f48dd293SBen Skeggs 	}
126f48dd293SBen Skeggs 
127f48dd293SBen Skeggs 	return ret;
128f48dd293SBen Skeggs }
129f48dd293SBen Skeggs 
130f48dd293SBen Skeggs static void
nvkm_uchan_object_dtor(struct nvkm_oproxy * oproxy)131f48dd293SBen Skeggs nvkm_uchan_object_dtor(struct nvkm_oproxy *oproxy)
132f48dd293SBen Skeggs {
133f48dd293SBen Skeggs 	struct nvkm_uobj *uobj = container_of(oproxy, typeof(*uobj), oproxy);
1347ac29332SBen Skeggs 	struct nvkm_engn *engn;
135f48dd293SBen Skeggs 
1368ab849d6SBen Skeggs 	if (!uobj->cctx)
1378ab849d6SBen Skeggs 		return;
1388ab849d6SBen Skeggs 
1397ac29332SBen Skeggs 	engn = uobj->cctx->vctx->ectx->engn;
1407ac29332SBen Skeggs 	if (engn->func->ramht_del)
1417ac29332SBen Skeggs 		engn->func->ramht_del(uobj->chan, uobj->hash);
1427ac29332SBen Skeggs 
143f48dd293SBen Skeggs 	nvkm_chan_cctx_put(uobj->chan, &uobj->cctx);
144f48dd293SBen Skeggs }
145f48dd293SBen Skeggs 
146f5e45689SBen Skeggs static const struct nvkm_oproxy_func
147f5e45689SBen Skeggs nvkm_uchan_object = {
148f48dd293SBen Skeggs 	.dtor[1] = nvkm_uchan_object_dtor,
149f48dd293SBen Skeggs 	.init[0] = nvkm_uchan_object_init_0,
150f48dd293SBen Skeggs 	.fini[1] = nvkm_uchan_object_fini_1,
151f5e45689SBen Skeggs };
152f5e45689SBen Skeggs 
153f5e45689SBen Skeggs static int
nvkm_uchan_object_new(const struct nvkm_oclass * oclass,void * argv,u32 argc,struct nvkm_object ** pobject)154f5e45689SBen Skeggs nvkm_uchan_object_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
155f5e45689SBen Skeggs 		      struct nvkm_object **pobject)
156f5e45689SBen Skeggs {
157f5e45689SBen Skeggs 	struct nvkm_chan *chan = nvkm_uchan(oclass->parent)->chan;
158f48dd293SBen Skeggs 	struct nvkm_cgrp *cgrp = chan->cgrp;
159f48dd293SBen Skeggs 	struct nvkm_engn *engn;
160f5e45689SBen Skeggs 	struct nvkm_uobj *uobj;
161f48dd293SBen Skeggs 	int ret;
162f5e45689SBen Skeggs 
163f48dd293SBen Skeggs 	/* Lookup host engine state for target engine. */
164f48dd293SBen Skeggs 	engn = nvkm_runl_find_engn(engn, cgrp->runl, engn->engine == oclass->engine);
165f48dd293SBen Skeggs 	if (WARN_ON(!engn))
166f48dd293SBen Skeggs 		return -EINVAL;
167f48dd293SBen Skeggs 
168f48dd293SBen Skeggs 	/* Allocate SW object. */
169f5e45689SBen Skeggs 	if (!(uobj = kzalloc(sizeof(*uobj), GFP_KERNEL)))
170f5e45689SBen Skeggs 		return -ENOMEM;
171f5e45689SBen Skeggs 
172f5e45689SBen Skeggs 	nvkm_oproxy_ctor(&nvkm_uchan_object, oclass, &uobj->oproxy);
173f5e45689SBen Skeggs 	uobj->chan = chan;
174f5e45689SBen Skeggs 	*pobject = &uobj->oproxy.base;
175f5e45689SBen Skeggs 
176f48dd293SBen Skeggs 	/* Ref. channel context for target engine.*/
177f48dd293SBen Skeggs 	ret = nvkm_chan_cctx_get(chan, engn, &uobj->cctx, oclass->client);
178f48dd293SBen Skeggs 	if (ret)
179f48dd293SBen Skeggs 		return ret;
180f48dd293SBen Skeggs 
181f48dd293SBen Skeggs 	/* Allocate HW object. */
1827ac29332SBen Skeggs 	ret = oclass->base.ctor(&(const struct nvkm_oclass) {
1837ac29332SBen Skeggs 					.base = oclass->base,
1847ac29332SBen Skeggs 					.engn = oclass->engn,
1857ac29332SBen Skeggs 					.handle = oclass->handle,
1867ac29332SBen Skeggs 					.object = oclass->object,
1877ac29332SBen Skeggs 					.client = oclass->client,
1887ac29332SBen Skeggs 					.parent = uobj->cctx->vctx->ectx->object ?: oclass->parent,
1897ac29332SBen Skeggs 					.engine = engn->engine,
1907ac29332SBen Skeggs 				 }, argv, argc, &uobj->oproxy.object);
1917ac29332SBen Skeggs 	if (ret)
1927ac29332SBen Skeggs 		return ret;
1937ac29332SBen Skeggs 
1947ac29332SBen Skeggs 	if (engn->func->ramht_add) {
1957ac29332SBen Skeggs 		uobj->hash = engn->func->ramht_add(engn, uobj->oproxy.object, uobj->chan);
1967ac29332SBen Skeggs 		if (uobj->hash < 0)
1977ac29332SBen Skeggs 			return uobj->hash;
1987ac29332SBen Skeggs 	}
1997ac29332SBen Skeggs 
2007ac29332SBen Skeggs 	return 0;
201f5e45689SBen Skeggs }
202f5e45689SBen Skeggs 
203f5e45689SBen Skeggs static int
nvkm_uchan_sclass(struct nvkm_object * object,int index,struct nvkm_oclass * oclass)204f5e45689SBen Skeggs nvkm_uchan_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *oclass)
205f5e45689SBen Skeggs {
206f5e45689SBen Skeggs 	struct nvkm_chan *chan = nvkm_uchan(object)->chan;
2070fc72ee9SBen Skeggs 	struct nvkm_engn *engn;
20806db7fdeSBen Skeggs 	int ret, runq = 0;
209f5e45689SBen Skeggs 
2100fc72ee9SBen Skeggs 	nvkm_runl_foreach_engn(engn, chan->cgrp->runl) {
2110fc72ee9SBen Skeggs 		struct nvkm_engine *engine = engn->engine;
2120fc72ee9SBen Skeggs 		int c = 0;
213f5e45689SBen Skeggs 
21406db7fdeSBen Skeggs 		/* Each runqueue, on runlists with multiple, has its own LCE. */
21506db7fdeSBen Skeggs 		if (engn->runl->func->runqs) {
21606db7fdeSBen Skeggs 			if (engine->subdev.type == NVKM_ENGINE_CE) {
21706db7fdeSBen Skeggs 				if (chan->runq != runq++)
21806db7fdeSBen Skeggs 					continue;
21906db7fdeSBen Skeggs 			}
22006db7fdeSBen Skeggs 		}
22106db7fdeSBen Skeggs 
2220fc72ee9SBen Skeggs 		oclass->engine = engine;
2230fc72ee9SBen Skeggs 		oclass->base.oclass = 0;
2240fc72ee9SBen Skeggs 
2250fc72ee9SBen Skeggs 		if (engine->func->fifo.sclass) {
2260fc72ee9SBen Skeggs 			ret = engine->func->fifo.sclass(oclass, index);
2270fc72ee9SBen Skeggs 			if (oclass->base.oclass) {
2280fc72ee9SBen Skeggs 				if (!oclass->base.ctor)
2290fc72ee9SBen Skeggs 					oclass->base.ctor = nvkm_object_new;
230f5e45689SBen Skeggs 				oclass->ctor = nvkm_uchan_object_new;
231f5e45689SBen Skeggs 				return 0;
232f5e45689SBen Skeggs 			}
233f5e45689SBen Skeggs 
2340fc72ee9SBen Skeggs 			index -= ret;
2350fc72ee9SBen Skeggs 			continue;
2360fc72ee9SBen Skeggs 		}
2370fc72ee9SBen Skeggs 
2380fc72ee9SBen Skeggs 		while (engine->func->sclass[c].oclass) {
2390fc72ee9SBen Skeggs 			if (c++ == index) {
2400fc72ee9SBen Skeggs 				oclass->base = engine->func->sclass[index];
2410fc72ee9SBen Skeggs 				if (!oclass->base.ctor)
2420fc72ee9SBen Skeggs 					oclass->base.ctor = nvkm_object_new;
2430fc72ee9SBen Skeggs 				oclass->ctor = nvkm_uchan_object_new;
2440fc72ee9SBen Skeggs 				return 0;
2450fc72ee9SBen Skeggs 			}
2460fc72ee9SBen Skeggs 		}
2470fc72ee9SBen Skeggs 
2480fc72ee9SBen Skeggs 		index -= c;
2490fc72ee9SBen Skeggs 	}
2500fc72ee9SBen Skeggs 
2510fc72ee9SBen Skeggs 	return -EINVAL;
2520fc72ee9SBen Skeggs }
2530fc72ee9SBen Skeggs 
254f5e45689SBen Skeggs static int
nvkm_uchan_map(struct nvkm_object * object,void * argv,u32 argc,enum nvkm_object_map * type,u64 * addr,u64 * size)255f5e45689SBen Skeggs nvkm_uchan_map(struct nvkm_object *object, void *argv, u32 argc,
256f5e45689SBen Skeggs 	       enum nvkm_object_map *type, u64 *addr, u64 *size)
257f5e45689SBen Skeggs {
258f5e45689SBen Skeggs 	struct nvkm_chan *chan = nvkm_uchan(object)->chan;
25906db7fdeSBen Skeggs 	struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
260f5e45689SBen Skeggs 
261fbe9f433SBen Skeggs 	if (chan->func->userd->bar < 0)
262fbe9f433SBen Skeggs 		return -ENOSYS;
263fbe9f433SBen Skeggs 
264fbe9f433SBen Skeggs 	*type = NVKM_OBJECT_MAP_IO;
265fbe9f433SBen Skeggs 	*addr = device->func->resource_addr(device, chan->func->userd->bar) +
266fbe9f433SBen Skeggs 		chan->func->userd->base + chan->userd.base;
267fbe9f433SBen Skeggs 	*size = chan->func->userd->size;
268fbe9f433SBen Skeggs 	return 0;
269f5e45689SBen Skeggs }
270f5e45689SBen Skeggs 
271f5e45689SBen Skeggs static int
nvkm_uchan_fini(struct nvkm_object * object,bool suspend)272f5e45689SBen Skeggs nvkm_uchan_fini(struct nvkm_object *object, bool suspend)
273f5e45689SBen Skeggs {
274f5e45689SBen Skeggs 	struct nvkm_chan *chan = nvkm_uchan(object)->chan;
275f5e45689SBen Skeggs 
27667059b9fSBen Skeggs 	nvkm_chan_block(chan);
277b084fff2SBen Skeggs 	nvkm_chan_remove(chan, true);
278f5e45689SBen Skeggs 
27962742b5eSBen Skeggs 	if (chan->func->unbind)
28062742b5eSBen Skeggs 		chan->func->unbind(chan);
28162742b5eSBen Skeggs 
282f5e45689SBen Skeggs 	return 0;
283f5e45689SBen Skeggs }
284f5e45689SBen Skeggs 
285f5e45689SBen Skeggs static int
nvkm_uchan_init(struct nvkm_object * object)286f5e45689SBen Skeggs nvkm_uchan_init(struct nvkm_object *object)
287f5e45689SBen Skeggs {
288f5e45689SBen Skeggs 	struct nvkm_chan *chan = nvkm_uchan(object)->chan;
289f5e45689SBen Skeggs 
29067059b9fSBen Skeggs 	if (atomic_read(&chan->errored))
29167059b9fSBen Skeggs 		return 0;
29267059b9fSBen Skeggs 
29362742b5eSBen Skeggs 	if (chan->func->bind)
29462742b5eSBen Skeggs 		chan->func->bind(chan);
29562742b5eSBen Skeggs 
29667059b9fSBen Skeggs 	nvkm_chan_allow(chan);
297b084fff2SBen Skeggs 	nvkm_chan_insert(chan);
298b084fff2SBen Skeggs 	return 0;
299f5e45689SBen Skeggs }
300f5e45689SBen Skeggs 
301f5e45689SBen Skeggs static void *
nvkm_uchan_dtor(struct nvkm_object * object)302f5e45689SBen Skeggs nvkm_uchan_dtor(struct nvkm_object *object)
303f5e45689SBen Skeggs {
304f5e45689SBen Skeggs 	struct nvkm_uchan *uchan = nvkm_uchan(object);
305f5e45689SBen Skeggs 
306f5e45689SBen Skeggs 	nvkm_chan_del(&uchan->chan);
307f5e45689SBen Skeggs 	return uchan;
308f5e45689SBen Skeggs }
309f5e45689SBen Skeggs 
310f5e45689SBen Skeggs static const struct nvkm_object_func
311f5e45689SBen Skeggs nvkm_uchan = {
312f5e45689SBen Skeggs 	.dtor = nvkm_uchan_dtor,
313f5e45689SBen Skeggs 	.init = nvkm_uchan_init,
314f5e45689SBen Skeggs 	.fini = nvkm_uchan_fini,
315f5e45689SBen Skeggs 	.map = nvkm_uchan_map,
316f5e45689SBen Skeggs 	.sclass = nvkm_uchan_sclass,
317f5e45689SBen Skeggs 	.uevent = nvkm_uchan_uevent,
318f5e45689SBen Skeggs };
319f5e45689SBen Skeggs 
320f5e45689SBen Skeggs int
nvkm_uchan_new(struct nvkm_fifo * fifo,struct nvkm_cgrp * cgrp,const struct nvkm_oclass * oclass,void * argv,u32 argc,struct nvkm_object ** pobject)321f5e45689SBen Skeggs nvkm_uchan_new(struct nvkm_fifo *fifo, struct nvkm_cgrp *cgrp, const struct nvkm_oclass *oclass,
322f5e45689SBen Skeggs 	       void *argv, u32 argc, struct nvkm_object **pobject)
323f5e45689SBen Skeggs {
32406db7fdeSBen Skeggs 	union nvif_chan_args *args = argv;
32506db7fdeSBen Skeggs 	struct nvkm_runl *runl;
32606db7fdeSBen Skeggs 	struct nvkm_vmm *vmm = NULL;
32706db7fdeSBen Skeggs 	struct nvkm_dmaobj *ctxdma = NULL;
32806db7fdeSBen Skeggs 	struct nvkm_memory *userd = NULL;
329f5e45689SBen Skeggs 	struct nvkm_uchan *uchan;
33006db7fdeSBen Skeggs 	struct nvkm_chan *chan;
331f5e45689SBen Skeggs 	int ret;
332f5e45689SBen Skeggs 
33306db7fdeSBen Skeggs 	if (argc < sizeof(args->v0) || args->v0.version != 0)
33406db7fdeSBen Skeggs 		return -ENOSYS;
33506db7fdeSBen Skeggs 	argc -= sizeof(args->v0);
33606db7fdeSBen Skeggs 
33706db7fdeSBen Skeggs 	if (args->v0.namelen != argc)
33806db7fdeSBen Skeggs 		return -EINVAL;
33906db7fdeSBen Skeggs 
34006db7fdeSBen Skeggs 	/* Lookup objects referenced in args. */
34106db7fdeSBen Skeggs 	runl = nvkm_runl_get(fifo, args->v0.runlist, 0);
34206db7fdeSBen Skeggs 	if (!runl)
34306db7fdeSBen Skeggs 		return -EINVAL;
34406db7fdeSBen Skeggs 
34506db7fdeSBen Skeggs 	if (args->v0.vmm) {
34606db7fdeSBen Skeggs 		vmm = nvkm_uvmm_search(oclass->client, args->v0.vmm);
34706db7fdeSBen Skeggs 		if (IS_ERR(vmm))
34806db7fdeSBen Skeggs 			return PTR_ERR(vmm);
34906db7fdeSBen Skeggs 	}
35006db7fdeSBen Skeggs 
35106db7fdeSBen Skeggs 	if (args->v0.ctxdma) {
35206db7fdeSBen Skeggs 		ctxdma = nvkm_dmaobj_search(oclass->client, args->v0.ctxdma);
35306db7fdeSBen Skeggs 		if (IS_ERR(ctxdma)) {
35406db7fdeSBen Skeggs 			ret = PTR_ERR(ctxdma);
35506db7fdeSBen Skeggs 			goto done;
35606db7fdeSBen Skeggs 		}
35706db7fdeSBen Skeggs 	}
35806db7fdeSBen Skeggs 
35906db7fdeSBen Skeggs 	if (args->v0.huserd) {
36006db7fdeSBen Skeggs 		userd = nvkm_umem_search(oclass->client, args->v0.huserd);
36106db7fdeSBen Skeggs 		if (IS_ERR(userd)) {
36206db7fdeSBen Skeggs 			ret = PTR_ERR(userd);
36306db7fdeSBen Skeggs 			userd = NULL;
36406db7fdeSBen Skeggs 			goto done;
36506db7fdeSBen Skeggs 		}
36606db7fdeSBen Skeggs 	}
36706db7fdeSBen Skeggs 
36806db7fdeSBen Skeggs 	/* Allocate channel. */
36906db7fdeSBen Skeggs 	if (!(uchan = kzalloc(sizeof(*uchan), GFP_KERNEL))) {
37006db7fdeSBen Skeggs 		ret = -ENOMEM;
37106db7fdeSBen Skeggs 		goto done;
37206db7fdeSBen Skeggs 	}
373f5e45689SBen Skeggs 
374f5e45689SBen Skeggs 	nvkm_object_ctor(&nvkm_uchan, oclass, &uchan->object);
375f5e45689SBen Skeggs 	*pobject = &uchan->object;
376f5e45689SBen Skeggs 
37706db7fdeSBen Skeggs 	ret = nvkm_chan_new_(fifo->func->chan.func, runl, args->v0.runq, cgrp, args->v0.name,
37806db7fdeSBen Skeggs 			     args->v0.priv != 0, args->v0.devm, vmm, ctxdma, args->v0.offset,
37906db7fdeSBen Skeggs 			     args->v0.length, userd, args->v0.ouserd, &uchan->chan);
38006db7fdeSBen Skeggs 	if (ret)
38106db7fdeSBen Skeggs 		goto done;
382f5e45689SBen Skeggs 
38306db7fdeSBen Skeggs 	chan = uchan->chan;
38406db7fdeSBen Skeggs 
38506db7fdeSBen Skeggs 	/* Return channel info to caller. */
38606db7fdeSBen Skeggs 	if (chan->func->doorbell_handle)
38706db7fdeSBen Skeggs 		args->v0.token = chan->func->doorbell_handle(chan);
38806db7fdeSBen Skeggs 	else
38906db7fdeSBen Skeggs 		args->v0.token = ~0;
39006db7fdeSBen Skeggs 
39106db7fdeSBen Skeggs 	args->v0.chid = chan->id;
39206db7fdeSBen Skeggs 
39306db7fdeSBen Skeggs 	switch (nvkm_memory_target(chan->inst->memory)) {
39406db7fdeSBen Skeggs 	case NVKM_MEM_TARGET_INST: args->v0.aper = NVIF_CHAN_V0_INST_APER_INST; break;
39506db7fdeSBen Skeggs 	case NVKM_MEM_TARGET_VRAM: args->v0.aper = NVIF_CHAN_V0_INST_APER_VRAM; break;
39606db7fdeSBen Skeggs 	case NVKM_MEM_TARGET_HOST: args->v0.aper = NVIF_CHAN_V0_INST_APER_HOST; break;
39706db7fdeSBen Skeggs 	case NVKM_MEM_TARGET_NCOH: args->v0.aper = NVIF_CHAN_V0_INST_APER_NCOH; break;
39806db7fdeSBen Skeggs 	default:
39906db7fdeSBen Skeggs 		WARN_ON(1);
40006db7fdeSBen Skeggs 		ret = -EFAULT;
40106db7fdeSBen Skeggs 		break;
40206db7fdeSBen Skeggs 	}
40306db7fdeSBen Skeggs 
40406db7fdeSBen Skeggs 	args->v0.inst = nvkm_memory_addr(chan->inst->memory);
40506db7fdeSBen Skeggs done:
40606db7fdeSBen Skeggs 	nvkm_memory_unref(&userd);
40706db7fdeSBen Skeggs 	nvkm_vmm_unref(&vmm);
408f5e45689SBen Skeggs 	return ret;
409f5e45689SBen Skeggs }
410