aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nv50_graph.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/nv50_graph.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/nv50_graph.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index 24a3f8487579..dcc9175fb794 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -242,17 +242,28 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
242{ 242{
243 struct drm_device *dev = chan->dev; 243 struct drm_device *dev = chan->dev;
244 struct drm_nouveau_private *dev_priv = dev->dev_private; 244 struct drm_nouveau_private *dev_priv = dev->dev_private;
245 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
245 int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; 246 int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
247 unsigned long flags;
246 248
247 NV_DEBUG(dev, "ch%d\n", chan->id); 249 NV_DEBUG(dev, "ch%d\n", chan->id);
248 250
249 if (!chan->ramin) 251 if (!chan->ramin)
250 return; 252 return;
251 253
254 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
255 pgraph->fifo_access(dev, false);
256
257 if (pgraph->channel(dev) == chan)
258 pgraph->unload_context(dev);
259
252 for (i = hdr; i < hdr + 24; i += 4) 260 for (i = hdr; i < hdr + 24; i += 4)
253 nv_wo32(chan->ramin, i, 0); 261 nv_wo32(chan->ramin, i, 0);
254 dev_priv->engine.instmem.flush(dev); 262 dev_priv->engine.instmem.flush(dev);
255 263
264 pgraph->fifo_access(dev, true);
265 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
266
256 nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); 267 nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
257} 268}
258 269