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"
26c39f472eSBen Skeggs 
2713de7f46SBen Skeggs #include <core/gpuobj.h>
285e721ad1SBen Skeggs #include <subdev/mc.h>
2905c7145dSBen Skeggs 
30eb47db4fSBen Skeggs #include <nvif/cl0080.h>
3105c7145dSBen Skeggs #include <nvif/unpack.h>
32c39f472eSBen Skeggs 
33344c2d42SBen Skeggs void
3421e6de29SBen Skeggs nvkm_fifo_recover_chan(struct nvkm_fifo *fifo, int chid)
3521e6de29SBen Skeggs {
3621e6de29SBen Skeggs 	unsigned long flags;
3721e6de29SBen Skeggs 	if (WARN_ON(!fifo->func->recover_chan))
3821e6de29SBen Skeggs 		return;
3921e6de29SBen Skeggs 	spin_lock_irqsave(&fifo->lock, flags);
4021e6de29SBen Skeggs 	fifo->func->recover_chan(fifo, chid);
4121e6de29SBen Skeggs 	spin_unlock_irqrestore(&fifo->lock, flags);
4221e6de29SBen Skeggs }
4321e6de29SBen Skeggs 
4421e6de29SBen Skeggs void
4513de7f46SBen Skeggs nvkm_fifo_pause(struct nvkm_fifo *fifo, unsigned long *flags)
4613de7f46SBen Skeggs {
4713de7f46SBen Skeggs 	return fifo->func->pause(fifo, flags);
4813de7f46SBen Skeggs }
4913de7f46SBen Skeggs 
5013de7f46SBen Skeggs void
5113de7f46SBen Skeggs nvkm_fifo_start(struct nvkm_fifo *fifo, unsigned long *flags)
5213de7f46SBen Skeggs {
5313de7f46SBen Skeggs 	return fifo->func->start(fifo, flags);
5413de7f46SBen Skeggs }
5513de7f46SBen Skeggs 
5613de7f46SBen Skeggs void
57ddc669e2SBen Skeggs nvkm_fifo_fault(struct nvkm_fifo *fifo, struct nvkm_fault_data *info)
58ddc669e2SBen Skeggs {
59*9be9c606SBen Skeggs 	return fifo->func->mmu_fault->recover(fifo, info);
60ddc669e2SBen Skeggs }
61ddc669e2SBen Skeggs 
62ddc669e2SBen Skeggs void
63344c2d42SBen Skeggs nvkm_fifo_chan_put(struct nvkm_fifo *fifo, unsigned long flags,
64344c2d42SBen Skeggs 		   struct nvkm_fifo_chan **pchan)
65344c2d42SBen Skeggs {
66344c2d42SBen Skeggs 	struct nvkm_fifo_chan *chan = *pchan;
67344c2d42SBen Skeggs 	if (likely(chan)) {
68344c2d42SBen Skeggs 		*pchan = NULL;
69344c2d42SBen Skeggs 		spin_unlock_irqrestore(&fifo->lock, flags);
70344c2d42SBen Skeggs 	}
71344c2d42SBen Skeggs }
72344c2d42SBen Skeggs 
73344c2d42SBen Skeggs struct nvkm_fifo_chan *
743534821dSBen Skeggs nvkm_fifo_chan_inst_locked(struct nvkm_fifo *fifo, u64 inst)
753534821dSBen Skeggs {
763534821dSBen Skeggs 	struct nvkm_fifo_chan *chan;
773534821dSBen Skeggs 	list_for_each_entry(chan, &fifo->chan, head) {
783534821dSBen Skeggs 		if (chan->inst->addr == inst) {
793534821dSBen Skeggs 			list_del(&chan->head);
803534821dSBen Skeggs 			list_add(&chan->head, &fifo->chan);
813534821dSBen Skeggs 			return chan;
823534821dSBen Skeggs 		}
833534821dSBen Skeggs 	}
843534821dSBen Skeggs 	return NULL;
853534821dSBen Skeggs }
863534821dSBen Skeggs 
873534821dSBen Skeggs struct nvkm_fifo_chan *
88344c2d42SBen Skeggs nvkm_fifo_chan_inst(struct nvkm_fifo *fifo, u64 inst, unsigned long *rflags)
89344c2d42SBen Skeggs {
908f0649b5SBen Skeggs 	struct nvkm_fifo_chan *chan;
91344c2d42SBen Skeggs 	unsigned long flags;
92344c2d42SBen Skeggs 	spin_lock_irqsave(&fifo->lock, flags);
933534821dSBen Skeggs 	if ((chan = nvkm_fifo_chan_inst_locked(fifo, inst))) {
94344c2d42SBen Skeggs 		*rflags = flags;
95344c2d42SBen Skeggs 		return chan;
96344c2d42SBen Skeggs 	}
97344c2d42SBen Skeggs 	spin_unlock_irqrestore(&fifo->lock, flags);
98344c2d42SBen Skeggs 	return NULL;
99344c2d42SBen Skeggs }
100344c2d42SBen Skeggs 
101344c2d42SBen Skeggs struct nvkm_fifo_chan *
102344c2d42SBen Skeggs nvkm_fifo_chan_chid(struct nvkm_fifo *fifo, int chid, unsigned long *rflags)
103344c2d42SBen Skeggs {
1048f0649b5SBen Skeggs 	struct nvkm_fifo_chan *chan;
105344c2d42SBen Skeggs 	unsigned long flags;
106344c2d42SBen Skeggs 	spin_lock_irqsave(&fifo->lock, flags);
1078f0649b5SBen Skeggs 	list_for_each_entry(chan, &fifo->chan, head) {
1088f0649b5SBen Skeggs 		if (chan->chid == chid) {
1098f0649b5SBen Skeggs 			list_del(&chan->head);
1108f0649b5SBen Skeggs 			list_add(&chan->head, &fifo->chan);
111344c2d42SBen Skeggs 			*rflags = flags;
1128f0649b5SBen Skeggs 			return chan;
1138f0649b5SBen Skeggs 		}
114344c2d42SBen Skeggs 	}
115344c2d42SBen Skeggs 	spin_unlock_irqrestore(&fifo->lock, flags);
116344c2d42SBen Skeggs 	return NULL;
117344c2d42SBen Skeggs }
118344c2d42SBen Skeggs 
119ff9f29abSBen Skeggs void
120ff9f29abSBen Skeggs nvkm_fifo_kevent(struct nvkm_fifo *fifo, int chid)
121ff9f29abSBen Skeggs {
12299d0701aSBen Skeggs 	nvkm_event_ntfy(&fifo->kevent, chid, NVKM_FIFO_EVENT_KILLED);
123ff9f29abSBen Skeggs }
124ff9f29abSBen Skeggs 
125ff9f29abSBen Skeggs static const struct nvkm_event_func
126ff9f29abSBen Skeggs nvkm_fifo_kevent_func = {
127ff9f29abSBen Skeggs };
128ff9f29abSBen Skeggs 
12913de7f46SBen Skeggs static void
13013de7f46SBen Skeggs nvkm_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
13113de7f46SBen Skeggs {
13213de7f46SBen Skeggs 	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
13313de7f46SBen Skeggs 	fifo->func->uevent_fini(fifo);
13413de7f46SBen Skeggs }
13513de7f46SBen Skeggs 
13613de7f46SBen Skeggs static void
13713de7f46SBen Skeggs nvkm_fifo_uevent_init(struct nvkm_event *event, int type, int index)
13813de7f46SBen Skeggs {
13913de7f46SBen Skeggs 	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
14013de7f46SBen Skeggs 	fifo->func->uevent_init(fifo);
14113de7f46SBen Skeggs }
14213de7f46SBen Skeggs 
14313de7f46SBen Skeggs static const struct nvkm_event_func
14413de7f46SBen Skeggs nvkm_fifo_uevent_func = {
14513de7f46SBen Skeggs 	.init = nvkm_fifo_uevent_init,
14613de7f46SBen Skeggs 	.fini = nvkm_fifo_uevent_fini,
14713de7f46SBen Skeggs };
14813de7f46SBen Skeggs 
1499a65a38cSBen Skeggs void
1509a65a38cSBen Skeggs nvkm_fifo_uevent(struct nvkm_fifo *fifo)
1519a65a38cSBen Skeggs {
15299d0701aSBen Skeggs 	nvkm_event_ntfy(&fifo->uevent, 0, NVKM_FIFO_EVENT_NON_STALL_INTR);
1539a65a38cSBen Skeggs }
1549a65a38cSBen Skeggs 
1558f0649b5SBen Skeggs static int
156f5e45689SBen Skeggs nvkm_fifo_class_new(struct nvkm_device *device, const struct nvkm_oclass *oclass,
157f5e45689SBen Skeggs 		    void *argv, u32 argc, struct nvkm_object **pobject)
158f9360c3aSBen Skeggs {
159f9360c3aSBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
160f9360c3aSBen Skeggs 
161f5e45689SBen Skeggs 	if (oclass->engn == &fifo->func->chan.user)
162f5e45689SBen Skeggs 		return nvkm_uchan_new(fifo, NULL, oclass, argv, argc, pobject);
163f9360c3aSBen Skeggs 
164f5e45689SBen Skeggs 	WARN_ON(1);
165f5e45689SBen Skeggs 	return -ENOSYS;
1668f0649b5SBen Skeggs }
1678f0649b5SBen Skeggs 
1688f0649b5SBen Skeggs static const struct nvkm_device_oclass
1698f0649b5SBen Skeggs nvkm_fifo_class = {
1708f0649b5SBen Skeggs 	.ctor = nvkm_fifo_class_new,
1718f0649b5SBen Skeggs };
1728f0649b5SBen Skeggs 
1738f0649b5SBen Skeggs static int
174f5e45689SBen Skeggs nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index, const struct nvkm_device_oclass **class)
1758f0649b5SBen Skeggs {
1768f0649b5SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
177f5e45689SBen Skeggs 	const struct nvkm_fifo_func_chan *chan = &fifo->func->chan;
1788f0649b5SBen Skeggs 	int c = 0;
1798f0649b5SBen Skeggs 
180f5e45689SBen Skeggs 	/* *_CHANNEL_DMA, *_CHANNEL_GPFIFO_* */
181f5e45689SBen Skeggs 	if (chan->user.oclass) {
1828f0649b5SBen Skeggs 		if (c++ == index) {
183f5e45689SBen Skeggs 			oclass->base = chan->user;
184f5e45689SBen Skeggs 			oclass->engn = &fifo->func->chan.user;
1858f0649b5SBen Skeggs 			*class = &nvkm_fifo_class;
1868f0649b5SBen Skeggs 			return 0;
1878f0649b5SBen Skeggs 		}
1888f0649b5SBen Skeggs 	}
1898f0649b5SBen Skeggs 
1908f0649b5SBen Skeggs 	return c;
1918f0649b5SBen Skeggs }
1928f0649b5SBen Skeggs 
19313de7f46SBen Skeggs static void
19413de7f46SBen Skeggs nvkm_fifo_intr(struct nvkm_engine *engine)
195c39f472eSBen Skeggs {
19613de7f46SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
19713de7f46SBen Skeggs 	fifo->func->intr(fifo);
19813de7f46SBen Skeggs }
19913de7f46SBen Skeggs 
20013de7f46SBen Skeggs static int
20113de7f46SBen Skeggs nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend)
20213de7f46SBen Skeggs {
20313de7f46SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
20413de7f46SBen Skeggs 	if (fifo->func->fini)
20513de7f46SBen Skeggs 		fifo->func->fini(fifo);
20613de7f46SBen Skeggs 	return 0;
20713de7f46SBen Skeggs }
20813de7f46SBen Skeggs 
20913de7f46SBen Skeggs static int
210fd67738aSBen Skeggs nvkm_fifo_init(struct nvkm_engine *engine)
211fd67738aSBen Skeggs {
212fd67738aSBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
213fd67738aSBen Skeggs 	fifo->func->init(fifo);
214fd67738aSBen Skeggs 	return 0;
215fd67738aSBen Skeggs }
216fd67738aSBen Skeggs 
217fd67738aSBen Skeggs static int
218eb47db4fSBen Skeggs nvkm_fifo_info(struct nvkm_engine *engine, u64 mthd, u64 *data)
219eb47db4fSBen Skeggs {
220eb47db4fSBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
221eb47db4fSBen Skeggs 	switch (mthd) {
222f8fabd31SBen Skeggs 	case NV_DEVICE_HOST_CHANNELS: *data = fifo->nr; return 0;
223eb47db4fSBen Skeggs 	default:
224cc362050SBen Skeggs 		if (fifo->func->info)
225cc362050SBen Skeggs 			return fifo->func->info(fifo, mthd, data);
226eb47db4fSBen Skeggs 		break;
227eb47db4fSBen Skeggs 	}
228eb47db4fSBen Skeggs 	return -ENOSYS;
229eb47db4fSBen Skeggs }
230eb47db4fSBen Skeggs 
231eb47db4fSBen Skeggs static int
23213de7f46SBen Skeggs nvkm_fifo_oneinit(struct nvkm_engine *engine)
23313de7f46SBen Skeggs {
23413de7f46SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
23513de7f46SBen Skeggs 	if (fifo->func->oneinit)
23613de7f46SBen Skeggs 		return fifo->func->oneinit(fifo);
23713de7f46SBen Skeggs 	return 0;
23813de7f46SBen Skeggs }
23913de7f46SBen Skeggs 
2405e721ad1SBen Skeggs static void
2415e721ad1SBen Skeggs nvkm_fifo_preinit(struct nvkm_engine *engine)
2425e721ad1SBen Skeggs {
2436997ea13SBen Skeggs 	nvkm_mc_reset(engine->subdev.device, NVKM_ENGINE_FIFO, 0);
2445e721ad1SBen Skeggs }
2455e721ad1SBen Skeggs 
24613de7f46SBen Skeggs static void *
24713de7f46SBen Skeggs nvkm_fifo_dtor(struct nvkm_engine *engine)
24813de7f46SBen Skeggs {
24913de7f46SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
25013de7f46SBen Skeggs 	void *data = fifo;
25113de7f46SBen Skeggs 	if (fifo->func->dtor)
25213de7f46SBen Skeggs 		data = fifo->func->dtor(fifo);
253ff9f29abSBen Skeggs 	nvkm_event_fini(&fifo->kevent);
25413de7f46SBen Skeggs 	nvkm_event_fini(&fifo->uevent);
255a6419360SBen Skeggs 	mutex_destroy(&fifo->mutex);
25613de7f46SBen Skeggs 	return data;
257c39f472eSBen Skeggs }
258c39f472eSBen Skeggs 
2598f0649b5SBen Skeggs static const struct nvkm_engine_func
26013de7f46SBen Skeggs nvkm_fifo = {
26113de7f46SBen Skeggs 	.dtor = nvkm_fifo_dtor,
2625e721ad1SBen Skeggs 	.preinit = nvkm_fifo_preinit,
26313de7f46SBen Skeggs 	.oneinit = nvkm_fifo_oneinit,
264eb47db4fSBen Skeggs 	.info = nvkm_fifo_info,
26513de7f46SBen Skeggs 	.init = nvkm_fifo_init,
26613de7f46SBen Skeggs 	.fini = nvkm_fifo_fini,
26713de7f46SBen Skeggs 	.intr = nvkm_fifo_intr,
2688f0649b5SBen Skeggs 	.base.sclass = nvkm_fifo_class_get,
2698f0649b5SBen Skeggs };
2708f0649b5SBen Skeggs 
271c39f472eSBen Skeggs int
27213de7f46SBen Skeggs nvkm_fifo_ctor(const struct nvkm_fifo_func *func, struct nvkm_device *device,
2738c18138cSBen Skeggs 	       enum nvkm_subdev_type type, int inst, struct nvkm_fifo *fifo)
274c39f472eSBen Skeggs {
2758c18138cSBen Skeggs 	int ret, nr;
276c39f472eSBen Skeggs 
27713de7f46SBen Skeggs 	fifo->func = func;
27813de7f46SBen Skeggs 	spin_lock_init(&fifo->lock);
279a6419360SBen Skeggs 	mutex_init(&fifo->mutex);
2808f0649b5SBen Skeggs 
2818c18138cSBen Skeggs 	ret = nvkm_engine_ctor(&nvkm_fifo, device, type, inst, true, &fifo->engine);
2828c18138cSBen Skeggs 	if (ret)
2838c18138cSBen Skeggs 		return ret;
2848c18138cSBen Skeggs 
2858c18138cSBen Skeggs 	INIT_LIST_HEAD(&fifo->chan);
2868c18138cSBen Skeggs 
287*9be9c606SBen Skeggs 	nr = func->chid_nr(fifo);
28813de7f46SBen Skeggs 	if (WARN_ON(fifo->nr > NVKM_FIFO_CHID_NR))
2898f0649b5SBen Skeggs 		fifo->nr = NVKM_FIFO_CHID_NR;
29013de7f46SBen Skeggs 	else
29113de7f46SBen Skeggs 		fifo->nr = nr;
29213de7f46SBen Skeggs 	bitmap_clear(fifo->mask, 0, fifo->nr);
293c39f472eSBen Skeggs 
29413de7f46SBen Skeggs 	if (func->uevent_init) {
295f43e47c0SBen Skeggs 		ret = nvkm_event_init(&nvkm_fifo_uevent_func, &fifo->engine.subdev, 1, 1,
29613de7f46SBen Skeggs 				      &fifo->uevent);
29713de7f46SBen Skeggs 		if (ret)
29813de7f46SBen Skeggs 			return ret;
29913de7f46SBen Skeggs 	}
30013de7f46SBen Skeggs 
301f43e47c0SBen Skeggs 	return nvkm_event_init(&nvkm_fifo_kevent_func, &fifo->engine.subdev, 1, nr, &fifo->kevent);
302c39f472eSBen Skeggs }
303