diff options
author | Francisco Jerez <currojerez@riseup.net> | 2010-10-17 21:53:39 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-12-03 00:06:35 -0500 |
commit | 3945e47543863385b54d94c94b023ee7ca9df972 (patch) | |
tree | 209eb523c0e3a01069f8e18751b97373804a22d3 /drivers/gpu/drm/nouveau/nv50_graph.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/nv50_graph.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_graph.c | 11 |
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 | ||