diff options
author | Francisco Jerez <currojerez@riseup.net> | 2010-10-18 03:53:39 +0200 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-12-03 15:06:35 +1000 |
commit | 3945e47543863385b54d94c94b023ee7ca9df972 (patch) | |
tree | 209eb523c0e3a01069f8e18751b97373804a22d3 /drivers/gpu/drm/nouveau/nouveau_channel.c | |
parent | fcccab2e4eb8d579837481054cc2cb28eea0baef (diff) |
drm/nouveau: Refactor context destruction to avoid a lock ordering issue.
The destroy_context() engine hooks call gpuobj management functions to
release the channel resources, these functions use HARDIRQ-unsafe locks
whereas destroy_context() is called with the HARDIRQ-safe
context_switch_lock held, that's a lock ordering violation.
Push the engine-specific channel destruction logic into destroy_context()
and let the hardware-specific code lock and unlock when it's actually
needed. Change the engine destruction order to avoid a race in the small
gap between pgraph and pfifo context uninitialization.
Reported-by: Marcin Slusarz <marcin.slusarz@gmail.com>
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
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 | 24 |
1 files changed, 6 insertions, 18 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 0e2414b0ae5..9a051fafa7c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -313,32 +313,20 @@ nouveau_channel_put(struct nouveau_channel **pchan) /* boot it off the hardware */ 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. + /* We want to give pgraph a chance to idle and get rid of all + * potential errors. We need to do this without the context + * switch lock held, 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); - pgraph->destroy_context(chan); - pgraph->fifo_access(dev, true); - - if (pfifo->channel_id(dev) == chan->id) { - pfifo->disable(dev); - pfifo->unload_context(dev); - pfifo->enable(dev); - } + /* destroy the engine specific contexts */ pfifo->destroy_context(chan); + pgraph->destroy_context(chan); pfifo->reassign(dev, true); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - /* aside from its resources, the channel should now be dead, * remove it from the channel list */ |