diff options
author | Maarten Maathuis <madman2003@gmail.com> | 2010-02-01 20:58:27 +0100 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-02-25 15:07:53 +1000 |
commit | ff9e5279b14dc024599cc705ee199dadb94e90a3 (patch) | |
tree | 4881498b0c5f0defdc14890783249b0514a8afde /drivers/gpu/drm/nouveau/nouveau_channel.c | |
parent | 6c42966768b0254f465a8f451333795283f53d22 (diff) |
drm/nouveau: protect channel create/destroy and irq handler with a spinlock
The nv50 pgraph handler (for example) could reenable pgraph fifo access
and that would be bad when pgraph context is being unloaded (we need the
guarantee a ctxprog isn't running).
Signed-off-by: Maarten Maathuis <madman2003@gmail.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_channel.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_channel.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 2281f99da7f..f7ca95003f5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -275,9 +275,18 @@ nouveau_channel_free(struct nouveau_channel *chan) */ nouveau_fence_fini(chan); - /* Ensure the channel is no longer active on the GPU */ + /* This will prevent pfifo from switching channels. */ pfifo->reassign(dev, false); + /* We want to give pgraph a chance to idle and get rid of all potential + * errors. We need to do this before the lock, otherwise the irq handler + * is unable to process them. + */ + if (pgraph->channel(dev) == chan) + nouveau_wait_for_idle(dev); + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + pgraph->fifo_access(dev, false); if (pgraph->channel(dev) == chan) pgraph->unload_context(dev); @@ -293,6 +302,8 @@ nouveau_channel_free(struct nouveau_channel *chan) pfifo->reassign(dev, true); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + /* Release the channel's resources */ nouveau_gpuobj_ref_del(dev, &chan->pushbuf); if (chan->pushbuf_bo) { |