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