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"
27d94470e9SBen Skeggs #include "runl.h"
281c488ba9SBen Skeggs #include "runq.h"
29c39f472eSBen Skeggs 
3013de7f46SBen Skeggs #include <core/gpuobj.h>
31fbe9f433SBen Skeggs #include <subdev/bar.h>
325e721ad1SBen Skeggs #include <subdev/mc.h>
33fbe9f433SBen Skeggs #include <subdev/mmu.h>
3405c7145dSBen Skeggs 
35eb47db4fSBen Skeggs #include <nvif/cl0080.h>
3605c7145dSBen Skeggs #include <nvif/unpack.h>
37c39f472eSBen Skeggs 
380ceceaa9SBen Skeggs bool
nvkm_fifo_ctxsw_in_progress(struct nvkm_engine * engine)390ceceaa9SBen Skeggs nvkm_fifo_ctxsw_in_progress(struct nvkm_engine *engine)
400ceceaa9SBen Skeggs {
410ceceaa9SBen Skeggs 	struct nvkm_runl *runl;
420ceceaa9SBen Skeggs 	struct nvkm_engn *engn;
430ceceaa9SBen Skeggs 
440ceceaa9SBen Skeggs 	nvkm_runl_foreach(runl, engine->subdev.device->fifo) {
450ceceaa9SBen Skeggs 		nvkm_runl_foreach_engn(engn, runl) {
460ceceaa9SBen Skeggs 			if (engn->engine == engine)
470ceceaa9SBen Skeggs 				return engn->func->chsw ? engn->func->chsw(engn) : false;
480ceceaa9SBen Skeggs 		}
490ceceaa9SBen Skeggs 	}
500ceceaa9SBen Skeggs 
510ceceaa9SBen Skeggs 	return false;
520ceceaa9SBen Skeggs }
530ceceaa9SBen Skeggs 
54344c2d42SBen Skeggs void
nvkm_fifo_pause(struct nvkm_fifo * fifo,unsigned long * flags)5513de7f46SBen Skeggs nvkm_fifo_pause(struct nvkm_fifo *fifo, unsigned long *flags)
5613de7f46SBen Skeggs {
5713de7f46SBen Skeggs 	return fifo->func->pause(fifo, flags);
5813de7f46SBen Skeggs }
5913de7f46SBen Skeggs 
6013de7f46SBen Skeggs void
nvkm_fifo_start(struct nvkm_fifo * fifo,unsigned long * flags)6113de7f46SBen Skeggs nvkm_fifo_start(struct nvkm_fifo *fifo, unsigned long *flags)
6213de7f46SBen Skeggs {
6313de7f46SBen Skeggs 	return fifo->func->start(fifo, flags);
6413de7f46SBen Skeggs }
6513de7f46SBen Skeggs 
6613de7f46SBen Skeggs void
nvkm_fifo_fault(struct nvkm_fifo * fifo,struct nvkm_fault_data * info)67ddc669e2SBen Skeggs nvkm_fifo_fault(struct nvkm_fifo *fifo, struct nvkm_fault_data *info)
68ddc669e2SBen Skeggs {
699be9c606SBen Skeggs 	return fifo->func->mmu_fault->recover(fifo, info);
70ddc669e2SBen Skeggs }
71ddc669e2SBen Skeggs 
728f0649b5SBen Skeggs static int
nvkm_fifo_class_new(struct nvkm_device * device,const struct nvkm_oclass * oclass,void * argv,u32 argc,struct nvkm_object ** pobject)73f5e45689SBen Skeggs nvkm_fifo_class_new(struct nvkm_device *device, const struct nvkm_oclass *oclass,
74f5e45689SBen Skeggs 		    void *argv, u32 argc, struct nvkm_object **pobject)
75f9360c3aSBen Skeggs {
76f9360c3aSBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
77f9360c3aSBen Skeggs 
7806db7fdeSBen Skeggs 	if (oclass->engn == &fifo->func->cgrp.user)
7906db7fdeSBen Skeggs 		return nvkm_ucgrp_new(fifo, oclass, argv, argc, pobject);
8006db7fdeSBen Skeggs 
81f5e45689SBen Skeggs 	if (oclass->engn == &fifo->func->chan.user)
82f5e45689SBen Skeggs 		return nvkm_uchan_new(fifo, NULL, oclass, argv, argc, pobject);
83f9360c3aSBen Skeggs 
84f5e45689SBen Skeggs 	WARN_ON(1);
85f5e45689SBen Skeggs 	return -ENOSYS;
868f0649b5SBen Skeggs }
878f0649b5SBen Skeggs 
888f0649b5SBen Skeggs static const struct nvkm_device_oclass
898f0649b5SBen Skeggs nvkm_fifo_class = {
908f0649b5SBen Skeggs 	.ctor = nvkm_fifo_class_new,
918f0649b5SBen Skeggs };
928f0649b5SBen Skeggs 
938f0649b5SBen Skeggs static int
nvkm_fifo_class_get(struct nvkm_oclass * oclass,int index,const struct nvkm_device_oclass ** class)94f5e45689SBen Skeggs nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index, const struct nvkm_device_oclass **class)
958f0649b5SBen Skeggs {
968f0649b5SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
9706db7fdeSBen Skeggs 	const struct nvkm_fifo_func_cgrp *cgrp = &fifo->func->cgrp;
98f5e45689SBen Skeggs 	const struct nvkm_fifo_func_chan *chan = &fifo->func->chan;
998f0649b5SBen Skeggs 	int c = 0;
1008f0649b5SBen Skeggs 
10106db7fdeSBen Skeggs 	/* *_CHANNEL_GROUP_* */
10206db7fdeSBen Skeggs 	if (cgrp->user.oclass) {
10306db7fdeSBen Skeggs 		if (c++ == index) {
10406db7fdeSBen Skeggs 			oclass->base = cgrp->user;
10506db7fdeSBen Skeggs 			oclass->engn = &fifo->func->cgrp.user;
10606db7fdeSBen Skeggs 			*class = &nvkm_fifo_class;
10706db7fdeSBen Skeggs 			return 0;
10806db7fdeSBen Skeggs 		}
10906db7fdeSBen Skeggs 	}
11006db7fdeSBen Skeggs 
111f5e45689SBen Skeggs 	/* *_CHANNEL_DMA, *_CHANNEL_GPFIFO_* */
112f5e45689SBen Skeggs 	if (chan->user.oclass) {
1138f0649b5SBen Skeggs 		if (c++ == index) {
114f5e45689SBen Skeggs 			oclass->base = chan->user;
115f5e45689SBen Skeggs 			oclass->engn = &fifo->func->chan.user;
1168f0649b5SBen Skeggs 			*class = &nvkm_fifo_class;
1178f0649b5SBen Skeggs 			return 0;
1188f0649b5SBen Skeggs 		}
1198f0649b5SBen Skeggs 	}
1208f0649b5SBen Skeggs 
1218f0649b5SBen Skeggs 	return c;
1228f0649b5SBen Skeggs }
1238f0649b5SBen Skeggs 
12413de7f46SBen Skeggs static int
nvkm_fifo_fini(struct nvkm_engine * engine,bool suspend)12513de7f46SBen Skeggs nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend)
12613de7f46SBen Skeggs {
12713de7f46SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
1284d60100aSBen Skeggs 	struct nvkm_runl *runl;
1292fc71a05SBen Skeggs 
1302fc71a05SBen Skeggs 	nvkm_inth_block(&fifo->engine.subdev.inth);
1312fc71a05SBen Skeggs 
1324d60100aSBen Skeggs 	nvkm_runl_foreach(runl, fifo)
1334d60100aSBen Skeggs 		nvkm_runl_fini(runl);
1342fc71a05SBen Skeggs 
13513de7f46SBen Skeggs 	return 0;
13613de7f46SBen Skeggs }
13713de7f46SBen Skeggs 
13813de7f46SBen Skeggs static int
nvkm_fifo_init(struct nvkm_engine * engine)139fd67738aSBen Skeggs nvkm_fifo_init(struct nvkm_engine *engine)
140fd67738aSBen Skeggs {
141fd67738aSBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
142965c41d9SBen Skeggs 	struct nvkm_runq *runq;
1437f4f35eaSBen Skeggs 	struct nvkm_runl *runl;
144965c41d9SBen Skeggs 	u32 mask = 0;
145965c41d9SBen Skeggs 
146965c41d9SBen Skeggs 	if (fifo->func->init_pbdmas) {
147965c41d9SBen Skeggs 		nvkm_runq_foreach(runq, fifo)
148965c41d9SBen Skeggs 			mask |= BIT(runq->id);
149965c41d9SBen Skeggs 
150965c41d9SBen Skeggs 		fifo->func->init_pbdmas(fifo, mask);
15187c86024SBen Skeggs 
15287c86024SBen Skeggs 		nvkm_runq_foreach(runq, fifo)
15387c86024SBen Skeggs 			runq->func->init(runq);
154965c41d9SBen Skeggs 	}
1552fc71a05SBen Skeggs 
1567f4f35eaSBen Skeggs 	nvkm_runl_foreach(runl, fifo) {
1577f4f35eaSBen Skeggs 		if (runl->func->init)
1587f4f35eaSBen Skeggs 			runl->func->init(runl);
1597f4f35eaSBen Skeggs 	}
1607f4f35eaSBen Skeggs 
1617f4f35eaSBen Skeggs 	if (fifo->func->init)
162fd67738aSBen Skeggs 		fifo->func->init(fifo);
1632fc71a05SBen Skeggs 
1642fc71a05SBen Skeggs 	nvkm_inth_allow(&fifo->engine.subdev.inth);
165fd67738aSBen Skeggs 	return 0;
166fd67738aSBen Skeggs }
167fd67738aSBen Skeggs 
168fd67738aSBen Skeggs static int
nvkm_fifo_info(struct nvkm_engine * engine,u64 mthd,u64 * data)169eb47db4fSBen Skeggs nvkm_fifo_info(struct nvkm_engine *engine, u64 mthd, u64 *data)
170eb47db4fSBen Skeggs {
171eb47db4fSBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
1726de12538SBen Skeggs 	struct nvkm_runl *runl;
1736de12538SBen Skeggs 	struct nvkm_engn *engn;
1746de12538SBen Skeggs 	int ret;
1756de12538SBen Skeggs 
1766de12538SBen Skeggs 	ret = nvkm_subdev_oneinit(&fifo->engine.subdev);
1776de12538SBen Skeggs 	if (ret)
1786de12538SBen Skeggs 		return ret;
179800ac1f8SBen Skeggs 
180eb47db4fSBen Skeggs 	switch (mthd) {
181800ac1f8SBen Skeggs 	case NV_DEVICE_HOST_CHANNELS: *data = fifo->chid ? fifo->chid->nr : 0; return 0;
1826de12538SBen Skeggs 	case NV_DEVICE_HOST_RUNLISTS:
1836de12538SBen Skeggs 		*data = 0;
1846de12538SBen Skeggs 		nvkm_runl_foreach(runl, fifo)
1856de12538SBen Skeggs 			*data |= BIT(runl->id);
1866de12538SBen Skeggs 		return 0;
1876de12538SBen Skeggs 	case NV_DEVICE_HOST_RUNLIST_ENGINES:
1886de12538SBen Skeggs 		runl = nvkm_runl_get(fifo, *data, 0);
1896de12538SBen Skeggs 		if (runl) {
1906de12538SBen Skeggs 			*data = 0;
1916de12538SBen Skeggs 			nvkm_runl_foreach_engn(engn, runl) {
1926de12538SBen Skeggs #define CASE(n) case NVKM_ENGINE_##n: *data |= NV_DEVICE_HOST_RUNLIST_ENGINES_##n; break
1936de12538SBen Skeggs 				switch (engn->engine->subdev.type) {
1946de12538SBen Skeggs 				case NVKM_ENGINE_DMAOBJ:
1956de12538SBen Skeggs 					break;
1966de12538SBen Skeggs 				CASE(SW    );
1976de12538SBen Skeggs 				CASE(GR    );
1986de12538SBen Skeggs 				CASE(MPEG  );
1996de12538SBen Skeggs 				CASE(ME    );
2006de12538SBen Skeggs 				CASE(CIPHER);
2016de12538SBen Skeggs 				CASE(BSP   );
2026de12538SBen Skeggs 				CASE(VP    );
2036de12538SBen Skeggs 				CASE(CE    );
2046de12538SBen Skeggs 				CASE(SEC   );
2056de12538SBen Skeggs 				CASE(MSVLD );
2066de12538SBen Skeggs 				CASE(MSPDEC);
2076de12538SBen Skeggs 				CASE(MSPPP );
2086de12538SBen Skeggs 				CASE(MSENC );
2096de12538SBen Skeggs 				CASE(VIC   );
2106de12538SBen Skeggs 				CASE(SEC2  );
2116de12538SBen Skeggs 				CASE(NVDEC );
2126de12538SBen Skeggs 				CASE(NVENC );
213eb47db4fSBen Skeggs 				default:
2146de12538SBen Skeggs 					WARN_ON(1);
2156de12538SBen Skeggs 					break;
2166de12538SBen Skeggs 				}
2176de12538SBen Skeggs #undef CASE
2186de12538SBen Skeggs 			}
2196de12538SBen Skeggs 			return 0;
2206de12538SBen Skeggs 		}
2216de12538SBen Skeggs 		return -EINVAL;
222eb39c613SBen Skeggs 	case NV_DEVICE_HOST_RUNLIST_CHANNELS:
223eb39c613SBen Skeggs 		if (!fifo->chid) {
224eb39c613SBen Skeggs 			runl = nvkm_runl_get(fifo, *data, 0);
225eb39c613SBen Skeggs 			if (runl) {
226eb39c613SBen Skeggs 				*data = runl->chid->nr;
227eb39c613SBen Skeggs 				return 0;
228eb39c613SBen Skeggs 			}
229eb39c613SBen Skeggs 		}
230eb39c613SBen Skeggs 		return -EINVAL;
2316de12538SBen Skeggs 	default:
232eb47db4fSBen Skeggs 		break;
233eb47db4fSBen Skeggs 	}
234800ac1f8SBen Skeggs 
235eb47db4fSBen Skeggs 	return -ENOSYS;
236eb47db4fSBen Skeggs }
237eb47db4fSBen Skeggs 
238eb47db4fSBen Skeggs static int
nvkm_fifo_oneinit(struct nvkm_engine * engine)23913de7f46SBen Skeggs nvkm_fifo_oneinit(struct nvkm_engine *engine)
24013de7f46SBen Skeggs {
2412fc71a05SBen Skeggs 	struct nvkm_subdev *subdev = &engine->subdev;
2422fc71a05SBen Skeggs 	struct nvkm_device *device = subdev->device;
24313de7f46SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
244d94470e9SBen Skeggs 	struct nvkm_runl *runl;
245d94470e9SBen Skeggs 	struct nvkm_engn *engn;
2461c488ba9SBen Skeggs 	int ret, nr, i;
247800ac1f8SBen Skeggs 
248800ac1f8SBen Skeggs 	/* Initialise CHID/CGID allocator(s) on GPUs where they aren't per-runlist. */
249800ac1f8SBen Skeggs 	if (fifo->func->chid_nr) {
250800ac1f8SBen Skeggs 		ret = fifo->func->chid_ctor(fifo, fifo->func->chid_nr(fifo));
251800ac1f8SBen Skeggs 		if (ret)
252800ac1f8SBen Skeggs 			return ret;
253800ac1f8SBen Skeggs 	}
254800ac1f8SBen Skeggs 
2551c488ba9SBen Skeggs 	/* Create runqueues for each PBDMA. */
2561c488ba9SBen Skeggs 	if (fifo->func->runq_nr) {
2571c488ba9SBen Skeggs 		for (nr = fifo->func->runq_nr(fifo), i = 0; i < nr; i++) {
2581c488ba9SBen Skeggs 			if (!nvkm_runq_new(fifo, i))
2591c488ba9SBen Skeggs 				return -ENOMEM;
2601c488ba9SBen Skeggs 		}
2611c488ba9SBen Skeggs 	}
2621c488ba9SBen Skeggs 
263d94470e9SBen Skeggs 	/* Create runlists. */
264d94470e9SBen Skeggs 	ret = fifo->func->runl_ctor(fifo);
265d94470e9SBen Skeggs 	if (ret)
266d94470e9SBen Skeggs 		return ret;
267d94470e9SBen Skeggs 
268d94470e9SBen Skeggs 	nvkm_runl_foreach(runl, fifo) {
2697f4f35eaSBen Skeggs 		RUNL_DEBUG(runl, "chan:%06x", runl->chan);
270d94470e9SBen Skeggs 		nvkm_runl_foreach_engn(engn, runl) {
271d94470e9SBen Skeggs 			ENGN_DEBUG(engn, "");
272d94470e9SBen Skeggs 		}
273d94470e9SBen Skeggs 	}
274d94470e9SBen Skeggs 
2752fc71a05SBen Skeggs 	/* Register interrupt handler. */
2762fc71a05SBen Skeggs 	if (fifo->func->intr) {
2772fc71a05SBen Skeggs 		ret = nvkm_inth_add(&device->mc->intr, NVKM_INTR_SUBDEV, NVKM_INTR_PRIO_NORMAL,
2782fc71a05SBen Skeggs 				    subdev, fifo->func->intr, &subdev->inth);
2792fc71a05SBen Skeggs 		if (ret) {
2802fc71a05SBen Skeggs 			nvkm_error(subdev, "intr %d\n", ret);
2812fc71a05SBen Skeggs 			return ret;
2822fc71a05SBen Skeggs 		}
2832fc71a05SBen Skeggs 	}
2842fc71a05SBen Skeggs 
2857f4f35eaSBen Skeggs 	/* Initialise non-stall intr handling. */
286*55e1a599SBen Skeggs 	if (fifo->func->nonstall) {
2877f4f35eaSBen Skeggs 		if (fifo->func->nonstall_ctor) {
2887f4f35eaSBen Skeggs 			ret = fifo->func->nonstall_ctor(fifo);
289*55e1a599SBen Skeggs 			if (ret < 0) {
2907f4f35eaSBen Skeggs 				nvkm_error(subdev, "nonstall %d\n", ret);
291*55e1a599SBen Skeggs 				return ret;
2927f4f35eaSBen Skeggs 			}
293*55e1a599SBen Skeggs 		} else {
294*55e1a599SBen Skeggs 			ret = 1;
295*55e1a599SBen Skeggs 		}
296*55e1a599SBen Skeggs 
297*55e1a599SBen Skeggs 		ret = nvkm_event_init(fifo->func->nonstall, &fifo->engine.subdev, 1, ret,
298*55e1a599SBen Skeggs 				      &fifo->nonstall.event);
299*55e1a599SBen Skeggs 		if (ret)
300*55e1a599SBen Skeggs 			return ret;
3017f4f35eaSBen Skeggs 	}
3027f4f35eaSBen Skeggs 
303fbe9f433SBen Skeggs 	/* Allocate USERD + BAR1 polling area. */
304fbe9f433SBen Skeggs 	if (fifo->func->chan.func->userd->bar == 1) {
305fbe9f433SBen Skeggs 		struct nvkm_vmm *bar1 = nvkm_bar_bar1_vmm(device);
306fbe9f433SBen Skeggs 
307fbe9f433SBen Skeggs 		ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, fifo->chid->nr *
308fbe9f433SBen Skeggs 				      fifo->func->chan.func->userd->size, 0, true,
309fbe9f433SBen Skeggs 				      &fifo->userd.mem);
310fbe9f433SBen Skeggs 		if (ret)
311fbe9f433SBen Skeggs 			return ret;
312fbe9f433SBen Skeggs 
313fbe9f433SBen Skeggs 		ret = nvkm_vmm_get(bar1, 12, nvkm_memory_size(fifo->userd.mem), &fifo->userd.bar1);
314fbe9f433SBen Skeggs 		if (ret)
315fbe9f433SBen Skeggs 			return ret;
316fbe9f433SBen Skeggs 
317fbe9f433SBen Skeggs 		ret = nvkm_memory_map(fifo->userd.mem, 0, bar1, fifo->userd.bar1, NULL, 0);
318fbe9f433SBen Skeggs 		if (ret)
319fbe9f433SBen Skeggs 			return ret;
320fbe9f433SBen Skeggs 	}
321fbe9f433SBen Skeggs 
32213de7f46SBen Skeggs 	return 0;
32313de7f46SBen Skeggs }
32413de7f46SBen Skeggs 
3255e721ad1SBen Skeggs static void
nvkm_fifo_preinit(struct nvkm_engine * engine)3265e721ad1SBen Skeggs nvkm_fifo_preinit(struct nvkm_engine *engine)
3275e721ad1SBen Skeggs {
3286997ea13SBen Skeggs 	nvkm_mc_reset(engine->subdev.device, NVKM_ENGINE_FIFO, 0);
3295e721ad1SBen Skeggs }
3305e721ad1SBen Skeggs 
33113de7f46SBen Skeggs static void *
nvkm_fifo_dtor(struct nvkm_engine * engine)33213de7f46SBen Skeggs nvkm_fifo_dtor(struct nvkm_engine *engine)
33313de7f46SBen Skeggs {
33413de7f46SBen Skeggs 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
335d94470e9SBen Skeggs 	struct nvkm_runl *runl, *runt;
3361c488ba9SBen Skeggs 	struct nvkm_runq *runq, *rtmp;
337800ac1f8SBen Skeggs 
338fbe9f433SBen Skeggs 	if (fifo->userd.bar1)
339fbe9f433SBen Skeggs 		nvkm_vmm_put(nvkm_bar_bar1_vmm(engine->subdev.device), &fifo->userd.bar1);
340fbe9f433SBen Skeggs 	nvkm_memory_unref(&fifo->userd.mem);
341fbe9f433SBen Skeggs 
342d94470e9SBen Skeggs 	list_for_each_entry_safe(runl, runt, &fifo->runls, head)
343d94470e9SBen Skeggs 		nvkm_runl_del(runl);
3441c488ba9SBen Skeggs 	list_for_each_entry_safe(runq, rtmp, &fifo->runqs, head)
3451c488ba9SBen Skeggs 		nvkm_runq_del(runq);
3461c488ba9SBen Skeggs 
347800ac1f8SBen Skeggs 	nvkm_chid_unref(&fifo->cgid);
348800ac1f8SBen Skeggs 	nvkm_chid_unref(&fifo->chid);
349800ac1f8SBen Skeggs 
350d67f3b96SBen Skeggs 	nvkm_event_fini(&fifo->nonstall.event);
351a6419360SBen Skeggs 	mutex_destroy(&fifo->mutex);
35206db7fdeSBen Skeggs 	return fifo;
353c39f472eSBen Skeggs }
354c39f472eSBen Skeggs 
3558f0649b5SBen Skeggs static const struct nvkm_engine_func
35613de7f46SBen Skeggs nvkm_fifo = {
35713de7f46SBen Skeggs 	.dtor = nvkm_fifo_dtor,
3585e721ad1SBen Skeggs 	.preinit = nvkm_fifo_preinit,
35913de7f46SBen Skeggs 	.oneinit = nvkm_fifo_oneinit,
360eb47db4fSBen Skeggs 	.info = nvkm_fifo_info,
36113de7f46SBen Skeggs 	.init = nvkm_fifo_init,
36213de7f46SBen Skeggs 	.fini = nvkm_fifo_fini,
3638f0649b5SBen Skeggs 	.base.sclass = nvkm_fifo_class_get,
3648f0649b5SBen Skeggs };
3658f0649b5SBen Skeggs 
366c39f472eSBen Skeggs int
nvkm_fifo_new_(const struct nvkm_fifo_func * func,struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_fifo ** pfifo)36706db7fdeSBen Skeggs nvkm_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device,
36806db7fdeSBen Skeggs 	       enum nvkm_subdev_type type, int inst, struct nvkm_fifo **pfifo)
369c39f472eSBen Skeggs {
37006db7fdeSBen Skeggs 	struct nvkm_fifo *fifo;
371c39f472eSBen Skeggs 
37206db7fdeSBen Skeggs 	if (!(fifo = *pfifo = kzalloc(sizeof(*fifo), GFP_KERNEL)))
37306db7fdeSBen Skeggs 		return -ENOMEM;
37406db7fdeSBen Skeggs 
37513de7f46SBen Skeggs 	fifo->func = func;
3761c488ba9SBen Skeggs 	INIT_LIST_HEAD(&fifo->runqs);
377d94470e9SBen Skeggs 	INIT_LIST_HEAD(&fifo->runls);
3784a492fd5SBen Skeggs 	/*TODO: Needs to be >CTXSW_TIMEOUT, so RC can recover before this is hit.
3794a492fd5SBen Skeggs 	 *      CTXSW_TIMEOUT HW default seems to differ between GPUs, so just a
3804a492fd5SBen Skeggs 	 *      large number for now until we support changing it.
3814a492fd5SBen Skeggs 	 */
3824a492fd5SBen Skeggs 	fifo->timeout.chan_msec = 10000;
38313de7f46SBen Skeggs 	spin_lock_init(&fifo->lock);
384a6419360SBen Skeggs 	mutex_init(&fifo->mutex);
3858f0649b5SBen Skeggs 
386*55e1a599SBen Skeggs 	return nvkm_engine_ctor(&nvkm_fifo, device, type, inst, true, &fifo->engine);
387c39f472eSBen Skeggs }
388