105c7145dSBen Skeggs /*
205c7145dSBen Skeggs * Copyright 2012 Red Hat Inc.
305c7145dSBen Skeggs *
405c7145dSBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
505c7145dSBen Skeggs * copy of this software and associated documentation files (the "Software"),
605c7145dSBen Skeggs * to deal in the Software without restriction, including without limitation
705c7145dSBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
805c7145dSBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the
905c7145dSBen Skeggs * Software is furnished to do so, subject to the following conditions:
1005c7145dSBen Skeggs *
1105c7145dSBen Skeggs * The above copyright notice and this permission notice shall be included in
1205c7145dSBen Skeggs * all copies or substantial portions of the Software.
1305c7145dSBen Skeggs *
1405c7145dSBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505c7145dSBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605c7145dSBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1705c7145dSBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1805c7145dSBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1905c7145dSBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2005c7145dSBen Skeggs * OTHER DEALINGS IN THE SOFTWARE.
2105c7145dSBen Skeggs *
2205c7145dSBen Skeggs * Authors: Ben Skeggs
2305c7145dSBen Skeggs */
2406db7fdeSBen Skeggs #include "priv.h"
2562742b5eSBen Skeggs #include "cgrp.h"
26f5e45689SBen Skeggs #include "chan.h"
27800ac1f8SBen Skeggs #include "chid.h"
28d94470e9SBen Skeggs #include "runl.h"
291c488ba9SBen Skeggs #include "runq.h"
30f5e45689SBen Skeggs
3113de7f46SBen Skeggs #include <core/gpuobj.h>
32358ce601SBen Skeggs #include <subdev/bar.h>
33cf9518b5SBen Skeggs #include <subdev/fault.h>
342fc71a05SBen Skeggs #include <subdev/mc.h>
3506db7fdeSBen Skeggs #include <subdev/mmu.h>
3661570911SBen Skeggs #include <engine/sw.h>
3705c7145dSBen Skeggs
3805c7145dSBen Skeggs #include <nvif/class.h>
3905c7145dSBen Skeggs
40acff9415SBen Skeggs void
gf100_chan_preempt(struct nvkm_chan * chan)41acff9415SBen Skeggs gf100_chan_preempt(struct nvkm_chan *chan)
42acff9415SBen Skeggs {
43acff9415SBen Skeggs nvkm_wr32(chan->cgrp->runl->fifo->engine.subdev.device, 0x002634, chan->id);
44acff9415SBen Skeggs }
45acff9415SBen Skeggs
4667059b9fSBen Skeggs static void
gf100_chan_stop(struct nvkm_chan * chan)4767059b9fSBen Skeggs gf100_chan_stop(struct nvkm_chan *chan)
4867059b9fSBen Skeggs {
4967059b9fSBen Skeggs struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
5067059b9fSBen Skeggs
5167059b9fSBen Skeggs nvkm_mask(device, 0x003004 + (chan->id * 8), 0x00000001, 0x00000000);
5267059b9fSBen Skeggs }
5367059b9fSBen Skeggs
5467059b9fSBen Skeggs static void
gf100_chan_start(struct nvkm_chan * chan)5567059b9fSBen Skeggs gf100_chan_start(struct nvkm_chan *chan)
5667059b9fSBen Skeggs {
5767059b9fSBen Skeggs struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
5867059b9fSBen Skeggs
5967059b9fSBen Skeggs nvkm_wr32(device, 0x003004 + (chan->id * 8), 0x001f0001);
6067059b9fSBen Skeggs }
6167059b9fSBen Skeggs
6262742b5eSBen Skeggs static void gf100_fifo_intr_engine(struct nvkm_fifo *);
6362742b5eSBen Skeggs
6462742b5eSBen Skeggs static void
gf100_chan_unbind(struct nvkm_chan * chan)6562742b5eSBen Skeggs gf100_chan_unbind(struct nvkm_chan *chan)
6662742b5eSBen Skeggs {
6762742b5eSBen Skeggs struct nvkm_fifo *fifo = chan->cgrp->runl->fifo;
6862742b5eSBen Skeggs struct nvkm_device *device = fifo->engine.subdev.device;
6962742b5eSBen Skeggs
7062742b5eSBen Skeggs /*TODO: Is this cargo-culted, or necessary? RM does *something* here... Why? */
7162742b5eSBen Skeggs gf100_fifo_intr_engine(fifo);
7262742b5eSBen Skeggs
7362742b5eSBen Skeggs nvkm_wr32(device, 0x003000 + (chan->id * 8), 0x00000000);
7462742b5eSBen Skeggs }
7562742b5eSBen Skeggs
7662742b5eSBen Skeggs static void
gf100_chan_bind(struct nvkm_chan * chan)7762742b5eSBen Skeggs gf100_chan_bind(struct nvkm_chan *chan)
7862742b5eSBen Skeggs {
7962742b5eSBen Skeggs struct nvkm_device *device = chan->cgrp->runl->fifo->engine.subdev.device;
8062742b5eSBen Skeggs
8162742b5eSBen Skeggs nvkm_wr32(device, 0x003000 + (chan->id * 8), 0xc0000000 | chan->inst->addr >> 12);
8262742b5eSBen Skeggs }
8362742b5eSBen Skeggs
843647c53bSBen Skeggs static int
gf100_chan_ramfc_write(struct nvkm_chan * chan,u64 offset,u64 length,u32 devm,bool priv)853647c53bSBen Skeggs gf100_chan_ramfc_write(struct nvkm_chan *chan, u64 offset, u64 length, u32 devm, bool priv)
863647c53bSBen Skeggs {
873647c53bSBen Skeggs const u64 userd = nvkm_memory_addr(chan->userd.mem) + chan->userd.base;
883647c53bSBen Skeggs const u32 limit2 = ilog2(length / 8);
893647c53bSBen Skeggs
903647c53bSBen Skeggs nvkm_kmap(chan->inst);
913647c53bSBen Skeggs nvkm_wo32(chan->inst, 0x08, lower_32_bits(userd));
923647c53bSBen Skeggs nvkm_wo32(chan->inst, 0x0c, upper_32_bits(userd));
933647c53bSBen Skeggs nvkm_wo32(chan->inst, 0x10, 0x0000face);
943647c53bSBen Skeggs nvkm_wo32(chan->inst, 0x30, 0xfffff902);
953647c53bSBen Skeggs nvkm_wo32(chan->inst, 0x48, lower_32_bits(offset));
963647c53bSBen Skeggs nvkm_wo32(chan->inst, 0x4c, upper_32_bits(offset) | (limit2 << 16));
973647c53bSBen Skeggs nvkm_wo32(chan->inst, 0x54, 0x00000002);
983647c53bSBen Skeggs nvkm_wo32(chan->inst, 0x84, 0x20400000);
993647c53bSBen Skeggs nvkm_wo32(chan->inst, 0x94, 0x30000000 | devm);
1003647c53bSBen Skeggs nvkm_wo32(chan->inst, 0x9c, 0x00000100);
1013647c53bSBen Skeggs nvkm_wo32(chan->inst, 0xa4, 0x1f1f1f1f);
1023647c53bSBen Skeggs nvkm_wo32(chan->inst, 0xa8, 0x1f1f1f1f);
1033647c53bSBen Skeggs nvkm_wo32(chan->inst, 0xac, 0x0000001f);
1043647c53bSBen Skeggs nvkm_wo32(chan->inst, 0xb8, 0xf8000000);
1053647c53bSBen Skeggs nvkm_wo32(chan->inst, 0xf8, 0x10003080); /* 0x002310 */
1063647c53bSBen Skeggs nvkm_wo32(chan->inst, 0xfc, 0x10000010); /* 0x002350 */
1073647c53bSBen Skeggs nvkm_done(chan->inst);
1083647c53bSBen Skeggs return 0;
1093647c53bSBen Skeggs }
1103647c53bSBen Skeggs
1113647c53bSBen Skeggs static const struct nvkm_chan_func_ramfc
1123647c53bSBen Skeggs gf100_chan_ramfc = {
1133647c53bSBen Skeggs .write = gf100_chan_ramfc_write,
1143647c53bSBen Skeggs .devm = 0xfff,
1153647c53bSBen Skeggs };
1163647c53bSBen Skeggs
117fbe9f433SBen Skeggs void
gf100_chan_userd_clear(struct nvkm_chan * chan)118fbe9f433SBen Skeggs gf100_chan_userd_clear(struct nvkm_chan *chan)
119fbe9f433SBen Skeggs {
120fbe9f433SBen Skeggs nvkm_kmap(chan->userd.mem);
121fbe9f433SBen Skeggs nvkm_wo32(chan->userd.mem, chan->userd.base + 0x040, 0x00000000);
122fbe9f433SBen Skeggs nvkm_wo32(chan->userd.mem, chan->userd.base + 0x044, 0x00000000);
123fbe9f433SBen Skeggs nvkm_wo32(chan->userd.mem, chan->userd.base + 0x048, 0x00000000);
124fbe9f433SBen Skeggs nvkm_wo32(chan->userd.mem, chan->userd.base + 0x04c, 0x00000000);
125fbe9f433SBen Skeggs nvkm_wo32(chan->userd.mem, chan->userd.base + 0x050, 0x00000000);
126fbe9f433SBen Skeggs nvkm_wo32(chan->userd.mem, chan->userd.base + 0x058, 0x00000000);
127fbe9f433SBen Skeggs nvkm_wo32(chan->userd.mem, chan->userd.base + 0x05c, 0x00000000);
128fbe9f433SBen Skeggs nvkm_wo32(chan->userd.mem, chan->userd.base + 0x060, 0x00000000);
129fbe9f433SBen Skeggs nvkm_wo32(chan->userd.mem, chan->userd.base + 0x088, 0x00000000);
130fbe9f433SBen Skeggs nvkm_wo32(chan->userd.mem, chan->userd.base + 0x08c, 0x00000000);
131fbe9f433SBen Skeggs nvkm_done(chan->userd.mem);
132fbe9f433SBen Skeggs }
133fbe9f433SBen Skeggs
134fbe9f433SBen Skeggs static const struct nvkm_chan_func_userd
135fbe9f433SBen Skeggs gf100_chan_userd = {
136fbe9f433SBen Skeggs .bar = 1,
137fbe9f433SBen Skeggs .size = 0x1000,
138fbe9f433SBen Skeggs .clear = gf100_chan_userd_clear,
139fbe9f433SBen Skeggs };
140fbe9f433SBen Skeggs
141d3e7a439SBen Skeggs const struct nvkm_chan_func_inst
142d3e7a439SBen Skeggs gf100_chan_inst = {
143d3e7a439SBen Skeggs .size = 0x1000,
144d3e7a439SBen Skeggs .zero = true,
145d3e7a439SBen Skeggs .vmm = true,
146d3e7a439SBen Skeggs };
147d3e7a439SBen Skeggs
148f5e45689SBen Skeggs static const struct nvkm_chan_func
149f5e45689SBen Skeggs gf100_chan = {
150d3e7a439SBen Skeggs .inst = &gf100_chan_inst,
151fbe9f433SBen Skeggs .userd = &gf100_chan_userd,
1523647c53bSBen Skeggs .ramfc = &gf100_chan_ramfc,
15362742b5eSBen Skeggs .bind = gf100_chan_bind,
15462742b5eSBen Skeggs .unbind = gf100_chan_unbind,
15567059b9fSBen Skeggs .start = gf100_chan_start,
15667059b9fSBen Skeggs .stop = gf100_chan_stop,
157acff9415SBen Skeggs .preempt = gf100_chan_preempt,
158f5e45689SBen Skeggs };
159f5e45689SBen Skeggs
1608ab849d6SBen Skeggs static void
gf100_ectx_bind(struct nvkm_engn * engn,struct nvkm_cctx * cctx,struct nvkm_chan * chan)1618ab849d6SBen Skeggs gf100_ectx_bind(struct nvkm_engn *engn, struct nvkm_cctx *cctx, struct nvkm_chan *chan)
1628ab849d6SBen Skeggs {
1638ab849d6SBen Skeggs u64 addr = 0ULL;
1648ab849d6SBen Skeggs u32 ptr0;
1658ab849d6SBen Skeggs
1668ab849d6SBen Skeggs switch (engn->engine->subdev.type) {
1678ab849d6SBen Skeggs case NVKM_ENGINE_SW : return;
1688ab849d6SBen Skeggs case NVKM_ENGINE_GR : ptr0 = 0x0210; break;
1698ab849d6SBen Skeggs case NVKM_ENGINE_CE : ptr0 = 0x0230 + (engn->engine->subdev.inst * 0x10); break;
1708ab849d6SBen Skeggs case NVKM_ENGINE_MSPDEC: ptr0 = 0x0250; break;
1718ab849d6SBen Skeggs case NVKM_ENGINE_MSPPP : ptr0 = 0x0260; break;
1728ab849d6SBen Skeggs case NVKM_ENGINE_MSVLD : ptr0 = 0x0270; break;
1738ab849d6SBen Skeggs default:
1748ab849d6SBen Skeggs WARN_ON(1);
1758ab849d6SBen Skeggs return;
1768ab849d6SBen Skeggs }
1778ab849d6SBen Skeggs
1788ab849d6SBen Skeggs if (cctx) {
1798ab849d6SBen Skeggs addr = cctx->vctx->vma->addr;
1808ab849d6SBen Skeggs addr |= 4ULL;
1818ab849d6SBen Skeggs }
1828ab849d6SBen Skeggs
1838ab849d6SBen Skeggs nvkm_kmap(chan->inst);
1848ab849d6SBen Skeggs nvkm_wo32(chan->inst, ptr0 + 0, lower_32_bits(addr));
1858ab849d6SBen Skeggs nvkm_wo32(chan->inst, ptr0 + 4, upper_32_bits(addr));
1868ab849d6SBen Skeggs nvkm_done(chan->inst);
1878ab849d6SBen Skeggs }
1888ab849d6SBen Skeggs
1898ab849d6SBen Skeggs static int
gf100_ectx_ctor(struct nvkm_engn * engn,struct nvkm_vctx * vctx)1908ab849d6SBen Skeggs gf100_ectx_ctor(struct nvkm_engn *engn, struct nvkm_vctx *vctx)
1918ab849d6SBen Skeggs {
1928ab849d6SBen Skeggs int ret;
1938ab849d6SBen Skeggs
1948ab849d6SBen Skeggs ret = nvkm_vmm_get(vctx->vmm, 12, vctx->inst->size, &vctx->vma);
1958ab849d6SBen Skeggs if (ret)
1968ab849d6SBen Skeggs return ret;
1978ab849d6SBen Skeggs
1988ab849d6SBen Skeggs return nvkm_memory_map(vctx->inst, 0, vctx->vmm, vctx->vma, NULL, 0);
1998ab849d6SBen Skeggs }
2008ab849d6SBen Skeggs
2014d60100aSBen Skeggs bool
gf100_engn_mmu_fault_triggered(struct nvkm_engn * engn)2024d60100aSBen Skeggs gf100_engn_mmu_fault_triggered(struct nvkm_engn *engn)
2034d60100aSBen Skeggs {
2044d60100aSBen Skeggs struct nvkm_runl *runl = engn->runl;
2054d60100aSBen Skeggs struct nvkm_fifo *fifo = runl->fifo;
2064d60100aSBen Skeggs struct nvkm_device *device = fifo->engine.subdev.device;
2074d60100aSBen Skeggs u32 data = nvkm_rd32(device, 0x002a30 + (engn->id * 4));
2084d60100aSBen Skeggs
2094d60100aSBen Skeggs ENGN_DEBUG(engn, "%08x: mmu fault triggered", data);
2104d60100aSBen Skeggs if (!(data & 0x00000100))
2114d60100aSBen Skeggs return false;
2124d60100aSBen Skeggs
2134d60100aSBen Skeggs spin_lock(&fifo->lock);
2144d60100aSBen Skeggs nvkm_mask(device, 0x002a30 + (engn->id * 4), 0x00000100, 0x00000000);
2154d60100aSBen Skeggs if (atomic_dec_and_test(&runl->rc_triggered))
2164d60100aSBen Skeggs nvkm_mask(device, 0x002140, 0x00000100, 0x00000100);
2174d60100aSBen Skeggs spin_unlock(&fifo->lock);
2184d60100aSBen Skeggs return true;
2194d60100aSBen Skeggs }
2204d60100aSBen Skeggs
2214d60100aSBen Skeggs void
gf100_engn_mmu_fault_trigger(struct nvkm_engn * engn)2224d60100aSBen Skeggs gf100_engn_mmu_fault_trigger(struct nvkm_engn *engn)
2234d60100aSBen Skeggs {
2244d60100aSBen Skeggs struct nvkm_runl *runl = engn->runl;
2254d60100aSBen Skeggs struct nvkm_fifo *fifo = runl->fifo;
2264d60100aSBen Skeggs struct nvkm_device *device = fifo->engine.subdev.device;
2274d60100aSBen Skeggs
2284d60100aSBen Skeggs ENGN_DEBUG(engn, "triggering mmu fault on 0x%02x", engn->fault);
2294d60100aSBen Skeggs spin_lock(&fifo->lock);
2304d60100aSBen Skeggs if (atomic_inc_return(&runl->rc_triggered) == 1)
2314d60100aSBen Skeggs nvkm_mask(device, 0x002140, 0x00000100, 0x00000000);
2324d60100aSBen Skeggs nvkm_wr32(device, 0x002100, 0x00000100);
2334d60100aSBen Skeggs nvkm_wr32(device, 0x002a30 + (engn->id * 4), 0x00000100 | engn->fault);
2344d60100aSBen Skeggs spin_unlock(&fifo->lock);
2354d60100aSBen Skeggs }
2364d60100aSBen Skeggs
2374d60100aSBen Skeggs /*TODO: clean all this up. */
2384d60100aSBen Skeggs struct gf100_engn_status {
2394d60100aSBen Skeggs bool busy;
2404d60100aSBen Skeggs bool save;
2414d60100aSBen Skeggs bool unk0;
2424d60100aSBen Skeggs bool unk1;
2434d60100aSBen Skeggs u8 chid;
2444d60100aSBen Skeggs };
2454d60100aSBen Skeggs
2464d60100aSBen Skeggs static void
gf100_engn_status(struct nvkm_engn * engn,struct gf100_engn_status * status)2474d60100aSBen Skeggs gf100_engn_status(struct nvkm_engn *engn, struct gf100_engn_status *status)
2484d60100aSBen Skeggs {
2494d60100aSBen Skeggs u32 stat = nvkm_rd32(engn->engine->subdev.device, 0x002640 + (engn->id * 4));
2504d60100aSBen Skeggs
2514d60100aSBen Skeggs status->busy = (stat & 0x10000000);
2524d60100aSBen Skeggs status->save = (stat & 0x00100000);
2534d60100aSBen Skeggs status->unk0 = (stat & 0x00004000);
2544d60100aSBen Skeggs status->unk1 = (stat & 0x00001000);
2554d60100aSBen Skeggs status->chid = (stat & 0x0000007f);
2564d60100aSBen Skeggs
2574d60100aSBen Skeggs ENGN_DEBUG(engn, "%08x: busy %d save %d unk0 %d unk1 %d chid %d",
2584d60100aSBen Skeggs stat, status->busy, status->save, status->unk0, status->unk1, status->chid);
2594d60100aSBen Skeggs }
2604d60100aSBen Skeggs
2614d60100aSBen Skeggs static int
gf100_engn_cxid(struct nvkm_engn * engn,bool * cgid)2624d60100aSBen Skeggs gf100_engn_cxid(struct nvkm_engn *engn, bool *cgid)
2634d60100aSBen Skeggs {
2644d60100aSBen Skeggs struct gf100_engn_status status;
2654d60100aSBen Skeggs
2664d60100aSBen Skeggs gf100_engn_status(engn, &status);
2674d60100aSBen Skeggs if (status.busy) {
2684d60100aSBen Skeggs *cgid = false;
2694d60100aSBen Skeggs return status.chid;
2704d60100aSBen Skeggs }
2714d60100aSBen Skeggs
2724d60100aSBen Skeggs return -ENODEV;
2734d60100aSBen Skeggs }
2744d60100aSBen Skeggs
2754d60100aSBen Skeggs static bool
gf100_engn_chsw(struct nvkm_engn * engn)2764d60100aSBen Skeggs gf100_engn_chsw(struct nvkm_engn *engn)
2774d60100aSBen Skeggs {
2784d60100aSBen Skeggs struct gf100_engn_status status;
2794d60100aSBen Skeggs
2804d60100aSBen Skeggs gf100_engn_status(engn, &status);
2814d60100aSBen Skeggs if (status.busy && (status.unk0 || status.unk1))
2824d60100aSBen Skeggs return true;
2834d60100aSBen Skeggs
2844d60100aSBen Skeggs return false;
2854d60100aSBen Skeggs }
2864d60100aSBen Skeggs
287d94470e9SBen Skeggs static const struct nvkm_engn_func
288d94470e9SBen Skeggs gf100_engn = {
2894d60100aSBen Skeggs .chsw = gf100_engn_chsw,
2904d60100aSBen Skeggs .cxid = gf100_engn_cxid,
2914d60100aSBen Skeggs .mmu_fault_trigger = gf100_engn_mmu_fault_trigger,
2924d60100aSBen Skeggs .mmu_fault_triggered = gf100_engn_mmu_fault_triggered,
2938ab849d6SBen Skeggs .ctor = gf100_ectx_ctor,
2948ab849d6SBen Skeggs .bind = gf100_ectx_bind,
295d94470e9SBen Skeggs };
296d94470e9SBen Skeggs
297d94470e9SBen Skeggs const struct nvkm_engn_func
298d94470e9SBen Skeggs gf100_engn_sw = {
299d94470e9SBen Skeggs };
300d94470e9SBen Skeggs
301fd67738aSBen Skeggs static const struct nvkm_bitfield
302923f1ff5SBen Skeggs gf100_runq_intr_0_names[] = {
303fd67738aSBen Skeggs /* { 0x00008000, "" } seen with null ib push */
304fd67738aSBen Skeggs { 0x00200000, "ILLEGAL_MTHD" },
305fd67738aSBen Skeggs { 0x00800000, "EMPTY_SUBC" },
306fd67738aSBen Skeggs {}
307fd67738aSBen Skeggs };
308fd67738aSBen Skeggs
309923f1ff5SBen Skeggs bool
gf100_runq_intr(struct nvkm_runq * runq,struct nvkm_runl * null)310923f1ff5SBen Skeggs gf100_runq_intr(struct nvkm_runq *runq, struct nvkm_runl *null)
311fd67738aSBen Skeggs {
312923f1ff5SBen Skeggs struct nvkm_subdev *subdev = &runq->fifo->engine.subdev;
313fd67738aSBen Skeggs struct nvkm_device *device = subdev->device;
314923f1ff5SBen Skeggs u32 mask = nvkm_rd32(device, 0x04010c + (runq->id * 0x2000));
315923f1ff5SBen Skeggs u32 stat = nvkm_rd32(device, 0x040108 + (runq->id * 0x2000)) & mask;
316923f1ff5SBen Skeggs u32 addr = nvkm_rd32(device, 0x0400c0 + (runq->id * 0x2000));
317923f1ff5SBen Skeggs u32 data = nvkm_rd32(device, 0x0400c4 + (runq->id * 0x2000));
318923f1ff5SBen Skeggs u32 chid = nvkm_rd32(device, 0x040120 + (runq->id * 0x2000)) & runq->fifo->chid->mask;
319fd67738aSBen Skeggs u32 subc = (addr & 0x00070000) >> 16;
320fd67738aSBen Skeggs u32 mthd = (addr & 0x00003ffc);
321fd67738aSBen Skeggs u32 show = stat;
322923f1ff5SBen Skeggs struct nvkm_chan *chan;
323923f1ff5SBen Skeggs unsigned long flags;
324fd67738aSBen Skeggs char msg[128];
325fd67738aSBen Skeggs
326fd67738aSBen Skeggs if (stat & 0x00800000) {
327fd67738aSBen Skeggs if (device->sw) {
328fd67738aSBen Skeggs if (nvkm_sw_mthd(device->sw, chid, subc, mthd, data))
329fd67738aSBen Skeggs show &= ~0x00800000;
330fd67738aSBen Skeggs }
331fd67738aSBen Skeggs }
332fd67738aSBen Skeggs
333fd67738aSBen Skeggs if (show) {
334923f1ff5SBen Skeggs nvkm_snprintbf(msg, sizeof(msg), runq->func->intr_0_names, show);
335c358f538SBen Skeggs chan = nvkm_chan_get_chid(&runq->fifo->engine, chid, &flags);
336fd67738aSBen Skeggs nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%010llx %s] "
337fd67738aSBen Skeggs "subc %d mthd %04x data %08x\n",
338923f1ff5SBen Skeggs runq->id, show, msg, chid, chan ? chan->inst->addr : 0,
339520db040SBen Skeggs chan ? chan->name : "unknown", subc, mthd, data);
3404d60100aSBen Skeggs
3414d60100aSBen Skeggs /*TODO: use proper procedure for clearing each exception / debug output */
342520db040SBen Skeggs if ((stat & 0xc67fe000) && chan)
343520db040SBen Skeggs nvkm_chan_error(chan, true);
344c358f538SBen Skeggs nvkm_chan_put(&chan, flags);
345fd67738aSBen Skeggs }
346fd67738aSBen Skeggs
347923f1ff5SBen Skeggs nvkm_wr32(device, 0x0400c0 + (runq->id * 0x2000), 0x80600008);
348923f1ff5SBen Skeggs nvkm_wr32(device, 0x040108 + (runq->id * 0x2000), stat);
349923f1ff5SBen Skeggs return true;
350fd67738aSBen Skeggs }
351fd67738aSBen Skeggs
35287c86024SBen Skeggs void
gf100_runq_init(struct nvkm_runq * runq)35387c86024SBen Skeggs gf100_runq_init(struct nvkm_runq *runq)
35487c86024SBen Skeggs {
35587c86024SBen Skeggs struct nvkm_device *device = runq->fifo->engine.subdev.device;
35687c86024SBen Skeggs
35787c86024SBen Skeggs nvkm_mask(device, 0x04013c + (runq->id * 0x2000), 0x10000100, 0x00000000);
35887c86024SBen Skeggs nvkm_wr32(device, 0x040108 + (runq->id * 0x2000), 0xffffffff); /* INTR */
35987c86024SBen Skeggs nvkm_wr32(device, 0x04010c + (runq->id * 0x2000), 0xfffffeff); /* INTREN */
36087c86024SBen Skeggs }
36187c86024SBen Skeggs
3621c488ba9SBen Skeggs static const struct nvkm_runq_func
3631c488ba9SBen Skeggs gf100_runq = {
36487c86024SBen Skeggs .init = gf100_runq_init,
365923f1ff5SBen Skeggs .intr = gf100_runq_intr,
366923f1ff5SBen Skeggs .intr_0_names = gf100_runq_intr_0_names,
3671c488ba9SBen Skeggs };
3681c488ba9SBen Skeggs
369acff9415SBen Skeggs bool
gf100_runl_preempt_pending(struct nvkm_runl * runl)370acff9415SBen Skeggs gf100_runl_preempt_pending(struct nvkm_runl *runl)
371acff9415SBen Skeggs {
372acff9415SBen Skeggs return nvkm_rd32(runl->fifo->engine.subdev.device, 0x002634) & 0x00100000;
373acff9415SBen Skeggs }
374acff9415SBen Skeggs
3753a6bc9c2SBen Skeggs static void
gf100_runl_fault_clear(struct nvkm_runl * runl)3764d60100aSBen Skeggs gf100_runl_fault_clear(struct nvkm_runl *runl)
3774d60100aSBen Skeggs {
3784d60100aSBen Skeggs nvkm_mask(runl->fifo->engine.subdev.device, 0x00262c, 0x00000000, 0x00000000);
3794d60100aSBen Skeggs }
3804d60100aSBen Skeggs
3814d60100aSBen Skeggs static void
gf100_runl_allow(struct nvkm_runl * runl,u32 engm)3823a6bc9c2SBen Skeggs gf100_runl_allow(struct nvkm_runl *runl, u32 engm)
3833a6bc9c2SBen Skeggs {
3843a6bc9c2SBen Skeggs nvkm_mask(runl->fifo->engine.subdev.device, 0x002630, engm, 0x00000000);
3853a6bc9c2SBen Skeggs }
3863a6bc9c2SBen Skeggs
3873a6bc9c2SBen Skeggs static void
gf100_runl_block(struct nvkm_runl * runl,u32 engm)3883a6bc9c2SBen Skeggs gf100_runl_block(struct nvkm_runl *runl, u32 engm)
3893a6bc9c2SBen Skeggs {
3903a6bc9c2SBen Skeggs nvkm_mask(runl->fifo->engine.subdev.device, 0x002630, engm, engm);
3913a6bc9c2SBen Skeggs }
3923a6bc9c2SBen Skeggs
3934a492fd5SBen Skeggs static bool
gf100_runl_pending(struct nvkm_runl * runl)3944a492fd5SBen Skeggs gf100_runl_pending(struct nvkm_runl *runl)
3954a492fd5SBen Skeggs {
3964a492fd5SBen Skeggs return nvkm_rd32(runl->fifo->engine.subdev.device, 0x00227c) & 0x00100000;
3974a492fd5SBen Skeggs }
3984a492fd5SBen Skeggs
399b084fff2SBen Skeggs static void
gf100_runl_commit(struct nvkm_runl * runl,struct nvkm_memory * memory,u32 start,int count)400b084fff2SBen Skeggs gf100_runl_commit(struct nvkm_runl *runl, struct nvkm_memory *memory, u32 start, int count)
40105c7145dSBen Skeggs {
402b084fff2SBen Skeggs struct nvkm_device *device = runl->fifo->engine.subdev.device;
403b084fff2SBen Skeggs u64 addr = nvkm_memory_addr(memory) + start;
404c694ecadSAlexandre Courbot int target;
40505c7145dSBen Skeggs
406b084fff2SBen Skeggs switch (nvkm_memory_target(memory)) {
407d2ee3605SBen Skeggs case NVKM_MEM_TARGET_VRAM: target = 0; break;
408d2ee3605SBen Skeggs case NVKM_MEM_TARGET_NCOH: target = 3; break;
409d2ee3605SBen Skeggs default:
410d2ee3605SBen Skeggs WARN_ON(1);
411d2ee3605SBen Skeggs return;
412d2ee3605SBen Skeggs }
413c694ecadSAlexandre Courbot
414b084fff2SBen Skeggs nvkm_wr32(device, 0x002270, (target << 28) | (addr >> 12));
415b084fff2SBen Skeggs nvkm_wr32(device, 0x002274, 0x01f00000 | count);
41605c7145dSBen Skeggs }
41705c7145dSBen Skeggs
418b084fff2SBen Skeggs static void
gf100_runl_insert_chan(struct nvkm_chan * chan,struct nvkm_memory * memory,u64 offset)419b084fff2SBen Skeggs gf100_runl_insert_chan(struct nvkm_chan *chan, struct nvkm_memory *memory, u64 offset)
420d40d0fd4SBen Skeggs {
421b084fff2SBen Skeggs nvkm_wo32(memory, offset + 0, chan->id);
422b084fff2SBen Skeggs nvkm_wo32(memory, offset + 4, 0x00000004);
423d40d0fd4SBen Skeggs }
424d40d0fd4SBen Skeggs
425d94470e9SBen Skeggs static const struct nvkm_runl_func
426d94470e9SBen Skeggs gf100_runl = {
427b084fff2SBen Skeggs .size = 8,
428b084fff2SBen Skeggs .update = nv50_runl_update,
429b084fff2SBen Skeggs .insert_chan = gf100_runl_insert_chan,
430b084fff2SBen Skeggs .commit = gf100_runl_commit,
4314a492fd5SBen Skeggs .wait = nv50_runl_wait,
4324a492fd5SBen Skeggs .pending = gf100_runl_pending,
4333a6bc9c2SBen Skeggs .block = gf100_runl_block,
4343a6bc9c2SBen Skeggs .allow = gf100_runl_allow,
4354d60100aSBen Skeggs .fault_clear = gf100_runl_fault_clear,
436acff9415SBen Skeggs .preempt_pending = gf100_runl_preempt_pending,
437d94470e9SBen Skeggs };
438d94470e9SBen Skeggs
439d67f3b96SBen Skeggs static void
gf100_fifo_nonstall_allow(struct nvkm_event * event,int type,int index)440d67f3b96SBen Skeggs gf100_fifo_nonstall_allow(struct nvkm_event *event, int type, int index)
441d67f3b96SBen Skeggs {
442d67f3b96SBen Skeggs struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event);
443d67f3b96SBen Skeggs unsigned long flags;
444d67f3b96SBen Skeggs
445d67f3b96SBen Skeggs spin_lock_irqsave(&fifo->lock, flags);
446d67f3b96SBen Skeggs nvkm_mask(fifo->engine.subdev.device, 0x002140, 0x80000000, 0x80000000);
447d67f3b96SBen Skeggs spin_unlock_irqrestore(&fifo->lock, flags);
448d67f3b96SBen Skeggs }
449d67f3b96SBen Skeggs
450*abe3c66fSTom Rix static void
gf100_fifo_nonstall_block(struct nvkm_event * event,int type,int index)451d67f3b96SBen Skeggs gf100_fifo_nonstall_block(struct nvkm_event *event, int type, int index)
452d67f3b96SBen Skeggs {
453d67f3b96SBen Skeggs struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), nonstall.event);
454d67f3b96SBen Skeggs unsigned long flags;
455d67f3b96SBen Skeggs
456d67f3b96SBen Skeggs spin_lock_irqsave(&fifo->lock, flags);
457d67f3b96SBen Skeggs nvkm_mask(fifo->engine.subdev.device, 0x002140, 0x80000000, 0x00000000);
458d67f3b96SBen Skeggs spin_unlock_irqrestore(&fifo->lock, flags);
459d67f3b96SBen Skeggs }
460d67f3b96SBen Skeggs
461d67f3b96SBen Skeggs const struct nvkm_event_func
462d67f3b96SBen Skeggs gf100_fifo_nonstall = {
463d67f3b96SBen Skeggs .init = gf100_fifo_nonstall_allow,
464d67f3b96SBen Skeggs .fini = gf100_fifo_nonstall_block,
465d67f3b96SBen Skeggs };
466d67f3b96SBen Skeggs
46705c7145dSBen Skeggs static const struct nvkm_enum
468e43c872cSBen Skeggs gf100_fifo_mmu_fault_engine[] = {
469cf9518b5SBen Skeggs { 0x00, "PGRAPH", NULL, NVKM_ENGINE_GR },
470cf9518b5SBen Skeggs { 0x03, "PEEPHOLE", NULL, NVKM_ENGINE_IFB },
471cf9518b5SBen Skeggs { 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR },
472cf9518b5SBen Skeggs { 0x05, "BAR3", NULL, NVKM_SUBDEV_INSTMEM },
4734d60100aSBen Skeggs { 0x07, "PFIFO" },
474cf9518b5SBen Skeggs { 0x10, "PMSVLD", NULL, NVKM_ENGINE_MSVLD },
475cf9518b5SBen Skeggs { 0x11, "PMSPPP", NULL, NVKM_ENGINE_MSPPP },
476cf9518b5SBen Skeggs { 0x13, "PCOUNTER" },
477cf9518b5SBen Skeggs { 0x14, "PMSPDEC", NULL, NVKM_ENGINE_MSPDEC },
478088bfe43SBen Skeggs { 0x15, "PCE0", NULL, NVKM_ENGINE_CE, 0 },
479088bfe43SBen Skeggs { 0x16, "PCE1", NULL, NVKM_ENGINE_CE, 1 },
480cf9518b5SBen Skeggs { 0x17, "PMU" },
481cf9518b5SBen Skeggs {}
482cf9518b5SBen Skeggs };
483cf9518b5SBen Skeggs
484cf9518b5SBen Skeggs static const struct nvkm_enum
485e43c872cSBen Skeggs gf100_fifo_mmu_fault_reason[] = {
486cf9518b5SBen Skeggs { 0x00, "PT_NOT_PRESENT" },
487cf9518b5SBen Skeggs { 0x01, "PT_TOO_SHORT" },
488cf9518b5SBen Skeggs { 0x02, "PAGE_NOT_PRESENT" },
489cf9518b5SBen Skeggs { 0x03, "VM_LIMIT_EXCEEDED" },
490cf9518b5SBen Skeggs { 0x04, "NO_CHANNEL" },
491cf9518b5SBen Skeggs { 0x05, "PAGE_SYSTEM_ONLY" },
492cf9518b5SBen Skeggs { 0x06, "PAGE_READ_ONLY" },
493cf9518b5SBen Skeggs { 0x0a, "COMPRESSED_SYSRAM" },
494cf9518b5SBen Skeggs { 0x0c, "INVALID_STORAGE_TYPE" },
495cf9518b5SBen Skeggs {}
496cf9518b5SBen Skeggs };
497cf9518b5SBen Skeggs
498cf9518b5SBen Skeggs static const struct nvkm_enum
499e43c872cSBen Skeggs gf100_fifo_mmu_fault_hubclient[] = {
500cf9518b5SBen Skeggs { 0x01, "PCOPY0" },
501cf9518b5SBen Skeggs { 0x02, "PCOPY1" },
502cf9518b5SBen Skeggs { 0x04, "DISPATCH" },
503cf9518b5SBen Skeggs { 0x05, "CTXCTL" },
504cf9518b5SBen Skeggs { 0x06, "PFIFO" },
505cf9518b5SBen Skeggs { 0x07, "BAR_READ" },
506cf9518b5SBen Skeggs { 0x08, "BAR_WRITE" },
507cf9518b5SBen Skeggs { 0x0b, "PVP" },
508cf9518b5SBen Skeggs { 0x0c, "PMSPPP" },
509cf9518b5SBen Skeggs { 0x0d, "PMSVLD" },
510cf9518b5SBen Skeggs { 0x11, "PCOUNTER" },
511cf9518b5SBen Skeggs { 0x12, "PMU" },
512cf9518b5SBen Skeggs { 0x14, "CCACHE" },
513cf9518b5SBen Skeggs { 0x15, "CCACHE_POST" },
514cf9518b5SBen Skeggs {}
515cf9518b5SBen Skeggs };
516cf9518b5SBen Skeggs
517cf9518b5SBen Skeggs static const struct nvkm_enum
518e43c872cSBen Skeggs gf100_fifo_mmu_fault_gpcclient[] = {
519cf9518b5SBen Skeggs { 0x01, "TEX" },
520cf9518b5SBen Skeggs { 0x0c, "ESETUP" },
521cf9518b5SBen Skeggs { 0x0e, "CTXCTL" },
522cf9518b5SBen Skeggs { 0x0f, "PROP" },
523cf9518b5SBen Skeggs {}
524cf9518b5SBen Skeggs };
525cf9518b5SBen Skeggs
526e43c872cSBen Skeggs const struct nvkm_enum
527e43c872cSBen Skeggs gf100_fifo_mmu_fault_access[] = {
528e43c872cSBen Skeggs { 0x00, "READ" },
529e43c872cSBen Skeggs { 0x01, "WRITE" },
530e43c872cSBen Skeggs {}
531e43c872cSBen Skeggs };
532e43c872cSBen Skeggs
533e43c872cSBen Skeggs void
gf100_fifo_mmu_fault_recover(struct nvkm_fifo * fifo,struct nvkm_fault_data * info)534e43c872cSBen Skeggs gf100_fifo_mmu_fault_recover(struct nvkm_fifo *fifo, struct nvkm_fault_data *info)
535cf9518b5SBen Skeggs {
536e43c872cSBen Skeggs struct nvkm_subdev *subdev = &fifo->engine.subdev;
537cf9518b5SBen Skeggs struct nvkm_device *device = subdev->device;
538e43c872cSBen Skeggs const struct nvkm_enum *er, *ee, *ec, *ea;
539cf9518b5SBen Skeggs struct nvkm_engine *engine = NULL;
540e43c872cSBen Skeggs struct nvkm_runl *runl;
541e43c872cSBen Skeggs struct nvkm_engn *engn;
542c358f538SBen Skeggs struct nvkm_chan *chan;
543cf9518b5SBen Skeggs unsigned long flags;
544e43c872cSBen Skeggs char ct[8] = "HUB/";
545cf9518b5SBen Skeggs
546e43c872cSBen Skeggs /* Lookup engine by MMU fault ID. */
547e43c872cSBen Skeggs nvkm_runl_foreach(runl, fifo) {
548e43c872cSBen Skeggs engn = nvkm_runl_find_engn(engn, runl, engn->fault == info->engine);
549e43c872cSBen Skeggs if (engn) {
5504d60100aSBen Skeggs /* Fault triggered by CTXSW_TIMEOUT recovery procedure. */
5514d60100aSBen Skeggs if (engn->func->mmu_fault_triggered &&
5524d60100aSBen Skeggs engn->func->mmu_fault_triggered(engn)) {
5534d60100aSBen Skeggs nvkm_runl_rc_engn(runl, engn);
5544d60100aSBen Skeggs return;
5554d60100aSBen Skeggs }
5564d60100aSBen Skeggs
557e43c872cSBen Skeggs engine = engn->engine;
558e43c872cSBen Skeggs break;
559e43c872cSBen Skeggs }
560cf9518b5SBen Skeggs }
561cf9518b5SBen Skeggs
562e43c872cSBen Skeggs er = nvkm_enum_find(fifo->func->mmu_fault->reason, info->reason);
563e43c872cSBen Skeggs ee = nvkm_enum_find(fifo->func->mmu_fault->engine, info->engine);
564e43c872cSBen Skeggs if (info->hub) {
565e43c872cSBen Skeggs ec = nvkm_enum_find(fifo->func->mmu_fault->hubclient, info->client);
566e43c872cSBen Skeggs } else {
567e43c872cSBen Skeggs ec = nvkm_enum_find(fifo->func->mmu_fault->gpcclient, info->client);
568e43c872cSBen Skeggs snprintf(ct, sizeof(ct), "GPC%d/", info->gpc);
569e43c872cSBen Skeggs }
570e43c872cSBen Skeggs ea = nvkm_enum_find(fifo->func->mmu_fault->access, info->access);
571e43c872cSBen Skeggs
572e43c872cSBen Skeggs /* Handle BAR faults. */
573e43c872cSBen Skeggs if (ee && ee->data2) {
574e43c872cSBen Skeggs switch (ee->data2) {
575cf9518b5SBen Skeggs case NVKM_SUBDEV_BAR:
576cf9518b5SBen Skeggs nvkm_bar_bar1_reset(device);
577cf9518b5SBen Skeggs break;
578cf9518b5SBen Skeggs case NVKM_SUBDEV_INSTMEM:
579cf9518b5SBen Skeggs nvkm_bar_bar2_reset(device);
580cf9518b5SBen Skeggs break;
581cf9518b5SBen Skeggs case NVKM_ENGINE_IFB:
582cf9518b5SBen Skeggs nvkm_mask(device, 0x001718, 0x00000000, 0x00000000);
583cf9518b5SBen Skeggs break;
584cf9518b5SBen Skeggs default:
585cf9518b5SBen Skeggs break;
586cf9518b5SBen Skeggs }
587cf9518b5SBen Skeggs }
588cf9518b5SBen Skeggs
589c358f538SBen Skeggs chan = nvkm_chan_get_inst(&fifo->engine, info->inst, &flags);
590cf9518b5SBen Skeggs
591cf9518b5SBen Skeggs nvkm_error(subdev,
592e43c872cSBen Skeggs "fault %02x [%s] at %016llx engine %02x [%s] client %02x "
593e43c872cSBen Skeggs "[%s%s] reason %02x [%s] on channel %d [%010llx %s]\n",
594e43c872cSBen Skeggs info->access, ea ? ea->name : "", info->addr,
595e43c872cSBen Skeggs info->engine, ee ? ee->name : engine ? engine->subdev.name : "",
596e43c872cSBen Skeggs info->client, ct, ec ? ec->name : "",
597e43c872cSBen Skeggs info->reason, er ? er->name : "",
598e43c872cSBen Skeggs chan ? chan->id : -1, info->inst, chan ? chan->name : "unknown");
599cf9518b5SBen Skeggs
600e43c872cSBen Skeggs /* Handle host/engine faults. */
6014d60100aSBen Skeggs if (chan)
6024d60100aSBen Skeggs nvkm_runl_rc_cgrp(chan->cgrp);
603e43c872cSBen Skeggs
604c358f538SBen Skeggs nvkm_chan_put(&chan, flags);
605cf9518b5SBen Skeggs }
606cf9518b5SBen Skeggs
6079be9c606SBen Skeggs static const struct nvkm_fifo_func_mmu_fault
6089be9c606SBen Skeggs gf100_fifo_mmu_fault = {
609e43c872cSBen Skeggs .recover = gf100_fifo_mmu_fault_recover,
610e43c872cSBen Skeggs .access = gf100_fifo_mmu_fault_access,
611e43c872cSBen Skeggs .engine = gf100_fifo_mmu_fault_engine,
612e43c872cSBen Skeggs .reason = gf100_fifo_mmu_fault_reason,
613e43c872cSBen Skeggs .hubclient = gf100_fifo_mmu_fault_hubclient,
614e43c872cSBen Skeggs .gpcclient = gf100_fifo_mmu_fault_gpcclient,
6159be9c606SBen Skeggs };
6169be9c606SBen Skeggs
6174d60100aSBen Skeggs void
gf100_fifo_intr_ctxsw_timeout(struct nvkm_fifo * fifo,u32 engm)6184d60100aSBen Skeggs gf100_fifo_intr_ctxsw_timeout(struct nvkm_fifo *fifo, u32 engm)
6194d60100aSBen Skeggs {
6204d60100aSBen Skeggs struct nvkm_runl *runl;
6214d60100aSBen Skeggs struct nvkm_engn *engn, *engn2;
6224d60100aSBen Skeggs bool cgid, cgid2;
6234d60100aSBen Skeggs int id, id2;
6244d60100aSBen Skeggs
6254d60100aSBen Skeggs nvkm_runl_foreach(runl, fifo) {
6264d60100aSBen Skeggs /* Stop the runlist, and go through all engines serving it. */
6274d60100aSBen Skeggs nvkm_runl_block(runl);
6284d60100aSBen Skeggs nvkm_runl_foreach_engn_cond(engn, runl, engm & BIT(engn->id)) {
6294d60100aSBen Skeggs /* Determine what channel (group) the engine is on. */
6304d60100aSBen Skeggs id = engn->func->cxid(engn, &cgid);
6314d60100aSBen Skeggs if (id >= 0) {
6324d60100aSBen Skeggs /* Trigger MMU fault on any engine(s) on that channel (group). */
6334d60100aSBen Skeggs nvkm_runl_foreach_engn_cond(engn2, runl, engn2->func->cxid) {
6344d60100aSBen Skeggs id2 = engn2->func->cxid(engn2, &cgid2);
6354d60100aSBen Skeggs if (cgid2 == cgid && id2 == id)
6364d60100aSBen Skeggs engn2->func->mmu_fault_trigger(engn2);
6374d60100aSBen Skeggs }
6384d60100aSBen Skeggs }
6394d60100aSBen Skeggs }
6404d60100aSBen Skeggs nvkm_runl_allow(runl); /* HW will keep runlist blocked via ERROR_SCHED_DISABLE. */
6414d60100aSBen Skeggs }
6424d60100aSBen Skeggs }
6434d60100aSBen Skeggs
6444d60100aSBen Skeggs static void
gf100_fifo_intr_sched_ctxsw(struct nvkm_fifo * fifo)6454d60100aSBen Skeggs gf100_fifo_intr_sched_ctxsw(struct nvkm_fifo *fifo)
6464d60100aSBen Skeggs {
6474d60100aSBen Skeggs struct nvkm_runl *runl;
6484d60100aSBen Skeggs struct nvkm_engn *engn;
6494d60100aSBen Skeggs u32 engm = 0;
6504d60100aSBen Skeggs
6514d60100aSBen Skeggs /* Look for any engines that are busy, and awaiting chsw ack. */
6524d60100aSBen Skeggs nvkm_runl_foreach(runl, fifo) {
6534d60100aSBen Skeggs nvkm_runl_foreach_engn_cond(engn, runl, engn->func->chsw) {
6544d60100aSBen Skeggs if (WARN_ON(engn->fault < 0) || !engn->func->chsw(engn))
6554d60100aSBen Skeggs continue;
6564d60100aSBen Skeggs
6574d60100aSBen Skeggs engm |= BIT(engn->id);
6584d60100aSBen Skeggs }
6594d60100aSBen Skeggs }
6604d60100aSBen Skeggs
6614d60100aSBen Skeggs if (!engm)
6624d60100aSBen Skeggs return;
6634d60100aSBen Skeggs
6644d60100aSBen Skeggs fifo->func->intr_ctxsw_timeout(fifo, engm);
6654d60100aSBen Skeggs }
6664d60100aSBen Skeggs
667cf9518b5SBen Skeggs static const struct nvkm_enum
6684d60100aSBen Skeggs gf100_fifo_intr_sched_names[] = {
66905c7145dSBen Skeggs { 0x0a, "CTXSW_TIMEOUT" },
67005c7145dSBen Skeggs {}
67105c7145dSBen Skeggs };
67205c7145dSBen Skeggs
6734d60100aSBen Skeggs void
gf100_fifo_intr_sched(struct nvkm_fifo * fifo)6744d60100aSBen Skeggs gf100_fifo_intr_sched(struct nvkm_fifo *fifo)
67505c7145dSBen Skeggs {
6764d60100aSBen Skeggs struct nvkm_subdev *subdev = &fifo->engine.subdev;
677e5c5e4f5SBen Skeggs struct nvkm_device *device = subdev->device;
67887744403SBen Skeggs u32 intr = nvkm_rd32(device, 0x00254c);
67905c7145dSBen Skeggs u32 code = intr & 0x000000ff;
68005c7145dSBen Skeggs const struct nvkm_enum *en;
68105c7145dSBen Skeggs
6824d60100aSBen Skeggs en = nvkm_enum_find(gf100_fifo_intr_sched_names, code);
68305c7145dSBen Skeggs
684e5c5e4f5SBen Skeggs nvkm_error(subdev, "SCHED_ERROR %02x [%s]\n", code, en ? en->name : "");
68505c7145dSBen Skeggs
68605c7145dSBen Skeggs switch (code) {
68705c7145dSBen Skeggs case 0x0a:
6886189f1b0SBen Skeggs gf100_fifo_intr_sched_ctxsw(fifo);
68905c7145dSBen Skeggs break;
69005c7145dSBen Skeggs default:
69105c7145dSBen Skeggs break;
69205c7145dSBen Skeggs }
69305c7145dSBen Skeggs }
69405c7145dSBen Skeggs
695cf9518b5SBen Skeggs void
gf100_fifo_intr_mmu_fault_unit(struct nvkm_fifo * fifo,int unit)6969be9c606SBen Skeggs gf100_fifo_intr_mmu_fault_unit(struct nvkm_fifo *fifo, int unit)
69705c7145dSBen Skeggs {
698cf9518b5SBen Skeggs struct nvkm_device *device = fifo->engine.subdev.device;
69987744403SBen Skeggs u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10));
70087744403SBen Skeggs u32 valo = nvkm_rd32(device, 0x002804 + (unit * 0x10));
70187744403SBen Skeggs u32 vahi = nvkm_rd32(device, 0x002808 + (unit * 0x10));
702cf9518b5SBen Skeggs u32 type = nvkm_rd32(device, 0x00280c + (unit * 0x10));
703cf9518b5SBen Skeggs struct nvkm_fault_data info;
70405c7145dSBen Skeggs
705cf9518b5SBen Skeggs info.inst = (u64)inst << 12;
706cf9518b5SBen Skeggs info.addr = ((u64)vahi << 32) | valo;
707cf9518b5SBen Skeggs info.time = 0;
708cf9518b5SBen Skeggs info.engine = unit;
709cf9518b5SBen Skeggs info.valid = 1;
710cf9518b5SBen Skeggs info.gpc = (type & 0x1f000000) >> 24;
711cf9518b5SBen Skeggs info.client = (type & 0x00001f00) >> 8;
712cf9518b5SBen Skeggs info.access = (type & 0x00000080) >> 7;
713cf9518b5SBen Skeggs info.hub = (type & 0x00000040) >> 6;
714cf9518b5SBen Skeggs info.reason = (type & 0x0000000f);
715e5c5e4f5SBen Skeggs
716cf9518b5SBen Skeggs nvkm_fifo_fault(fifo, &info);
71705c7145dSBen Skeggs }
71805c7145dSBen Skeggs
719e43c872cSBen Skeggs void
gf100_fifo_intr_mmu_fault(struct nvkm_fifo * fifo)720e43c872cSBen Skeggs gf100_fifo_intr_mmu_fault(struct nvkm_fifo *fifo)
721e43c872cSBen Skeggs {
722e43c872cSBen Skeggs struct nvkm_device *device = fifo->engine.subdev.device;
723e43c872cSBen Skeggs unsigned long mask = nvkm_rd32(device, 0x00259c);
724e43c872cSBen Skeggs int unit;
725e43c872cSBen Skeggs
726e43c872cSBen Skeggs for_each_set_bit(unit, &mask, 32) {
727e43c872cSBen Skeggs fifo->func->intr_mmu_fault_unit(fifo, unit);
728e43c872cSBen Skeggs nvkm_wr32(device, 0x00259c, BIT(unit));
729e43c872cSBen Skeggs }
730e43c872cSBen Skeggs }
731e43c872cSBen Skeggs
732923f1ff5SBen Skeggs bool
gf100_fifo_intr_pbdma(struct nvkm_fifo * fifo)733923f1ff5SBen Skeggs gf100_fifo_intr_pbdma(struct nvkm_fifo *fifo)
734923f1ff5SBen Skeggs {
735923f1ff5SBen Skeggs struct nvkm_device *device = fifo->engine.subdev.device;
736923f1ff5SBen Skeggs struct nvkm_runq *runq;
737923f1ff5SBen Skeggs u32 mask = nvkm_rd32(device, 0x0025a0);
738923f1ff5SBen Skeggs bool handled = false;
739923f1ff5SBen Skeggs
740923f1ff5SBen Skeggs nvkm_runq_foreach_cond(runq, fifo, mask & BIT(runq->id)) {
741923f1ff5SBen Skeggs if (runq->func->intr(runq, NULL))
742923f1ff5SBen Skeggs handled = true;
743923f1ff5SBen Skeggs
744923f1ff5SBen Skeggs nvkm_wr32(device, 0x0025a0, BIT(runq->id));
745923f1ff5SBen Skeggs }
746923f1ff5SBen Skeggs
747923f1ff5SBen Skeggs return handled;
748923f1ff5SBen Skeggs }
749923f1ff5SBen Skeggs
75005c7145dSBen Skeggs static void
gf100_fifo_intr_runlist(struct nvkm_fifo * fifo)7514a492fd5SBen Skeggs gf100_fifo_intr_runlist(struct nvkm_fifo *fifo)
75205c7145dSBen Skeggs {
7534a492fd5SBen Skeggs struct nvkm_subdev *subdev = &fifo->engine.subdev;
754e5c5e4f5SBen Skeggs struct nvkm_device *device = subdev->device;
75587744403SBen Skeggs u32 intr = nvkm_rd32(device, 0x002a00);
75605c7145dSBen Skeggs
75705c7145dSBen Skeggs if (intr & 0x10000000) {
75887744403SBen Skeggs nvkm_wr32(device, 0x002a00, 0x10000000);
75905c7145dSBen Skeggs intr &= ~0x10000000;
76005c7145dSBen Skeggs }
76105c7145dSBen Skeggs
76205c7145dSBen Skeggs if (intr) {
763e5c5e4f5SBen Skeggs nvkm_error(subdev, "RUNLIST %08x\n", intr);
76487744403SBen Skeggs nvkm_wr32(device, 0x002a00, intr);
76505c7145dSBen Skeggs }
76605c7145dSBen Skeggs }
76705c7145dSBen Skeggs
76805c7145dSBen Skeggs static void
gf100_fifo_intr_engine_unit(struct nvkm_fifo * fifo,int engn)769d67f3b96SBen Skeggs gf100_fifo_intr_engine_unit(struct nvkm_fifo *fifo, int engn)
77005c7145dSBen Skeggs {
771d67f3b96SBen Skeggs struct nvkm_subdev *subdev = &fifo->engine.subdev;
772e5c5e4f5SBen Skeggs struct nvkm_device *device = subdev->device;
77387744403SBen Skeggs u32 intr = nvkm_rd32(device, 0x0025a8 + (engn * 0x04));
77487744403SBen Skeggs u32 inte = nvkm_rd32(device, 0x002628);
77505c7145dSBen Skeggs u32 unkn;
77605c7145dSBen Skeggs
77787744403SBen Skeggs nvkm_wr32(device, 0x0025a8 + (engn * 0x04), intr);
77805c7145dSBen Skeggs
77905c7145dSBen Skeggs for (unkn = 0; unkn < 8; unkn++) {
78005c7145dSBen Skeggs u32 ints = (intr >> (unkn * 0x04)) & inte;
78105c7145dSBen Skeggs if (ints & 0x1) {
782d67f3b96SBen Skeggs nvkm_event_ntfy(&fifo->nonstall.event, 0, NVKM_FIFO_NONSTALL_EVENT);
78305c7145dSBen Skeggs ints &= ~1;
78405c7145dSBen Skeggs }
78505c7145dSBen Skeggs if (ints) {
786d67f3b96SBen Skeggs nvkm_error(subdev, "ENGINE %d %d %01x", engn, unkn, ints);
78787744403SBen Skeggs nvkm_mask(device, 0x002628, ints, 0);
78805c7145dSBen Skeggs }
78905c7145dSBen Skeggs }
79005c7145dSBen Skeggs }
79105c7145dSBen Skeggs
79262742b5eSBen Skeggs static void
gf100_fifo_intr_engine(struct nvkm_fifo * fifo)79362742b5eSBen Skeggs gf100_fifo_intr_engine(struct nvkm_fifo *fifo)
79405c7145dSBen Skeggs {
79562742b5eSBen Skeggs struct nvkm_device *device = fifo->engine.subdev.device;
79687744403SBen Skeggs u32 mask = nvkm_rd32(device, 0x0025a4);
797d67f3b96SBen Skeggs
79805c7145dSBen Skeggs while (mask) {
79905c7145dSBen Skeggs u32 unit = __ffs(mask);
80062742b5eSBen Skeggs gf100_fifo_intr_engine_unit(fifo, unit);
80105c7145dSBen Skeggs mask &= ~(1 << unit);
80205c7145dSBen Skeggs }
80305c7145dSBen Skeggs }
80405c7145dSBen Skeggs
8052fc71a05SBen Skeggs static irqreturn_t
gf100_fifo_intr(struct nvkm_inth * inth)8062fc71a05SBen Skeggs gf100_fifo_intr(struct nvkm_inth *inth)
80705c7145dSBen Skeggs {
8082fc71a05SBen Skeggs struct nvkm_fifo *fifo = container_of(inth, typeof(*fifo), engine.subdev.inth);
8092fc71a05SBen Skeggs struct nvkm_subdev *subdev = &fifo->engine.subdev;
81013de7f46SBen Skeggs struct nvkm_device *device = subdev->device;
81187744403SBen Skeggs u32 mask = nvkm_rd32(device, 0x002140);
81287744403SBen Skeggs u32 stat = nvkm_rd32(device, 0x002100) & mask;
81305c7145dSBen Skeggs
81405c7145dSBen Skeggs if (stat & 0x00000001) {
81587744403SBen Skeggs u32 intr = nvkm_rd32(device, 0x00252c);
816e5c5e4f5SBen Skeggs nvkm_warn(subdev, "INTR 00000001: %08x\n", intr);
81787744403SBen Skeggs nvkm_wr32(device, 0x002100, 0x00000001);
81805c7145dSBen Skeggs stat &= ~0x00000001;
81905c7145dSBen Skeggs }
82005c7145dSBen Skeggs
82105c7145dSBen Skeggs if (stat & 0x00000100) {
8224d60100aSBen Skeggs gf100_fifo_intr_sched(fifo);
82387744403SBen Skeggs nvkm_wr32(device, 0x002100, 0x00000100);
82405c7145dSBen Skeggs stat &= ~0x00000100;
82505c7145dSBen Skeggs }
82605c7145dSBen Skeggs
82705c7145dSBen Skeggs if (stat & 0x00010000) {
82887744403SBen Skeggs u32 intr = nvkm_rd32(device, 0x00256c);
829e5c5e4f5SBen Skeggs nvkm_warn(subdev, "INTR 00010000: %08x\n", intr);
83087744403SBen Skeggs nvkm_wr32(device, 0x002100, 0x00010000);
83105c7145dSBen Skeggs stat &= ~0x00010000;
83205c7145dSBen Skeggs }
83305c7145dSBen Skeggs
83405c7145dSBen Skeggs if (stat & 0x01000000) {
83587744403SBen Skeggs u32 intr = nvkm_rd32(device, 0x00258c);
836e5c5e4f5SBen Skeggs nvkm_warn(subdev, "INTR 01000000: %08x\n", intr);
83787744403SBen Skeggs nvkm_wr32(device, 0x002100, 0x01000000);
83805c7145dSBen Skeggs stat &= ~0x01000000;
83905c7145dSBen Skeggs }
84005c7145dSBen Skeggs
84105c7145dSBen Skeggs if (stat & 0x10000000) {
842e43c872cSBen Skeggs gf100_fifo_intr_mmu_fault(fifo);
84305c7145dSBen Skeggs stat &= ~0x10000000;
84405c7145dSBen Skeggs }
84505c7145dSBen Skeggs
84605c7145dSBen Skeggs if (stat & 0x20000000) {
847923f1ff5SBen Skeggs if (gf100_fifo_intr_pbdma(fifo))
84805c7145dSBen Skeggs stat &= ~0x20000000;
84905c7145dSBen Skeggs }
85005c7145dSBen Skeggs
85105c7145dSBen Skeggs if (stat & 0x40000000) {
8524a492fd5SBen Skeggs gf100_fifo_intr_runlist(fifo);
85305c7145dSBen Skeggs stat &= ~0x40000000;
85405c7145dSBen Skeggs }
85505c7145dSBen Skeggs
85605c7145dSBen Skeggs if (stat & 0x80000000) {
85762742b5eSBen Skeggs gf100_fifo_intr_engine(fifo);
85805c7145dSBen Skeggs stat &= ~0x80000000;
85905c7145dSBen Skeggs }
86005c7145dSBen Skeggs
86105c7145dSBen Skeggs if (stat) {
862e5c5e4f5SBen Skeggs nvkm_error(subdev, "INTR %08x\n", stat);
863d67f3b96SBen Skeggs spin_lock(&fifo->lock);
86487744403SBen Skeggs nvkm_mask(device, 0x002140, stat, 0x00000000);
865d67f3b96SBen Skeggs spin_unlock(&fifo->lock);
86687744403SBen Skeggs nvkm_wr32(device, 0x002100, stat);
86705c7145dSBen Skeggs }
8682fc71a05SBen Skeggs
8692fc71a05SBen Skeggs return IRQ_HANDLED;
87005c7145dSBen Skeggs }
87105c7145dSBen Skeggs
87213de7f46SBen Skeggs static void
gf100_fifo_init_pbdmas(struct nvkm_fifo * fifo,u32 mask)873965c41d9SBen Skeggs gf100_fifo_init_pbdmas(struct nvkm_fifo *fifo, u32 mask)
87413de7f46SBen Skeggs {
875965c41d9SBen Skeggs struct nvkm_device *device = fifo->engine.subdev.device;
87613de7f46SBen Skeggs
877adbe24a2SBen Skeggs /* Enable PBDMAs. */
878965c41d9SBen Skeggs nvkm_wr32(device, 0x000204, mask);
879965c41d9SBen Skeggs nvkm_wr32(device, 0x002204, mask);
8809a65a38cSBen Skeggs
881adbe24a2SBen Skeggs /* Assign engines to PBDMAs. */
882965c41d9SBen Skeggs if ((mask & 7) == 7) {
8839a65a38cSBen Skeggs nvkm_wr32(device, 0x002208, ~(1 << 0)); /* PGRAPH */
8849a65a38cSBen Skeggs nvkm_wr32(device, 0x00220c, ~(1 << 1)); /* PVP */
8859a65a38cSBen Skeggs nvkm_wr32(device, 0x002210, ~(1 << 1)); /* PMSPP */
8869a65a38cSBen Skeggs nvkm_wr32(device, 0x002214, ~(1 << 1)); /* PMSVLD */
8879a65a38cSBen Skeggs nvkm_wr32(device, 0x002218, ~(1 << 2)); /* PCE0 */
8889a65a38cSBen Skeggs nvkm_wr32(device, 0x00221c, ~(1 << 1)); /* PCE1 */
8899a65a38cSBen Skeggs }
8909a65a38cSBen Skeggs
891324176e7SBen Skeggs nvkm_mask(device, 0x002a04, 0xbfffffff, 0xbfffffff);
892965c41d9SBen Skeggs }
893965c41d9SBen Skeggs
894965c41d9SBen Skeggs static void
gf100_fifo_init(struct nvkm_fifo * fifo)895fbe9f433SBen Skeggs gf100_fifo_init(struct nvkm_fifo *fifo)
896965c41d9SBen Skeggs {
897fbe9f433SBen Skeggs struct nvkm_device *device = fifo->engine.subdev.device;
8989a65a38cSBen Skeggs
8999a65a38cSBen Skeggs nvkm_mask(device, 0x002200, 0x00000001, 0x00000001);
900fbe9f433SBen Skeggs nvkm_wr32(device, 0x002254, 0x10000000 | fifo->userd.bar1->addr >> 12);
9019a65a38cSBen Skeggs
9029a65a38cSBen Skeggs nvkm_wr32(device, 0x002100, 0xffffffff);
9039a65a38cSBen Skeggs nvkm_wr32(device, 0x002140, 0x7fffffff);
9049a65a38cSBen Skeggs nvkm_wr32(device, 0x002628, 0x00000001); /* ENGINE_INTR_EN */
90505c7145dSBen Skeggs }
90605c7145dSBen Skeggs
907d94470e9SBen Skeggs static int
gf100_fifo_runl_ctor(struct nvkm_fifo * fifo)908d94470e9SBen Skeggs gf100_fifo_runl_ctor(struct nvkm_fifo *fifo)
909d94470e9SBen Skeggs {
910d94470e9SBen Skeggs struct nvkm_runl *runl;
911d94470e9SBen Skeggs
912d94470e9SBen Skeggs runl = nvkm_runl_new(fifo, 0, 0, 0);
913d94470e9SBen Skeggs if (IS_ERR(runl))
914d94470e9SBen Skeggs return PTR_ERR(runl);
915d94470e9SBen Skeggs
916d94470e9SBen Skeggs nvkm_runl_add(runl, 0, fifo->func->engn, NVKM_ENGINE_GR, 0);
917d94470e9SBen Skeggs nvkm_runl_add(runl, 1, fifo->func->engn, NVKM_ENGINE_MSPDEC, 0);
918d94470e9SBen Skeggs nvkm_runl_add(runl, 2, fifo->func->engn, NVKM_ENGINE_MSPPP, 0);
919d94470e9SBen Skeggs nvkm_runl_add(runl, 3, fifo->func->engn, NVKM_ENGINE_MSVLD, 0);
920d94470e9SBen Skeggs nvkm_runl_add(runl, 4, fifo->func->engn, NVKM_ENGINE_CE, 0);
921d94470e9SBen Skeggs nvkm_runl_add(runl, 5, fifo->func->engn, NVKM_ENGINE_CE, 1);
922d94470e9SBen Skeggs nvkm_runl_add(runl, 15, &gf100_engn_sw, NVKM_ENGINE_SW, 0);
923d94470e9SBen Skeggs return 0;
924d94470e9SBen Skeggs }
925d94470e9SBen Skeggs
926800ac1f8SBen Skeggs int
gf100_fifo_runq_nr(struct nvkm_fifo * fifo)9271c488ba9SBen Skeggs gf100_fifo_runq_nr(struct nvkm_fifo *fifo)
9281c488ba9SBen Skeggs {
9291c488ba9SBen Skeggs struct nvkm_device *device = fifo->engine.subdev.device;
9301c488ba9SBen Skeggs u32 save;
9311c488ba9SBen Skeggs
9321c488ba9SBen Skeggs /* Determine number of PBDMAs by checking valid enable bits. */
9331c488ba9SBen Skeggs save = nvkm_mask(device, 0x000204, 0xffffffff, 0xffffffff);
9341c488ba9SBen Skeggs save = nvkm_mask(device, 0x000204, 0xffffffff, save);
9351c488ba9SBen Skeggs return hweight32(save);
9361c488ba9SBen Skeggs }
9371c488ba9SBen Skeggs
9381c488ba9SBen Skeggs int
gf100_fifo_chid_ctor(struct nvkm_fifo * fifo,int nr)939800ac1f8SBen Skeggs gf100_fifo_chid_ctor(struct nvkm_fifo *fifo, int nr)
940800ac1f8SBen Skeggs {
941800ac1f8SBen Skeggs return nvkm_chid_new(&nvkm_chan_event, &fifo->engine.subdev, nr, 0, nr, &fifo->chid);
942800ac1f8SBen Skeggs }
943800ac1f8SBen Skeggs
9448f0649b5SBen Skeggs static const struct nvkm_fifo_func
94513de7f46SBen Skeggs gf100_fifo = {
9468c18138cSBen Skeggs .chid_nr = nv50_fifo_chid_nr,
947800ac1f8SBen Skeggs .chid_ctor = gf100_fifo_chid_ctor,
9481c488ba9SBen Skeggs .runq_nr = gf100_fifo_runq_nr,
949d94470e9SBen Skeggs .runl_ctor = gf100_fifo_runl_ctor,
95013de7f46SBen Skeggs .init = gf100_fifo_init,
951965c41d9SBen Skeggs .init_pbdmas = gf100_fifo_init_pbdmas,
95213de7f46SBen Skeggs .intr = gf100_fifo_intr,
953e43c872cSBen Skeggs .intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit,
9544d60100aSBen Skeggs .intr_ctxsw_timeout = gf100_fifo_intr_ctxsw_timeout,
9559be9c606SBen Skeggs .mmu_fault = &gf100_fifo_mmu_fault,
956d67f3b96SBen Skeggs .nonstall = &gf100_fifo_nonstall,
957d94470e9SBen Skeggs .runl = &gf100_runl,
9581c488ba9SBen Skeggs .runq = &gf100_runq,
959d94470e9SBen Skeggs .engn = &gf100_engn,
960f5e45689SBen Skeggs .cgrp = {{ }, &nv04_cgrp },
96106db7fdeSBen Skeggs .chan = {{ 0, 0, FERMI_CHANNEL_GPFIFO }, &gf100_chan },
9628f0649b5SBen Skeggs };
9638f0649b5SBen Skeggs
96413de7f46SBen Skeggs int
gf100_fifo_new(struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_fifo ** pfifo)965ab0db2bdSBen Skeggs gf100_fifo_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
966ab0db2bdSBen Skeggs struct nvkm_fifo **pfifo)
96705c7145dSBen Skeggs {
96806db7fdeSBen Skeggs return nvkm_fifo_new_(&gf100_fifo, device, type, inst, pfifo);
96905c7145dSBen Skeggs }
970