aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandre Courbot <acourbot@nvidia.com>2015-04-15 22:33:32 -0400
committerBen Skeggs <bskeggs@redhat.com>2015-07-27 04:56:08 -0400
commit1addc12648521d15ef33c1a88d0354850190dfa7 (patch)
tree00e053db68f5d758baa148b09ae860820eb6853f
parent9c56be4cf3d6db5a20c3b6483bd4cdc21c15cf4f (diff)
drm/nouveau/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> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c29
1 files changed, 21 insertions, 8 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
index e10f9644140f..52c22b026005 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
@@ -166,14 +166,30 @@ gk104_fifo_context_attach(struct nvkm_object *parent,
166} 166}
167 167
168static int 168static int
169gk104_fifo_chan_kick(struct gk104_fifo_chan *chan)
170{
171 struct nvkm_object *obj = (void *)chan;
172 struct gk104_fifo_priv *priv = (void *)obj->engine;
173
174 nv_wr32(priv, 0x002634, chan->base.chid);
175 if (!nv_wait(priv, 0x002634, 0x100000, 0x000000)) {
176 nv_error(priv, "channel %d [%s] kick timeout\n",
177 chan->base.chid, nvkm_client_name(chan));
178 return -EBUSY;
179 }
180
181 return 0;
182}
183
184static int
169gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend, 185gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend,
170 struct nvkm_object *object) 186 struct nvkm_object *object)
171{ 187{
172 struct nvkm_bar *bar = nvkm_bar(parent); 188 struct nvkm_bar *bar = nvkm_bar(parent);
173 struct gk104_fifo_priv *priv = (void *)parent->engine;
174 struct gk104_fifo_base *base = (void *)parent->parent; 189 struct gk104_fifo_base *base = (void *)parent->parent;
175 struct gk104_fifo_chan *chan = (void *)parent; 190 struct gk104_fifo_chan *chan = (void *)parent;
176 u32 addr; 191 u32 addr;
192 int ret;
177 193
178 switch (nv_engidx(object->engine)) { 194 switch (nv_engidx(object->engine)) {
179 case NVDEV_ENGINE_SW : return 0; 195 case NVDEV_ENGINE_SW : return 0;
@@ -188,13 +204,9 @@ gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend,
188 return -EINVAL; 204 return -EINVAL;
189 } 205 }
190 206
191 nv_wr32(priv, 0x002634, chan->base.chid); 207 ret = gk104_fifo_chan_kick(chan);
192 if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) { 208 if (ret && suspend)
193 nv_error(priv, "channel %d [%s] kick timeout\n", 209 return ret;
194 chan->base.chid, nvkm_client_name(chan));
195 if (suspend)
196 return -EBUSY;
197 }
198 210
199 if (addr) { 211 if (addr) {
200 nv_wo32(base, addr + 0x00, 0x00000000); 212 nv_wo32(base, addr + 0x00, 0x00000000);
@@ -319,6 +331,7 @@ gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend)
319 gk104_fifo_runlist_update(priv, chan->engine); 331 gk104_fifo_runlist_update(priv, chan->engine);
320 } 332 }
321 333
334 gk104_fifo_chan_kick(chan);
322 nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000); 335 nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000);
323 return nvkm_fifo_channel_fini(&chan->base, suspend); 336 return nvkm_fifo_channel_fini(&chan->base, suspend);
324} 337}