aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nv04_fifo.c
diff options
context:
space:
mode:
authorFrancisco Jerez <currojerez@riseup.net>2010-10-17 21:53:39 -0400
committerBen Skeggs <bskeggs@redhat.com>2010-12-03 00:06:35 -0500
commit3945e47543863385b54d94c94b023ee7ca9df972 (patch)
tree209eb523c0e3a01069f8e18751b97373804a22d3 /drivers/gpu/drm/nouveau/nv04_fifo.c
parentfcccab2e4eb8d579837481054cc2cb28eea0baef (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/nv04_fifo.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fifo.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c
index 25c439dcdfd9..4c0d3a8fca68 100644
--- a/drivers/gpu/drm/nouveau/nv04_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv04_fifo.c
@@ -151,10 +151,27 @@ void
151nv04_fifo_destroy_context(struct nouveau_channel *chan) 151nv04_fifo_destroy_context(struct nouveau_channel *chan)
152{ 152{
153 struct drm_device *dev = chan->dev; 153 struct drm_device *dev = chan->dev;
154 struct drm_nouveau_private *dev_priv = dev->dev_private;
155 struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
156 unsigned long flags;
154 157
155 nv_wr32(dev, NV04_PFIFO_MODE, 158 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
156 nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id)); 159 pfifo->reassign(dev, false);
160
161 /* Unload the context if it's the currently active one */
162 if (pfifo->channel_id(dev) == chan->id) {
163 pfifo->disable(dev);
164 pfifo->unload_context(dev);
165 pfifo->enable(dev);
166 }
167
168 /* Keep it from being rescheduled */
169 nv_mask(dev, NV04_PFIFO_MODE, 1 << chan->id, 0);
170
171 pfifo->reassign(dev, true);
172 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
157 173
174 /* Free the channel resources */
158 nouveau_gpuobj_ref(NULL, &chan->ramfc); 175 nouveau_gpuobj_ref(NULL, &chan->ramfc);
159} 176}
160 177