aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrancisco Jerez <currojerez@riseup.net>2010-11-18 17:57:46 -0500
committerFrancisco Jerez <currojerez@riseup.net>2010-12-07 21:00:23 -0500
commit6dccd311dd4b104b3bc53cb67aef414141d11c9f (patch)
tree98cbd0546c1081c76d29184aa7f2510fe19f8f60
parent38cf189fa13e988f85efb6de26315e762cecc260 (diff)
drm/nouveau: Synchronize with the user channel before GPU object destruction.
There have been reports of PFIFO cache errors during context take down (fdo bug 31637). They are caused by some GPU objects being taken out while the channel is still potentially processing commands. Make sure that all the previous rendering has landed before releasing a GPU object. Reported-by: Grzesiek Sójka <pld@pfu.pl> Reported-by: Patrice Mandin <patmandin@gmail.com> Signed-off-by: Francisco Jerez <currojerez@riseup.net> Acked-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_channel.c36
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c16
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_object.c3
4 files changed, 28 insertions, 28 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index 0f33132fba3b..3e49babd62ac 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -284,7 +284,6 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
284 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; 284 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
285 struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt; 285 struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
286 unsigned long flags; 286 unsigned long flags;
287 int ret;
288 287
289 /* decrement the refcount, and we're done if there's still refs */ 288 /* decrement the refcount, and we're done if there's still refs */
290 if (likely(!atomic_dec_and_test(&chan->users))) { 289 if (likely(!atomic_dec_and_test(&chan->users))) {
@@ -297,19 +296,7 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
297 nouveau_debugfs_channel_fini(chan); 296 nouveau_debugfs_channel_fini(chan);
298 297
299 /* give it chance to idle */ 298 /* give it chance to idle */
300 nouveau_fence_update(chan); 299 nouveau_channel_idle(chan);
301 if (chan->fence.sequence != chan->fence.sequence_ack) {
302 struct nouveau_fence *fence = NULL;
303
304 ret = nouveau_fence_new(chan, &fence, true);
305 if (ret == 0) {
306 ret = nouveau_fence_wait(fence, false, false);
307 nouveau_fence_unref(&fence);
308 }
309
310 if (ret)
311 NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id);
312 }
313 300
314 /* ensure all outstanding fences are signaled. they should be if the 301 /* ensure all outstanding fences are signaled. they should be if the
315 * above attempts at idling were OK, but if we failed this'll tell TTM 302 * above attempts at idling were OK, but if we failed this'll tell TTM
@@ -388,6 +375,27 @@ nouveau_channel_ref(struct nouveau_channel *chan,
388 *pchan = chan; 375 *pchan = chan;
389} 376}
390 377
378void
379nouveau_channel_idle(struct nouveau_channel *chan)
380{
381 struct drm_device *dev = chan->dev;
382 struct nouveau_fence *fence = NULL;
383 int ret;
384
385 nouveau_fence_update(chan);
386
387 if (chan->fence.sequence != chan->fence.sequence_ack) {
388 ret = nouveau_fence_new(chan, &fence, true);
389 if (!ret) {
390 ret = nouveau_fence_wait(fence, false, false);
391 nouveau_fence_unref(&fence);
392 }
393
394 if (ret)
395 NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id);
396 }
397}
398
391/* cleans up all the fifos from file_priv */ 399/* cleans up all the fifos from file_priv */
392void 400void
393nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv) 401nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv)
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 7ff5b4369f03..a48c7da133d2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -197,22 +197,10 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
197 197
198 NV_INFO(dev, "Idling channels...\n"); 198 NV_INFO(dev, "Idling channels...\n");
199 for (i = 0; i < pfifo->channels; i++) { 199 for (i = 0; i < pfifo->channels; i++) {
200 struct nouveau_fence *fence = NULL;
201
202 chan = dev_priv->channels.ptr[i]; 200 chan = dev_priv->channels.ptr[i];
203 if (!chan || !chan->pushbuf_bo)
204 continue;
205
206 ret = nouveau_fence_new(chan, &fence, true);
207 if (ret == 0) {
208 ret = nouveau_fence_wait(fence, false, false);
209 nouveau_fence_unref(&fence);
210 }
211 201
212 if (ret) { 202 if (chan && chan->pushbuf_bo)
213 NV_ERROR(dev, "Failed to idle channel %d for suspend\n", 203 nouveau_channel_idle(chan);
214 chan->id);
215 }
216 } 204 }
217 205
218 pgraph->fifo_access(dev, false); 206 pgraph->fifo_access(dev, false);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index a52b1da32031..d001453e857b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -847,6 +847,7 @@ extern void nouveau_channel_put_unlocked(struct nouveau_channel **);
847extern void nouveau_channel_put(struct nouveau_channel **); 847extern void nouveau_channel_put(struct nouveau_channel **);
848extern void nouveau_channel_ref(struct nouveau_channel *chan, 848extern void nouveau_channel_ref(struct nouveau_channel *chan,
849 struct nouveau_channel **pchan); 849 struct nouveau_channel **pchan);
850extern void nouveau_channel_idle(struct nouveau_channel *chan);
850 851
851/* nouveau_object.c */ 852/* nouveau_object.c */
852#define NVOBJ_CLASS(d,c,e) do { \ 853#define NVOBJ_CLASS(d,c,e) do { \
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
index 2fb7e9d47500..24540862a23f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_object.c
+++ b/drivers/gpu/drm/nouveau/nouveau_object.c
@@ -1017,6 +1017,9 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
1017 if (IS_ERR(chan)) 1017 if (IS_ERR(chan))
1018 return PTR_ERR(chan); 1018 return PTR_ERR(chan);
1019 1019
1020 /* Synchronize with the user channel */
1021 nouveau_channel_idle(chan);
1022
1020 ret = nouveau_ramht_remove(chan, objfree->handle); 1023 ret = nouveau_ramht_remove(chan, objfree->handle);
1021 nouveau_channel_put(&chan); 1024 nouveau_channel_put(&chan);
1022 return ret; 1025 return ret;