1c39f472eSBen Skeggs /*
2c39f472eSBen Skeggs  * Copyright 2012 Red Hat Inc.
3c39f472eSBen Skeggs  *
4c39f472eSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
5c39f472eSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
6c39f472eSBen Skeggs  * to deal in the Software without restriction, including without limitation
7c39f472eSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c39f472eSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
9c39f472eSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
10c39f472eSBen Skeggs  *
11c39f472eSBen Skeggs  * The above copyright notice and this permission notice shall be included in
12c39f472eSBen Skeggs  * all copies or substantial portions of the Software.
13c39f472eSBen Skeggs  *
14c39f472eSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c39f472eSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c39f472eSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17c39f472eSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18c39f472eSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19c39f472eSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20c39f472eSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
21c39f472eSBen Skeggs  *
22c39f472eSBen Skeggs  * Authors: Ben Skeggs
23c39f472eSBen Skeggs  */
249a65a38cSBen Skeggs #include "priv.h"
259a65a38cSBen Skeggs #include "chan.h"
26800ac1f8SBen Skeggs #include "chid.h"
27*d94470e9SBen Skeggs #include "runl.h"
281c488ba9SBen Skeggs #include "runq.h"
29c39f472eSBen Skeggs 
3013de7f46SBen Skeggs #include <core/gpuobj.h>
315e721ad1SBen Skeggs #include <subdev/mc.h>
3205c7145dSBen Skeggs 
33eb47db4fSBen Skeggs #include <nvif/cl0080.h>
3405c7145dSBen Skeggs #include <nvif/unpack.h>
35c39f472eSBen Skeggs 
36344c2d42SBen Skeggs void
3721e6de29SBen Skeggs nvkm_fifo_recover_chan(struct nvkm_fifo *fifo, int chid)
3821e6de29SBen Skeggs {
3921e6de29SBen Skeggs 	unsigned long flags;
4021e6de29SBen Skeggs 	if (WARN_ON(!fifo->func->recover_chan))
4121e6de29SBen Skeggs 		return;
4221e6de29SBen Skeggs 	spin_lock_irqsave(&fifo->lock, flags);
4321e6de29SBen Skeggs 	fifo->func->recover_chan(fifo, chid);
4421e6de29SBen Skeggs 	spin_unlock_irqrestore(&fifo->lock, flags);
4521e6de29SBen Skeggs }
4621e6de29SBen Skeggs 
4721e6de29SBen Skeggs void
4813de7f46SBen Skeggs nvkm_fifo_pause(struct nvkm_fifo *fifo, unsigned long *flags)
4913de7f46SBen Skeggs {
5013de7f46SBen Skeggs 	return fifo->func->pause(fifo, flags);
5113de7f46SBen Skeggs }
5213de7f46SBen Skeggs 
5313de7f46SBen Skeggs void
5413de7f46SBen Skeggs nvkm_fifo_start(struct nvkm_fifo *fifo, unsigned long *flags)
5513de7f46SBen Skeggs {
5613de7f46SBen Skeggs 	return fifo->func->start(fifo, flags);
5713de7f46SBen Skeggs }
5813de7f46SBen Skeggs 
5913de7f46SBen Skeggs void
60ddc669e2SBen Skeggs nvkm_fifo_fault(struct nvkm_fifo *fifo, struct nvkm_fault_data *info)
61ddc669e2SBen Skeggs {
629be9c606SBen Skeggs 	return fifo->func->mmu_fault->recover(fifo, info);
63ddc669e2SBen Skeggs }
64ddc669e2SBen Skeggs 
65ddc669e2SBen Skeggs void
66344c2d42SBen Skeggs nvkm_fifo_chan_put(struct nvkm_fifo *fifo, unsigned long flags,
67344c2d42SBen Skeggs 		   struct nvkm_fifo_chan **pchan)
68344c2d42SBen Skeggs {
69344c2d42SBen Skeggs 	struct nvkm_fifo_chan *chan = *pchan;
70344c2d42SBen Skeggs 	if (likely(chan)) {
71344c2d42SBen Skeggs 		*pchan = NULL;
72344c2d42SBen Skeggs 		spin_unlock_irqrestore(&fifo->lock, flags);
73344c2d42SBen Skeggs 	}
74344c2d42SBen Skeggs }
75344c2d42SBen Skeggs 
76344c2d42SBen Skeggs struct nvkm_fifo_chan *
773534821dSBen Skeggs nvkm_fifo_chan_inst_locked(struct nvkm_fifo *fifo, u64 inst)
783534821dSBen Skeggs {
793534821dSBen Skeggs 	struct nvkm_fifo_chan *chan;
803534821dSBen Skeggs 	list_for_each_entry(chan, &fifo->chan, head) {
813534821dSBen Skeggs 		if (chan->inst->addr == inst) {
823534821dSBen Skeggs 			list_del(&chan->head);
833534821dSBen Skeggs 			list_add(&chan->head, &fifo->chan);
843534821dSBen Skeggs 			return chan;
853534821dSBen Skeggs 		}
863534821dSBen Skeggs 	}
873534821dSBen Skeggs 	return NULL;
883534821dSBen Skeggs }
893534821dSBen Skeggs 
903534821dSBen Skeggs struct nvkm_fifo_chan *
91344c2d42SBen Skeggs nvkm_fifo_chan_inst(struct nvkm_fifo *fifo, u64 inst, unsigned long *rflags)
92344c2d42SBen Skeggs {
938f0649b5SBen Skeggs 	struct nvkm_fifo_chan *chan;
94344c2d42SBen Skeggs 	unsigned long flags;
95344c2d42SBen Skeggs 	spin_lock_irqsave(&fifo->lock, flags);
963534821dSBen Skeggs 	if ((chan = nvkm_fifo_chan_inst_locked(fifo, inst))) {
97344c2d42SBen Skeggs 		*rflags = flags;
98344c2d42SBen Skeggs 		return chan;
99344c2d42SBen Skeggs 	}
100344c2d42SBen Skeggs 	spin_unlock_irqrestore(&fifo->lock, flags);
101344c2d42SBen Skeggs 	return NULL;
102344c2d42SBen Skeggs }
103344c2d42SBen Skeggs 
104344c2d42SBen Skeggs struct nvkm_fifo_chan *
105344c2d42SBen Skeggs nvkm_fifo_chan_chid(struct nvkm_fifo *fifo, int chid, unsigned long *rflags)
106344c2d42SBen Skeggs {
1078f0649b5SBen Skeggs 	struct nvkm_fifo_chan *chan;
108344c2d42SBen Skeggs 	unsigned long flags;
109344c2d42SBen Skeggs 	spin_lock_irqsave(&fifo->lock, flags);
1108f0649b5SBen Skeggs 	list_for_each_entry(chan, &fifo->chan, head) {
1118f0649b5SBen Skeggs 		if (chan->chid == chid) {
1128f0649b5SBen Skeggs 			list_del(&chan->head);
1138f0649b5SBen Skeggs 			list_add(&chan->head, &fifo->chan);
114344c2d42SBen Skeggs 			*rflags = flags;
1158f0649b5SBen Skeggs 			return chan;
1168f0649b5SBen Skeggs 		}
117344c2d42SBen Skeggs 	}
118344c2d42SBen Skeggs 	spin_unlock_irqrestore(&fifo->lock, flags);
119344c2d42SBen Skeggs 	return NULL;
120344c2d42SBen Skeggs }
121344c2d42SBen Skeggs 
122ff9f29abSBen Skeggs void
123ff9f29abSBen Skeggs nvkm_fifo_kevent(struct nvkm_fifo *fifo, int chid)
124ff9f29abSBen Skeggs {
12599d0701aSBen Skeggs 	nvkm_event_ntfy(&fifo->kevent, chid, NVKM_FIFO_EVENT_KILLED);
126ff9f29abSBen Skeggs }
127ff9f29abSBen Skeggs 
128ff9f29abSBen Skeggs static const struct nvkm_event_func
129ff9f29abSBen Skeggs nvkm_fifo_kevent_func = {
130ff9f29abSBen Skeggs };
131ff9f29abSBen Skeggs 
13213de7f46SBen Skeggs static void
13313de7f46SBen Skeggs nvkm_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
13413de7f46SBen Skeggs {
13513de7f46SBen Skeggs 	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
13613de7f46SBen Skeggs 	fifo->func->uevent_fini(fifo);
13713de7f46SBen Skeggs }
13813de7f46SBen Skeggs 
13913de7f46SBen Skeggs static void
14013de7f46SBen Skeggs nvkm_fifo_uevent_init(struct nvkm_event *event, int type, int index)
14113de7f46SBen Skeggs {
14213de7f46SBen Skeggs 	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
14313de7f46SBen Skeggs 	fifo->func->uevent_init(fifo);
14413de7f46SBen Skeggs }
14513de7f46SBen Skeggs 
14613de7f46SBen Skeggs static const struct nvkm_event_func
14713de7f46SBen Skeggs nvkm_fifo_uevent_func = {
14813de7f46SBen Skeggs 	.init = nvkm_fifo_uevent_init,
14913de7f46SBen Skeggs 	.fini = nvkm_fifo_uevent_fini,
15013de7f46SBen Skeggs };
15113de7f46SBen Skeggs 
1529a65a38cSBen Skeggs void
1539a65a38cSBen Skeggs nvkm_fifo_uevent(struct nvkm_fifo *fifo)
1549a65a38cSBen Skeggs {
15599d0701aSBen Skeggs 	nvkm_event_ntfy(&fifo->uevent, 0, NVKM_FIFO_EVENT_NON_STALL_INTR);
1569a65a38cSBen Skeggs }
1579a65a38cSBen Skeggs 
1588f0649b5SBen Skeggs static int
159f5e45689SBen Skeggs nvkm_fifo_class_new(struct nvkm_device *device, const struct nvkm_oclass *oclass,
160f5e45689SBen Skeggs 		    void *argv, u32 argc, struct nvkm_object **pobject)
161f9360c3aSBen Skeggs {
162f9360c3aSBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
163f9360c3aSBen Skeggs 
164f5e45689SBen Skeggs 	if (oclass->engn == &fifo->func->chan.user)
165f5e45689SBen Skeggs 		return nvkm_uchan_new(fifo, NULL, oclass, argv, argc, pobject);
166f9360c3aSBen Skeggs 
167f5e45689SBen Skeggs 	WARN_ON(1);
168f5e45689SBen Skeggs 	return -ENOSYS;
1698f0649b5SBen Skeggs }
1708f0649b5SBen Skeggs 
1718f0649b5SBen Skeggs static const struct nvkm_device_oclass
1728f0649b5SBen Skeggs nvkm_fifo_class = {
1738f0649b5SBen Skeggs 	.ctor = nvkm_fifo_class_new,
1748f0649b5SBen Skeggs };
1758f0649b5SBen Skeggs 
1768f0649b5SBen Skeggs static int
177f5e45689SBen Skeggs nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index, const struct nvkm_device_oclass **class)
1788f0649b5SBen Skeggs {
1798f0649b5SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
180f5e45689SBen Skeggs 	const struct nvkm_fifo_func_chan *chan = &fifo->func->chan;
1818f0649b5SBen Skeggs 	int c = 0;
1828f0649b5SBen Skeggs 
183f5e45689SBen Skeggs 	/* *_CHANNEL_DMA, *_CHANNEL_GPFIFO_* */
184f5e45689SBen Skeggs 	if (chan->user.oclass) {
1858f0649b5SBen Skeggs 		if (c++ == index) {
186f5e45689SBen Skeggs 			oclass->base = chan->user;
187f5e45689SBen Skeggs 			oclass->engn = &fifo->func->chan.user;
1888f0649b5SBen Skeggs 			*class = &nvkm_fifo_class;
1898f0649b5SBen Skeggs 			return 0;
1908f0649b5SBen Skeggs 		}
1918f0649b5SBen Skeggs 	}
1928f0649b5SBen Skeggs 
1938f0649b5SBen Skeggs 	return c;
1948f0649b5SBen Skeggs }
1958f0649b5SBen Skeggs 
19613de7f46SBen Skeggs static void
19713de7f46SBen Skeggs nvkm_fifo_intr(struct nvkm_engine *engine)
198c39f472eSBen Skeggs {
19913de7f46SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
20013de7f46SBen Skeggs 	fifo->func->intr(fifo);
20113de7f46SBen Skeggs }
20213de7f46SBen Skeggs 
20313de7f46SBen Skeggs static int
20413de7f46SBen Skeggs nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend)
20513de7f46SBen Skeggs {
20613de7f46SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
20713de7f46SBen Skeggs 	if (fifo->func->fini)
20813de7f46SBen Skeggs 		fifo->func->fini(fifo);
20913de7f46SBen Skeggs 	return 0;
21013de7f46SBen Skeggs }
21113de7f46SBen Skeggs 
21213de7f46SBen Skeggs static int
213fd67738aSBen Skeggs nvkm_fifo_init(struct nvkm_engine *engine)
214fd67738aSBen Skeggs {
215fd67738aSBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
216fd67738aSBen Skeggs 	fifo->func->init(fifo);
217fd67738aSBen Skeggs 	return 0;
218fd67738aSBen Skeggs }
219fd67738aSBen Skeggs 
220fd67738aSBen Skeggs static int
221eb47db4fSBen Skeggs nvkm_fifo_info(struct nvkm_engine *engine, u64 mthd, u64 *data)
222eb47db4fSBen Skeggs {
223eb47db4fSBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
224800ac1f8SBen Skeggs 
225eb47db4fSBen Skeggs 	switch (mthd) {
226800ac1f8SBen Skeggs 	case NV_DEVICE_HOST_CHANNELS: *data = fifo->chid ? fifo->chid->nr : 0; return 0;
227eb47db4fSBen Skeggs 	default:
228cc362050SBen Skeggs 		if (fifo->func->info)
229cc362050SBen Skeggs 			return fifo->func->info(fifo, mthd, data);
230eb47db4fSBen Skeggs 		break;
231eb47db4fSBen Skeggs 	}
232800ac1f8SBen Skeggs 
233eb47db4fSBen Skeggs 	return -ENOSYS;
234eb47db4fSBen Skeggs }
235eb47db4fSBen Skeggs 
236eb47db4fSBen Skeggs static int
23713de7f46SBen Skeggs nvkm_fifo_oneinit(struct nvkm_engine *engine)
23813de7f46SBen Skeggs {
23913de7f46SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
240*d94470e9SBen Skeggs 	struct nvkm_runl *runl;
241*d94470e9SBen Skeggs 	struct nvkm_engn *engn;
2421c488ba9SBen Skeggs 	int ret, nr, i;
243800ac1f8SBen Skeggs 
244800ac1f8SBen Skeggs 	/* Initialise CHID/CGID allocator(s) on GPUs where they aren't per-runlist. */
245800ac1f8SBen Skeggs 	if (fifo->func->chid_nr) {
246800ac1f8SBen Skeggs 		ret = fifo->func->chid_ctor(fifo, fifo->func->chid_nr(fifo));
247800ac1f8SBen Skeggs 		if (ret)
248800ac1f8SBen Skeggs 			return ret;
249800ac1f8SBen Skeggs 	}
250800ac1f8SBen Skeggs 
2511c488ba9SBen Skeggs 	/* Create runqueues for each PBDMA. */
2521c488ba9SBen Skeggs 	if (fifo->func->runq_nr) {
2531c488ba9SBen Skeggs 		for (nr = fifo->func->runq_nr(fifo), i = 0; i < nr; i++) {
2541c488ba9SBen Skeggs 			if (!nvkm_runq_new(fifo, i))
2551c488ba9SBen Skeggs 				return -ENOMEM;
2561c488ba9SBen Skeggs 		}
2571c488ba9SBen Skeggs 	}
2581c488ba9SBen Skeggs 
259*d94470e9SBen Skeggs 	/* Create runlists. */
260*d94470e9SBen Skeggs 	ret = fifo->func->runl_ctor(fifo);
261*d94470e9SBen Skeggs 	if (ret)
262*d94470e9SBen Skeggs 		return ret;
263*d94470e9SBen Skeggs 
264*d94470e9SBen Skeggs 	nvkm_runl_foreach(runl, fifo) {
265*d94470e9SBen Skeggs 		RUNL_DEBUG(runl, "");
266*d94470e9SBen Skeggs 		nvkm_runl_foreach_engn(engn, runl) {
267*d94470e9SBen Skeggs 			ENGN_DEBUG(engn, "");
268*d94470e9SBen Skeggs 		}
269*d94470e9SBen Skeggs 	}
270*d94470e9SBen Skeggs 
27113de7f46SBen Skeggs 	if (fifo->func->oneinit)
27213de7f46SBen Skeggs 		return fifo->func->oneinit(fifo);
273800ac1f8SBen Skeggs 
27413de7f46SBen Skeggs 	return 0;
27513de7f46SBen Skeggs }
27613de7f46SBen Skeggs 
2775e721ad1SBen Skeggs static void
2785e721ad1SBen Skeggs nvkm_fifo_preinit(struct nvkm_engine *engine)
2795e721ad1SBen Skeggs {
2806997ea13SBen Skeggs 	nvkm_mc_reset(engine->subdev.device, NVKM_ENGINE_FIFO, 0);
2815e721ad1SBen Skeggs }
2825e721ad1SBen Skeggs 
28313de7f46SBen Skeggs static void *
28413de7f46SBen Skeggs nvkm_fifo_dtor(struct nvkm_engine *engine)
28513de7f46SBen Skeggs {
28613de7f46SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
287*d94470e9SBen Skeggs 	struct nvkm_runl *runl, *runt;
2881c488ba9SBen Skeggs 	struct nvkm_runq *runq, *rtmp;
28913de7f46SBen Skeggs 	void *data = fifo;
290800ac1f8SBen Skeggs 
291*d94470e9SBen Skeggs 	list_for_each_entry_safe(runl, runt, &fifo->runls, head)
292*d94470e9SBen Skeggs 		nvkm_runl_del(runl);
2931c488ba9SBen Skeggs 	list_for_each_entry_safe(runq, rtmp, &fifo->runqs, head)
2941c488ba9SBen Skeggs 		nvkm_runq_del(runq);
2951c488ba9SBen Skeggs 
296800ac1f8SBen Skeggs 	nvkm_chid_unref(&fifo->cgid);
297800ac1f8SBen Skeggs 	nvkm_chid_unref(&fifo->chid);
298800ac1f8SBen Skeggs 
29913de7f46SBen Skeggs 	if (fifo->func->dtor)
30013de7f46SBen Skeggs 		data = fifo->func->dtor(fifo);
301ff9f29abSBen Skeggs 	nvkm_event_fini(&fifo->kevent);
30213de7f46SBen Skeggs 	nvkm_event_fini(&fifo->uevent);
303a6419360SBen Skeggs 	mutex_destroy(&fifo->mutex);
30413de7f46SBen Skeggs 	return data;
305c39f472eSBen Skeggs }
306c39f472eSBen Skeggs 
3078f0649b5SBen Skeggs static const struct nvkm_engine_func
30813de7f46SBen Skeggs nvkm_fifo = {
30913de7f46SBen Skeggs 	.dtor = nvkm_fifo_dtor,
3105e721ad1SBen Skeggs 	.preinit = nvkm_fifo_preinit,
31113de7f46SBen Skeggs 	.oneinit = nvkm_fifo_oneinit,
312eb47db4fSBen Skeggs 	.info = nvkm_fifo_info,
31313de7f46SBen Skeggs 	.init = nvkm_fifo_init,
31413de7f46SBen Skeggs 	.fini = nvkm_fifo_fini,
31513de7f46SBen Skeggs 	.intr = nvkm_fifo_intr,
3168f0649b5SBen Skeggs 	.base.sclass = nvkm_fifo_class_get,
3178f0649b5SBen Skeggs };
3188f0649b5SBen Skeggs 
319c39f472eSBen Skeggs int
32013de7f46SBen Skeggs nvkm_fifo_ctor(const struct nvkm_fifo_func *func, struct nvkm_device *device,
3218c18138cSBen Skeggs 	       enum nvkm_subdev_type type, int inst, struct nvkm_fifo *fifo)
322c39f472eSBen Skeggs {
3238c18138cSBen Skeggs 	int ret, nr;
324c39f472eSBen Skeggs 
32513de7f46SBen Skeggs 	fifo->func = func;
3261c488ba9SBen Skeggs 	INIT_LIST_HEAD(&fifo->runqs);
327*d94470e9SBen Skeggs 	INIT_LIST_HEAD(&fifo->runls);
32813de7f46SBen Skeggs 	spin_lock_init(&fifo->lock);
329a6419360SBen Skeggs 	mutex_init(&fifo->mutex);
3308f0649b5SBen Skeggs 
3318c18138cSBen Skeggs 	ret = nvkm_engine_ctor(&nvkm_fifo, device, type, inst, true, &fifo->engine);
3328c18138cSBen Skeggs 	if (ret)
3338c18138cSBen Skeggs 		return ret;
3348c18138cSBen Skeggs 
3358c18138cSBen Skeggs 	INIT_LIST_HEAD(&fifo->chan);
3368c18138cSBen Skeggs 
3379be9c606SBen Skeggs 	nr = func->chid_nr(fifo);
33813de7f46SBen Skeggs 	if (WARN_ON(fifo->nr > NVKM_FIFO_CHID_NR))
3398f0649b5SBen Skeggs 		fifo->nr = NVKM_FIFO_CHID_NR;
34013de7f46SBen Skeggs 	else
34113de7f46SBen Skeggs 		fifo->nr = nr;
342c39f472eSBen Skeggs 
34313de7f46SBen Skeggs 	if (func->uevent_init) {
344f43e47c0SBen Skeggs 		ret = nvkm_event_init(&nvkm_fifo_uevent_func, &fifo->engine.subdev, 1, 1,
34513de7f46SBen Skeggs 				      &fifo->uevent);
34613de7f46SBen Skeggs 		if (ret)
34713de7f46SBen Skeggs 			return ret;
34813de7f46SBen Skeggs 	}
34913de7f46SBen Skeggs 
350f43e47c0SBen Skeggs 	return nvkm_event_init(&nvkm_fifo_kevent_func, &fifo->engine.subdev, 1, nr, &fifo->kevent);
351c39f472eSBen Skeggs }
352