xref: /openbmc/linux/drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1468fae7bSBen Skeggs /*
2468fae7bSBen Skeggs  * Copyright 2021 Red Hat Inc.
3468fae7bSBen Skeggs  *
4468fae7bSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
5468fae7bSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
6468fae7bSBen Skeggs  * to deal in the Software without restriction, including without limitation
7468fae7bSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8468fae7bSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
9468fae7bSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
10468fae7bSBen Skeggs  *
11468fae7bSBen Skeggs  * The above copyright notice and this permission notice shall be included in
12468fae7bSBen Skeggs  * all copies or substantial portions of the Software.
13468fae7bSBen Skeggs  *
14468fae7bSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15468fae7bSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16468fae7bSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17468fae7bSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18468fae7bSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19468fae7bSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20468fae7bSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
21468fae7bSBen Skeggs  */
22468fae7bSBen Skeggs #include "cgrp.h"
23468fae7bSBen Skeggs #include "chan.h"
24468fae7bSBen Skeggs #include "chid.h"
25468fae7bSBen Skeggs #include "runl.h"
26468fae7bSBen Skeggs #include "priv.h"
27468fae7bSBen Skeggs 
28*8ab849d6SBen Skeggs #include <core/gpuobj.h>
29468fae7bSBen Skeggs #include <subdev/mmu.h>
30468fae7bSBen Skeggs 
31468fae7bSBen Skeggs static void
nvkm_cgrp_ectx_put(struct nvkm_cgrp * cgrp,struct nvkm_ectx ** pectx)32f48dd293SBen Skeggs nvkm_cgrp_ectx_put(struct nvkm_cgrp *cgrp, struct nvkm_ectx **pectx)
33f48dd293SBen Skeggs {
34f48dd293SBen Skeggs 	struct nvkm_ectx *ectx = *pectx;
35f48dd293SBen Skeggs 
36f48dd293SBen Skeggs 	if (ectx) {
37f48dd293SBen Skeggs 		struct nvkm_engn *engn = ectx->engn;
38f48dd293SBen Skeggs 
39f48dd293SBen Skeggs 		if (refcount_dec_and_test(&ectx->refs)) {
40f48dd293SBen Skeggs 			CGRP_TRACE(cgrp, "dtor ectx %d[%s]", engn->id, engn->engine->subdev.name);
41*8ab849d6SBen Skeggs 			nvkm_object_del(&ectx->object);
42f48dd293SBen Skeggs 			list_del(&ectx->head);
43f48dd293SBen Skeggs 			kfree(ectx);
44f48dd293SBen Skeggs 		}
45f48dd293SBen Skeggs 
46f48dd293SBen Skeggs 		*pectx = NULL;
47f48dd293SBen Skeggs 	}
48f48dd293SBen Skeggs }
49f48dd293SBen Skeggs 
50f48dd293SBen Skeggs static int
nvkm_cgrp_ectx_get(struct nvkm_cgrp * cgrp,struct nvkm_engn * engn,struct nvkm_ectx ** pectx,struct nvkm_chan * chan,struct nvkm_client * client)51f48dd293SBen Skeggs nvkm_cgrp_ectx_get(struct nvkm_cgrp *cgrp, struct nvkm_engn *engn, struct nvkm_ectx **pectx,
52f48dd293SBen Skeggs 		   struct nvkm_chan *chan, struct nvkm_client *client)
53f48dd293SBen Skeggs {
54*8ab849d6SBen Skeggs 	struct nvkm_engine *engine = engn->engine;
55*8ab849d6SBen Skeggs 	struct nvkm_oclass cclass = {
56*8ab849d6SBen Skeggs 		.client = client,
57*8ab849d6SBen Skeggs 		.engine = engine,
58*8ab849d6SBen Skeggs 	};
59f48dd293SBen Skeggs 	struct nvkm_ectx *ectx;
60f48dd293SBen Skeggs 	int ret = 0;
61f48dd293SBen Skeggs 
62f48dd293SBen Skeggs 	/* Look for an existing context for this engine in the channel group. */
63f48dd293SBen Skeggs 	ectx = nvkm_list_find(ectx, &cgrp->ectxs, head, ectx->engn == engn);
64f48dd293SBen Skeggs 	if (ectx) {
65f48dd293SBen Skeggs 		refcount_inc(&ectx->refs);
66f48dd293SBen Skeggs 		*pectx = ectx;
67f48dd293SBen Skeggs 		return 0;
68f48dd293SBen Skeggs 	}
69f48dd293SBen Skeggs 
70f48dd293SBen Skeggs 	/* Nope - create a fresh one. */
71f48dd293SBen Skeggs 	CGRP_TRACE(cgrp, "ctor ectx %d[%s]", engn->id, engn->engine->subdev.name);
72f48dd293SBen Skeggs 	if (!(ectx = *pectx = kzalloc(sizeof(*ectx), GFP_KERNEL)))
73f48dd293SBen Skeggs 		return -ENOMEM;
74f48dd293SBen Skeggs 
75f48dd293SBen Skeggs 	ectx->engn = engn;
76f48dd293SBen Skeggs 	refcount_set(&ectx->refs, 1);
77*8ab849d6SBen Skeggs 	refcount_set(&ectx->uses, 0);
78f48dd293SBen Skeggs 	list_add_tail(&ectx->head, &cgrp->ectxs);
79*8ab849d6SBen Skeggs 
80*8ab849d6SBen Skeggs 	/* Allocate the HW structures. */
81*8ab849d6SBen Skeggs 	if (engine->func->fifo.cclass)
82*8ab849d6SBen Skeggs 		ret = engine->func->fifo.cclass(chan, &cclass, &ectx->object);
83*8ab849d6SBen Skeggs 	else if (engine->func->cclass)
84*8ab849d6SBen Skeggs 		ret = nvkm_object_new_(engine->func->cclass, &cclass, NULL, 0, &ectx->object);
85*8ab849d6SBen Skeggs 
86*8ab849d6SBen Skeggs 	if (ret)
87*8ab849d6SBen Skeggs 		nvkm_cgrp_ectx_put(cgrp, pectx);
88*8ab849d6SBen Skeggs 
89f48dd293SBen Skeggs 	return ret;
90f48dd293SBen Skeggs }
91f48dd293SBen Skeggs 
92f48dd293SBen Skeggs void
nvkm_cgrp_vctx_put(struct nvkm_cgrp * cgrp,struct nvkm_vctx ** pvctx)93f48dd293SBen Skeggs nvkm_cgrp_vctx_put(struct nvkm_cgrp *cgrp, struct nvkm_vctx **pvctx)
94f48dd293SBen Skeggs {
95f48dd293SBen Skeggs 	struct nvkm_vctx *vctx = *pvctx;
96f48dd293SBen Skeggs 
97f48dd293SBen Skeggs 	if (vctx) {
98f48dd293SBen Skeggs 		struct nvkm_engn *engn = vctx->ectx->engn;
99f48dd293SBen Skeggs 
100f48dd293SBen Skeggs 		if (refcount_dec_and_test(&vctx->refs)) {
101f48dd293SBen Skeggs 			CGRP_TRACE(cgrp, "dtor vctx %d[%s]", engn->id, engn->engine->subdev.name);
102*8ab849d6SBen Skeggs 			nvkm_vmm_put(vctx->vmm, &vctx->vma);
103*8ab849d6SBen Skeggs 			nvkm_gpuobj_del(&vctx->inst);
104f48dd293SBen Skeggs 
105f48dd293SBen Skeggs 			nvkm_cgrp_ectx_put(cgrp, &vctx->ectx);
106f48dd293SBen Skeggs 			if (vctx->vmm) {
107f48dd293SBen Skeggs 				atomic_dec(&vctx->vmm->engref[engn->engine->subdev.type]);
108f48dd293SBen Skeggs 				nvkm_vmm_unref(&vctx->vmm);
109f48dd293SBen Skeggs 			}
110f48dd293SBen Skeggs 			list_del(&vctx->head);
111f48dd293SBen Skeggs 			kfree(vctx);
112f48dd293SBen Skeggs 		}
113f48dd293SBen Skeggs 
114f48dd293SBen Skeggs 		*pvctx = NULL;
115f48dd293SBen Skeggs 	}
116f48dd293SBen Skeggs }
117f48dd293SBen Skeggs 
118f48dd293SBen Skeggs int
nvkm_cgrp_vctx_get(struct nvkm_cgrp * cgrp,struct nvkm_engn * engn,struct nvkm_chan * chan,struct nvkm_vctx ** pvctx,struct nvkm_client * client)119f48dd293SBen Skeggs nvkm_cgrp_vctx_get(struct nvkm_cgrp *cgrp, struct nvkm_engn *engn, struct nvkm_chan *chan,
120f48dd293SBen Skeggs 		   struct nvkm_vctx **pvctx, struct nvkm_client *client)
121f48dd293SBen Skeggs {
122f48dd293SBen Skeggs 	struct nvkm_ectx *ectx;
123f48dd293SBen Skeggs 	struct nvkm_vctx *vctx;
124f48dd293SBen Skeggs 	int ret;
125f48dd293SBen Skeggs 
126f48dd293SBen Skeggs 	/* Look for an existing sub-context for this engine+VEID in the channel group. */
127f48dd293SBen Skeggs 	vctx = nvkm_list_find(vctx, &cgrp->vctxs, head,
128f48dd293SBen Skeggs 			      vctx->ectx->engn == engn && vctx->vmm == chan->vmm);
129f48dd293SBen Skeggs 	if (vctx) {
130f48dd293SBen Skeggs 		refcount_inc(&vctx->refs);
131f48dd293SBen Skeggs 		*pvctx = vctx;
132f48dd293SBen Skeggs 		return 0;
133f48dd293SBen Skeggs 	}
134f48dd293SBen Skeggs 
135f48dd293SBen Skeggs 	/* Nope - create a fresh one.  But, context first. */
136f48dd293SBen Skeggs 	ret = nvkm_cgrp_ectx_get(cgrp, engn, &ectx, chan, client);
137f48dd293SBen Skeggs 	if (ret) {
138f48dd293SBen Skeggs 		CGRP_ERROR(cgrp, "ectx %d[%s]: %d", engn->id, engn->engine->subdev.name, ret);
139f48dd293SBen Skeggs 		return ret;
140f48dd293SBen Skeggs 	}
141f48dd293SBen Skeggs 
142f48dd293SBen Skeggs 	/* Now, create the sub-context. */
143f48dd293SBen Skeggs 	CGRP_TRACE(cgrp, "ctor vctx %d[%s]", engn->id, engn->engine->subdev.name);
144f48dd293SBen Skeggs 	if (!(vctx = *pvctx = kzalloc(sizeof(*vctx), GFP_KERNEL))) {
145f48dd293SBen Skeggs 		nvkm_cgrp_ectx_put(cgrp, &ectx);
146f48dd293SBen Skeggs 		return -ENOMEM;
147f48dd293SBen Skeggs 	}
148f48dd293SBen Skeggs 
149f48dd293SBen Skeggs 	vctx->ectx = ectx;
150f48dd293SBen Skeggs 	vctx->vmm = nvkm_vmm_ref(chan->vmm);
151f48dd293SBen Skeggs 	refcount_set(&vctx->refs, 1);
152f48dd293SBen Skeggs 	list_add_tail(&vctx->head, &cgrp->vctxs);
153*8ab849d6SBen Skeggs 
154*8ab849d6SBen Skeggs 	/* MMU on some GPUs needs to know engine usage for TLB invalidation. */
155*8ab849d6SBen Skeggs 	if (vctx->vmm)
156*8ab849d6SBen Skeggs 		atomic_inc(&vctx->vmm->engref[engn->engine->subdev.type]);
157*8ab849d6SBen Skeggs 
158*8ab849d6SBen Skeggs 	/* Allocate the HW structures. */
159*8ab849d6SBen Skeggs 	if (engn->func->bind) {
160*8ab849d6SBen Skeggs 		ret = nvkm_object_bind(vctx->ectx->object, NULL, 0, &vctx->inst);
161*8ab849d6SBen Skeggs 		if (ret == 0 && engn->func->ctor)
162*8ab849d6SBen Skeggs 			ret = engn->func->ctor(engn, vctx);
163*8ab849d6SBen Skeggs 	}
164*8ab849d6SBen Skeggs 
165*8ab849d6SBen Skeggs 	if (ret)
166*8ab849d6SBen Skeggs 		nvkm_cgrp_vctx_put(cgrp, pvctx);
167*8ab849d6SBen Skeggs 
168f48dd293SBen Skeggs 	return ret;
169f48dd293SBen Skeggs }
170f48dd293SBen Skeggs 
171f48dd293SBen Skeggs static void
nvkm_cgrp_del(struct kref * kref)172468fae7bSBen Skeggs nvkm_cgrp_del(struct kref *kref)
173468fae7bSBen Skeggs {
174468fae7bSBen Skeggs 	struct nvkm_cgrp *cgrp = container_of(kref, typeof(*cgrp), kref);
175468fae7bSBen Skeggs 	struct nvkm_runl *runl = cgrp->runl;
176468fae7bSBen Skeggs 
177468fae7bSBen Skeggs 	if (runl->cgid)
178468fae7bSBen Skeggs 		nvkm_chid_put(runl->cgid, cgrp->id, &cgrp->lock);
179468fae7bSBen Skeggs 
180f48dd293SBen Skeggs 	mutex_destroy(&cgrp->mutex);
181468fae7bSBen Skeggs 	nvkm_vmm_unref(&cgrp->vmm);
182468fae7bSBen Skeggs 	kfree(cgrp);
183468fae7bSBen Skeggs }
184468fae7bSBen Skeggs 
185468fae7bSBen Skeggs void
nvkm_cgrp_unref(struct nvkm_cgrp ** pcgrp)186468fae7bSBen Skeggs nvkm_cgrp_unref(struct nvkm_cgrp **pcgrp)
187468fae7bSBen Skeggs {
188468fae7bSBen Skeggs 	struct nvkm_cgrp *cgrp = *pcgrp;
189468fae7bSBen Skeggs 
190468fae7bSBen Skeggs 	if (!cgrp)
191468fae7bSBen Skeggs 		return;
192468fae7bSBen Skeggs 
193468fae7bSBen Skeggs 	kref_put(&cgrp->kref, nvkm_cgrp_del);
194468fae7bSBen Skeggs 	*pcgrp = NULL;
195468fae7bSBen Skeggs }
196468fae7bSBen Skeggs 
197468fae7bSBen Skeggs struct nvkm_cgrp *
nvkm_cgrp_ref(struct nvkm_cgrp * cgrp)198468fae7bSBen Skeggs nvkm_cgrp_ref(struct nvkm_cgrp *cgrp)
199468fae7bSBen Skeggs {
200468fae7bSBen Skeggs 	if (cgrp)
201468fae7bSBen Skeggs 		kref_get(&cgrp->kref);
202468fae7bSBen Skeggs 
203468fae7bSBen Skeggs 	return cgrp;
204468fae7bSBen Skeggs }
205468fae7bSBen Skeggs 
2064d60100aSBen Skeggs void
nvkm_cgrp_put(struct nvkm_cgrp ** pcgrp,unsigned long irqflags)2074d60100aSBen Skeggs nvkm_cgrp_put(struct nvkm_cgrp **pcgrp, unsigned long irqflags)
2084d60100aSBen Skeggs {
2094d60100aSBen Skeggs 	struct nvkm_cgrp *cgrp = *pcgrp;
2104d60100aSBen Skeggs 
2114d60100aSBen Skeggs 	if (!cgrp)
2124d60100aSBen Skeggs 		return;
2134d60100aSBen Skeggs 
2144d60100aSBen Skeggs 	*pcgrp = NULL;
2154d60100aSBen Skeggs 	spin_unlock_irqrestore(&cgrp->lock, irqflags);
2164d60100aSBen Skeggs }
2174d60100aSBen Skeggs 
218468fae7bSBen Skeggs int
nvkm_cgrp_new(struct nvkm_runl * runl,const char * name,struct nvkm_vmm * vmm,bool hw,struct nvkm_cgrp ** pcgrp)219468fae7bSBen Skeggs nvkm_cgrp_new(struct nvkm_runl *runl, const char *name, struct nvkm_vmm *vmm, bool hw,
220468fae7bSBen Skeggs 	      struct nvkm_cgrp **pcgrp)
221468fae7bSBen Skeggs {
222468fae7bSBen Skeggs 	struct nvkm_cgrp *cgrp;
223468fae7bSBen Skeggs 
224468fae7bSBen Skeggs 	if (!(cgrp = *pcgrp = kmalloc(sizeof(*cgrp), GFP_KERNEL)))
225468fae7bSBen Skeggs 		return -ENOMEM;
226468fae7bSBen Skeggs 
227468fae7bSBen Skeggs 	cgrp->func = runl->fifo->func->cgrp.func;
228468fae7bSBen Skeggs 	strscpy(cgrp->name, name, sizeof(cgrp->name));
229468fae7bSBen Skeggs 	cgrp->runl = runl;
230468fae7bSBen Skeggs 	cgrp->vmm = nvkm_vmm_ref(vmm);
231468fae7bSBen Skeggs 	cgrp->hw = hw;
232468fae7bSBen Skeggs 	cgrp->id = -1;
233468fae7bSBen Skeggs 	kref_init(&cgrp->kref);
234b084fff2SBen Skeggs 	INIT_LIST_HEAD(&cgrp->chans);
235468fae7bSBen Skeggs 	cgrp->chan_nr = 0;
236468fae7bSBen Skeggs 	spin_lock_init(&cgrp->lock);
237f48dd293SBen Skeggs 	INIT_LIST_HEAD(&cgrp->ectxs);
238f48dd293SBen Skeggs 	INIT_LIST_HEAD(&cgrp->vctxs);
239f48dd293SBen Skeggs 	mutex_init(&cgrp->mutex);
2404d60100aSBen Skeggs 	atomic_set(&cgrp->rc, NVKM_CGRP_RC_NONE);
241468fae7bSBen Skeggs 
242468fae7bSBen Skeggs 	if (runl->cgid) {
243468fae7bSBen Skeggs 		cgrp->id = nvkm_chid_get(runl->cgid, cgrp);
244468fae7bSBen Skeggs 		if (cgrp->id < 0) {
245468fae7bSBen Skeggs 			RUNL_ERROR(runl, "!cgids");
246468fae7bSBen Skeggs 			nvkm_cgrp_unref(pcgrp);
247468fae7bSBen Skeggs 			return -ENOSPC;
248468fae7bSBen Skeggs 		}
249468fae7bSBen Skeggs 	}
250468fae7bSBen Skeggs 
251468fae7bSBen Skeggs 	return 0;
252468fae7bSBen Skeggs }
253