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