summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Courbot <acourbot@nvidia.com>2015-04-16 11:33:32 +0900
committerAlexandre Courbot <acourbot@nvidia.com>2015-06-08 17:42:18 +0900
commit8caa6bad9ab78dbb08aae45bc85fd8e97cf0c23a (patch)
tree8f5cbdaea12eb7710997e2903c818fcf3e600652
parent89467baf290113a3036e0bbf158e51dba3b8738e (diff)
downloadnouveau-8caa6bad9ab78dbb08aae45bc85fd8e97cf0c23a.tar.gz
fifo/gk104: kick channels when deactivating them
Kicking channels is part of their deactivation process. Maxwell chips are particularly sensitive to this, and can start fetching the previous pushbuffer of a recycled channel if this is not done. While we are at it, improve the channel preemption code to only wait for bit 20 of 0x002634 to turn to 0, as it is the bit indicating a preempt is pending. Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
-rw-r--r--drm/nouveau/nvkm/engine/fifo/gk104.c29
1 files changed, 21 insertions, 8 deletions
diff --git a/drm/nouveau/nvkm/engine/fifo/gk104.c b/drm/nouveau/nvkm/engine/fifo/gk104.c
index e10f96441..37a7cbe6b 100644
--- a/drm/nouveau/nvkm/engine/fifo/gk104.c
+++ b/drm/nouveau/nvkm/engine/fifo/gk104.c
@@ -166,14 +166,30 @@ gk104_fifo_context_attach(struct nvkm_object *parent,
}
static int
+gk104_fifo_chan_kick(struct gk104_fifo_chan *chan)
+{
+ struct nvkm_object *obj = (void *)chan;
+ struct gk104_fifo_priv *priv = (void *)obj->engine;
+
+ nv_wr32(priv, 0x002634, chan->base.chid);
+ if (!nv_wait(priv, 0x002634, 0x100000, 0x000000)) {
+ nv_error(priv, "channel %d [%s] kick timeout\n",
+ chan->base.chid, nvkm_client_name(chan));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int
gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend,
struct nvkm_object *object)
{
struct nvkm_bar *bar = nvkm_bar(parent);
- struct gk104_fifo_priv *priv = (void *)parent->engine;
struct gk104_fifo_base *base = (void *)parent->parent;
struct gk104_fifo_chan *chan = (void *)parent;
u32 addr;
+ int err;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
@@ -188,13 +204,9 @@ gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend,
return -EINVAL;
}
- nv_wr32(priv, 0x002634, chan->base.chid);
- if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
- nv_error(priv, "channel %d [%s] kick timeout\n",
- chan->base.chid, nvkm_client_name(chan));
- if (suspend)
- return -EBUSY;
- }
+ err = gk104_fifo_chan_kick(chan);
+ if (err && suspend)
+ return err;
if (addr) {
nv_wo32(base, addr + 0x00, 0x00000000);
@@ -319,6 +331,7 @@ gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend)
gk104_fifo_runlist_update(priv, chan->engine);
}
+ gk104_fifo_chan_kick(chan);
nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000);
return nvkm_fifo_channel_fini(&chan->base, suspend);
}