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