xref: /openbmc/linux/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1acbe9ecfSBen Skeggs /*
2acbe9ecfSBen Skeggs  * Copyright 2021 Red Hat Inc.
3acbe9ecfSBen Skeggs  *
4acbe9ecfSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
5acbe9ecfSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
6acbe9ecfSBen Skeggs  * to deal in the Software without restriction, including without limitation
7acbe9ecfSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8acbe9ecfSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
9acbe9ecfSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
10acbe9ecfSBen Skeggs  *
11acbe9ecfSBen Skeggs  * The above copyright notice and this permission notice shall be included in
12acbe9ecfSBen Skeggs  * all copies or substantial portions of the Software.
13acbe9ecfSBen Skeggs  *
14acbe9ecfSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15acbe9ecfSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16acbe9ecfSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17acbe9ecfSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18acbe9ecfSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19acbe9ecfSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20acbe9ecfSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
21acbe9ecfSBen Skeggs  */
22acbe9ecfSBen Skeggs #include "chan.h"
23acbe9ecfSBen Skeggs 
24acbe9ecfSBen Skeggs #include <core/oproxy.h>
25acbe9ecfSBen Skeggs #include <core/ramht.h>
26acbe9ecfSBen Skeggs 
27*889fcbe9SBen Skeggs #include <nvif/if0014.h>
28acbe9ecfSBen Skeggs 
29acbe9ecfSBen Skeggs static int
nvkm_disp_chan_rd32(struct nvkm_object * object,u64 addr,u32 * data)30acbe9ecfSBen Skeggs nvkm_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data)
31acbe9ecfSBen Skeggs {
32acbe9ecfSBen Skeggs 	struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
33acbe9ecfSBen Skeggs 	struct nvkm_device *device = chan->disp->engine.subdev.device;
34acbe9ecfSBen Skeggs 	u64 size, base = chan->func->user(chan, &size);
35acbe9ecfSBen Skeggs 
36acbe9ecfSBen Skeggs 	*data = nvkm_rd32(device, base + addr);
37acbe9ecfSBen Skeggs 	return 0;
38acbe9ecfSBen Skeggs }
39acbe9ecfSBen Skeggs 
40acbe9ecfSBen Skeggs static int
nvkm_disp_chan_wr32(struct nvkm_object * object,u64 addr,u32 data)41acbe9ecfSBen Skeggs nvkm_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data)
42acbe9ecfSBen Skeggs {
43acbe9ecfSBen Skeggs 	struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
44acbe9ecfSBen Skeggs 	struct nvkm_device *device = chan->disp->engine.subdev.device;
45acbe9ecfSBen Skeggs 	u64 size, base = chan->func->user(chan, &size);
46acbe9ecfSBen Skeggs 
47acbe9ecfSBen Skeggs 	nvkm_wr32(device, base + addr, data);
48acbe9ecfSBen Skeggs 	return 0;
49acbe9ecfSBen Skeggs }
50acbe9ecfSBen Skeggs 
51acbe9ecfSBen Skeggs static int
nvkm_disp_chan_ntfy(struct nvkm_object * object,u32 type,struct nvkm_event ** pevent)52acbe9ecfSBen Skeggs nvkm_disp_chan_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **pevent)
53acbe9ecfSBen Skeggs {
54acbe9ecfSBen Skeggs 	struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
55acbe9ecfSBen Skeggs 	struct nvkm_disp *disp = chan->disp;
56acbe9ecfSBen Skeggs 
57acbe9ecfSBen Skeggs 	switch (type) {
58*889fcbe9SBen Skeggs 	case 0:
59acbe9ecfSBen Skeggs 		*pevent = &disp->uevent;
60acbe9ecfSBen Skeggs 		return 0;
61acbe9ecfSBen Skeggs 	default:
62acbe9ecfSBen Skeggs 		break;
63acbe9ecfSBen Skeggs 	}
64acbe9ecfSBen Skeggs 
65acbe9ecfSBen Skeggs 	return -EINVAL;
66acbe9ecfSBen Skeggs }
67acbe9ecfSBen Skeggs 
68acbe9ecfSBen Skeggs static int
nvkm_disp_chan_map(struct nvkm_object * object,void * argv,u32 argc,enum nvkm_object_map * type,u64 * addr,u64 * size)69acbe9ecfSBen Skeggs nvkm_disp_chan_map(struct nvkm_object *object, void *argv, u32 argc,
70acbe9ecfSBen Skeggs 		   enum nvkm_object_map *type, u64 *addr, u64 *size)
71acbe9ecfSBen Skeggs {
72acbe9ecfSBen Skeggs 	struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
73acbe9ecfSBen Skeggs 	struct nvkm_device *device = chan->disp->engine.subdev.device;
74acbe9ecfSBen Skeggs 	const u64 base = device->func->resource_addr(device, 0);
75acbe9ecfSBen Skeggs 
76acbe9ecfSBen Skeggs 	*type = NVKM_OBJECT_MAP_IO;
77acbe9ecfSBen Skeggs 	*addr = base + chan->func->user(chan, size);
78acbe9ecfSBen Skeggs 	return 0;
79acbe9ecfSBen Skeggs }
80acbe9ecfSBen Skeggs 
81acbe9ecfSBen Skeggs struct nvkm_disp_chan_object {
82acbe9ecfSBen Skeggs 	struct nvkm_oproxy oproxy;
83acbe9ecfSBen Skeggs 	struct nvkm_disp *disp;
84acbe9ecfSBen Skeggs 	int hash;
85acbe9ecfSBen Skeggs };
86acbe9ecfSBen Skeggs 
87acbe9ecfSBen Skeggs static void
nvkm_disp_chan_child_del_(struct nvkm_oproxy * base)88acbe9ecfSBen Skeggs nvkm_disp_chan_child_del_(struct nvkm_oproxy *base)
89acbe9ecfSBen Skeggs {
90acbe9ecfSBen Skeggs 	struct nvkm_disp_chan_object *object = container_of(base, typeof(*object), oproxy);
91acbe9ecfSBen Skeggs 
92acbe9ecfSBen Skeggs 	nvkm_ramht_remove(object->disp->ramht, object->hash);
93acbe9ecfSBen Skeggs }
94acbe9ecfSBen Skeggs 
95acbe9ecfSBen Skeggs static const struct nvkm_oproxy_func
96acbe9ecfSBen Skeggs nvkm_disp_chan_child_func_ = {
97acbe9ecfSBen Skeggs 	.dtor[0] = nvkm_disp_chan_child_del_,
98acbe9ecfSBen Skeggs };
99acbe9ecfSBen Skeggs 
100acbe9ecfSBen Skeggs static int
nvkm_disp_chan_child_new(const struct nvkm_oclass * oclass,void * argv,u32 argc,struct nvkm_object ** pobject)101acbe9ecfSBen Skeggs nvkm_disp_chan_child_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
102acbe9ecfSBen Skeggs 			 struct nvkm_object **pobject)
103acbe9ecfSBen Skeggs {
104acbe9ecfSBen Skeggs 	struct nvkm_disp_chan *chan = nvkm_disp_chan(oclass->parent);
105acbe9ecfSBen Skeggs 	struct nvkm_disp *disp = chan->disp;
106acbe9ecfSBen Skeggs 	struct nvkm_device *device = disp->engine.subdev.device;
107acbe9ecfSBen Skeggs 	const struct nvkm_device_oclass *sclass = oclass->priv;
108acbe9ecfSBen Skeggs 	struct nvkm_disp_chan_object *object;
109acbe9ecfSBen Skeggs 	int ret;
110acbe9ecfSBen Skeggs 
111acbe9ecfSBen Skeggs 	if (!(object = kzalloc(sizeof(*object), GFP_KERNEL)))
112acbe9ecfSBen Skeggs 		return -ENOMEM;
113acbe9ecfSBen Skeggs 	nvkm_oproxy_ctor(&nvkm_disp_chan_child_func_, oclass, &object->oproxy);
114acbe9ecfSBen Skeggs 	object->disp = disp;
115acbe9ecfSBen Skeggs 	*pobject = &object->oproxy.base;
116acbe9ecfSBen Skeggs 
117acbe9ecfSBen Skeggs 	ret = sclass->ctor(device, oclass, argv, argc, &object->oproxy.object);
118acbe9ecfSBen Skeggs 	if (ret)
119acbe9ecfSBen Skeggs 		return ret;
120acbe9ecfSBen Skeggs 
121acbe9ecfSBen Skeggs 	object->hash = chan->func->bind(chan, object->oproxy.object, oclass->handle);
122acbe9ecfSBen Skeggs 	if (object->hash < 0)
123acbe9ecfSBen Skeggs 		return object->hash;
124acbe9ecfSBen Skeggs 
125acbe9ecfSBen Skeggs 	return 0;
126acbe9ecfSBen Skeggs }
127acbe9ecfSBen Skeggs 
128acbe9ecfSBen Skeggs static int
nvkm_disp_chan_child_get(struct nvkm_object * object,int index,struct nvkm_oclass * sclass)129acbe9ecfSBen Skeggs nvkm_disp_chan_child_get(struct nvkm_object *object, int index, struct nvkm_oclass *sclass)
130acbe9ecfSBen Skeggs {
131acbe9ecfSBen Skeggs 	struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
132acbe9ecfSBen Skeggs 	struct nvkm_device *device = chan->disp->engine.subdev.device;
133acbe9ecfSBen Skeggs 	const struct nvkm_device_oclass *oclass = NULL;
134acbe9ecfSBen Skeggs 
135acbe9ecfSBen Skeggs 	if (chan->func->bind)
136acbe9ecfSBen Skeggs 		sclass->engine = nvkm_device_engine(device, NVKM_ENGINE_DMAOBJ, 0);
137acbe9ecfSBen Skeggs 	else
138acbe9ecfSBen Skeggs 		sclass->engine = NULL;
139acbe9ecfSBen Skeggs 
140acbe9ecfSBen Skeggs 	if (sclass->engine && sclass->engine->func->base.sclass) {
141acbe9ecfSBen Skeggs 		sclass->engine->func->base.sclass(sclass, index, &oclass);
142acbe9ecfSBen Skeggs 		if (oclass) {
143acbe9ecfSBen Skeggs 			sclass->ctor = nvkm_disp_chan_child_new;
144acbe9ecfSBen Skeggs 			sclass->priv = oclass;
145acbe9ecfSBen Skeggs 			return 0;
146acbe9ecfSBen Skeggs 		}
147acbe9ecfSBen Skeggs 	}
148acbe9ecfSBen Skeggs 
149acbe9ecfSBen Skeggs 	return -EINVAL;
150acbe9ecfSBen Skeggs }
151acbe9ecfSBen Skeggs 
152acbe9ecfSBen Skeggs static int
nvkm_disp_chan_fini(struct nvkm_object * object,bool suspend)153acbe9ecfSBen Skeggs nvkm_disp_chan_fini(struct nvkm_object *object, bool suspend)
154acbe9ecfSBen Skeggs {
155acbe9ecfSBen Skeggs 	struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
156acbe9ecfSBen Skeggs 
157acbe9ecfSBen Skeggs 	chan->func->fini(chan);
158acbe9ecfSBen Skeggs 	chan->func->intr(chan, false);
159acbe9ecfSBen Skeggs 	return 0;
160acbe9ecfSBen Skeggs }
161acbe9ecfSBen Skeggs 
162acbe9ecfSBen Skeggs static int
nvkm_disp_chan_init(struct nvkm_object * object)163acbe9ecfSBen Skeggs nvkm_disp_chan_init(struct nvkm_object *object)
164acbe9ecfSBen Skeggs {
165acbe9ecfSBen Skeggs 	struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
166acbe9ecfSBen Skeggs 
167acbe9ecfSBen Skeggs 	chan->func->intr(chan, true);
168acbe9ecfSBen Skeggs 	return chan->func->init(chan);
169acbe9ecfSBen Skeggs }
170acbe9ecfSBen Skeggs 
171acbe9ecfSBen Skeggs static void *
nvkm_disp_chan_dtor(struct nvkm_object * object)172acbe9ecfSBen Skeggs nvkm_disp_chan_dtor(struct nvkm_object *object)
173acbe9ecfSBen Skeggs {
174acbe9ecfSBen Skeggs 	struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
175acbe9ecfSBen Skeggs 	struct nvkm_disp *disp = chan->disp;
176acbe9ecfSBen Skeggs 
177*889fcbe9SBen Skeggs 	spin_lock(&disp->client.lock);
178*889fcbe9SBen Skeggs 	if (disp->chan[chan->chid.user] == chan)
179acbe9ecfSBen Skeggs 		disp->chan[chan->chid.user] = NULL;
180*889fcbe9SBen Skeggs 	spin_unlock(&disp->client.lock);
181acbe9ecfSBen Skeggs 
182acbe9ecfSBen Skeggs 	nvkm_memory_unref(&chan->memory);
183acbe9ecfSBen Skeggs 	return chan;
184acbe9ecfSBen Skeggs }
185acbe9ecfSBen Skeggs 
186acbe9ecfSBen Skeggs static const struct nvkm_object_func
187acbe9ecfSBen Skeggs nvkm_disp_chan = {
188acbe9ecfSBen Skeggs 	.dtor = nvkm_disp_chan_dtor,
189acbe9ecfSBen Skeggs 	.init = nvkm_disp_chan_init,
190acbe9ecfSBen Skeggs 	.fini = nvkm_disp_chan_fini,
191acbe9ecfSBen Skeggs 	.rd32 = nvkm_disp_chan_rd32,
192acbe9ecfSBen Skeggs 	.wr32 = nvkm_disp_chan_wr32,
193acbe9ecfSBen Skeggs 	.ntfy = nvkm_disp_chan_ntfy,
194acbe9ecfSBen Skeggs 	.map = nvkm_disp_chan_map,
195acbe9ecfSBen Skeggs 	.sclass = nvkm_disp_chan_child_get,
196acbe9ecfSBen Skeggs };
197acbe9ecfSBen Skeggs 
198*889fcbe9SBen Skeggs 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)199*889fcbe9SBen Skeggs nvkm_disp_chan_new_(struct nvkm_disp *disp, int nr, const struct nvkm_oclass *oclass,
200*889fcbe9SBen Skeggs 		    void *argv, u32 argc, struct nvkm_object **pobject)
201acbe9ecfSBen Skeggs {
202*889fcbe9SBen Skeggs 	const struct nvkm_disp_chan_user *user = NULL;
203acbe9ecfSBen Skeggs 	struct nvkm_disp_chan *chan;
204*889fcbe9SBen Skeggs 	union nvif_disp_chan_args *args = argv;
205*889fcbe9SBen Skeggs 	int ret, i;
206*889fcbe9SBen Skeggs 
207*889fcbe9SBen Skeggs 	for (i = 0; disp->func->user[i].ctor; i++) {
208*889fcbe9SBen Skeggs 		if (disp->func->user[i].base.oclass == oclass->base.oclass) {
209*889fcbe9SBen Skeggs 			user = disp->func->user[i].chan;
210*889fcbe9SBen Skeggs 			break;
211*889fcbe9SBen Skeggs 		}
212*889fcbe9SBen Skeggs 	}
213*889fcbe9SBen Skeggs 
214*889fcbe9SBen Skeggs 	if (WARN_ON(!user))
215*889fcbe9SBen Skeggs 		return -EINVAL;
216*889fcbe9SBen Skeggs 
217*889fcbe9SBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
218*889fcbe9SBen Skeggs 		return -ENOSYS;
219*889fcbe9SBen Skeggs 	if (args->v0.id >= nr || !args->v0.pushbuf != !user->func->push)
220*889fcbe9SBen Skeggs 		return -EINVAL;
221acbe9ecfSBen Skeggs 
222acbe9ecfSBen Skeggs 	if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
223acbe9ecfSBen Skeggs 		return -ENOMEM;
224acbe9ecfSBen Skeggs 	*pobject = &chan->object;
225acbe9ecfSBen Skeggs 
226acbe9ecfSBen Skeggs 	nvkm_object_ctor(&nvkm_disp_chan, oclass, &chan->object);
227*889fcbe9SBen Skeggs 	chan->func = user->func;
228*889fcbe9SBen Skeggs 	chan->mthd = user->mthd;
229acbe9ecfSBen Skeggs 	chan->disp = disp;
230*889fcbe9SBen Skeggs 	chan->chid.ctrl = user->ctrl + args->v0.id;
231*889fcbe9SBen Skeggs 	chan->chid.user = user->user + args->v0.id;
232*889fcbe9SBen Skeggs 	chan->head = args->v0.id;
233acbe9ecfSBen Skeggs 
234*889fcbe9SBen Skeggs 	if (chan->func->push) {
235*889fcbe9SBen Skeggs 		ret = chan->func->push(chan, args->v0.pushbuf);
236*889fcbe9SBen Skeggs 		if (ret)
237*889fcbe9SBen Skeggs 			return ret;
238*889fcbe9SBen Skeggs 	}
239*889fcbe9SBen Skeggs 
240*889fcbe9SBen Skeggs 	spin_lock(&disp->client.lock);
241acbe9ecfSBen Skeggs 	if (disp->chan[chan->chid.user]) {
242*889fcbe9SBen Skeggs 		spin_unlock(&disp->client.lock);
243acbe9ecfSBen Skeggs 		return -EBUSY;
244acbe9ecfSBen Skeggs 	}
245acbe9ecfSBen Skeggs 	disp->chan[chan->chid.user] = chan;
246*889fcbe9SBen Skeggs 	spin_unlock(&disp->client.lock);
247acbe9ecfSBen Skeggs 	return 0;
248acbe9ecfSBen Skeggs }
249*889fcbe9SBen Skeggs 
250*889fcbe9SBen Skeggs int
nvkm_disp_wndw_new(const struct nvkm_oclass * oclass,void * argv,u32 argc,struct nvkm_object ** pobject)251*889fcbe9SBen Skeggs nvkm_disp_wndw_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
252*889fcbe9SBen Skeggs 		   struct nvkm_object **pobject)
253*889fcbe9SBen Skeggs {
254*889fcbe9SBen Skeggs 	struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
255*889fcbe9SBen Skeggs 
256*889fcbe9SBen Skeggs 	return nvkm_disp_chan_new_(disp, disp->wndw.nr, oclass, argv, argc, pobject);
257*889fcbe9SBen Skeggs }
258*889fcbe9SBen Skeggs 
259*889fcbe9SBen Skeggs int
nvkm_disp_chan_new(const struct nvkm_oclass * oclass,void * argv,u32 argc,struct nvkm_object ** pobject)260*889fcbe9SBen Skeggs nvkm_disp_chan_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
261*889fcbe9SBen Skeggs 		   struct nvkm_object **pobject)
262*889fcbe9SBen Skeggs {
263*889fcbe9SBen Skeggs 	struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
264*889fcbe9SBen Skeggs 
265*889fcbe9SBen Skeggs 	return nvkm_disp_chan_new_(disp, disp->head.nr, oclass, argv, argc, pobject);
266*889fcbe9SBen Skeggs }
267*889fcbe9SBen Skeggs 
268*889fcbe9SBen Skeggs int
nvkm_disp_core_new(const struct nvkm_oclass * oclass,void * argv,u32 argc,struct nvkm_object ** pobject)269*889fcbe9SBen Skeggs nvkm_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
270*889fcbe9SBen Skeggs 		   struct nvkm_object **pobject)
271*889fcbe9SBen Skeggs {
272*889fcbe9SBen Skeggs 	struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
273*889fcbe9SBen Skeggs 
274*889fcbe9SBen Skeggs 	return nvkm_disp_chan_new_(disp, 1, oclass, argv, argc, pobject);
275*889fcbe9SBen Skeggs }
276