Commit 6dccd311 authored by Francisco Jerez's avatar Francisco Jerez

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: default avatarGrzesiek Sójka <pld@pfu.pl>
Reported-by: default avatarPatrice Mandin <patmandin@gmail.com>
Signed-off-by: default avatarFrancisco Jerez <currojerez@riseup.net>
Acked-by: default avatarBen Skeggs <bskeggs@redhat.com>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 38cf189f
...@@ -284,7 +284,6 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan) ...@@ -284,7 +284,6 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt; struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
unsigned long flags; unsigned long flags;
int ret;
/* decrement the refcount, and we're done if there's still refs */ /* decrement the refcount, and we're done if there's still refs */
if (likely(!atomic_dec_and_test(&chan->users))) { if (likely(!atomic_dec_and_test(&chan->users))) {
...@@ -297,19 +296,7 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan) ...@@ -297,19 +296,7 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
nouveau_debugfs_channel_fini(chan); nouveau_debugfs_channel_fini(chan);
/* give it chance to idle */ /* give it chance to idle */
nouveau_fence_update(chan); nouveau_channel_idle(chan);
if (chan->fence.sequence != chan->fence.sequence_ack) {
struct nouveau_fence *fence = NULL;
ret = nouveau_fence_new(chan, &fence, true);
if (ret == 0) {
ret = nouveau_fence_wait(fence, false, false);
nouveau_fence_unref(&fence);
}
if (ret)
NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id);
}
/* ensure all outstanding fences are signaled. they should be if the /* ensure all outstanding fences are signaled. they should be if the
* above attempts at idling were OK, but if we failed this'll tell TTM * 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,6 +375,27 @@ nouveau_channel_ref(struct nouveau_channel *chan,
*pchan = chan; *pchan = chan;
} }
void
nouveau_channel_idle(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct nouveau_fence *fence = NULL;
int ret;
nouveau_fence_update(chan);
if (chan->fence.sequence != chan->fence.sequence_ack) {
ret = nouveau_fence_new(chan, &fence, true);
if (!ret) {
ret = nouveau_fence_wait(fence, false, false);
nouveau_fence_unref(&fence);
}
if (ret)
NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id);
}
}
/* cleans up all the fifos from file_priv */ /* cleans up all the fifos from file_priv */
void void
nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv) nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv)
......
...@@ -197,22 +197,10 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) ...@@ -197,22 +197,10 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
NV_INFO(dev, "Idling channels...\n"); NV_INFO(dev, "Idling channels...\n");
for (i = 0; i < pfifo->channels; i++) { for (i = 0; i < pfifo->channels; i++) {
struct nouveau_fence *fence = NULL;
chan = dev_priv->channels.ptr[i]; chan = dev_priv->channels.ptr[i];
if (!chan || !chan->pushbuf_bo)
continue;
ret = nouveau_fence_new(chan, &fence, true);
if (ret == 0) {
ret = nouveau_fence_wait(fence, false, false);
nouveau_fence_unref(&fence);
}
if (ret) { if (chan && chan->pushbuf_bo)
NV_ERROR(dev, "Failed to idle channel %d for suspend\n", nouveau_channel_idle(chan);
chan->id);
}
} }
pgraph->fifo_access(dev, false); pgraph->fifo_access(dev, false);
......
...@@ -847,6 +847,7 @@ extern void nouveau_channel_put_unlocked(struct nouveau_channel **); ...@@ -847,6 +847,7 @@ extern void nouveau_channel_put_unlocked(struct nouveau_channel **);
extern void nouveau_channel_put(struct nouveau_channel **); extern void nouveau_channel_put(struct nouveau_channel **);
extern void nouveau_channel_ref(struct nouveau_channel *chan, extern void nouveau_channel_ref(struct nouveau_channel *chan,
struct nouveau_channel **pchan); struct nouveau_channel **pchan);
extern void nouveau_channel_idle(struct nouveau_channel *chan);
/* nouveau_object.c */ /* nouveau_object.c */
#define NVOBJ_CLASS(d,c,e) do { \ #define NVOBJ_CLASS(d,c,e) do { \
......
...@@ -1017,6 +1017,9 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, ...@@ -1017,6 +1017,9 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
if (IS_ERR(chan)) if (IS_ERR(chan))
return PTR_ERR(chan); return PTR_ERR(chan);
/* Synchronize with the user channel */
nouveau_channel_idle(chan);
ret = nouveau_ramht_remove(chan, objfree->handle); ret = nouveau_ramht_remove(chan, objfree->handle);
nouveau_channel_put(&chan); nouveau_channel_put(&chan);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment