aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
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
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')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_channel.c24
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c8
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fifo.c21
-rw-r--r--drivers/gpu/drm/nouveau/nv04_graph.c15
-rw-r--r--drivers/gpu/drm/nouveau/nv10_fifo.c11
-rw-r--r--drivers/gpu/drm/nouveau/nv10_graph.c15
-rw-r--r--drivers/gpu/drm/nouveau/nv20_graph.c14
-rw-r--r--drivers/gpu/drm/nouveau/nv40_fifo.c11
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c16
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fifo.c17
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c11
12 files changed, 116 insertions, 49 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)
313 /* boot it off the hardware */ 313 /* boot it off the hardware */
314 pfifo->reassign(dev, false); 314 pfifo->reassign(dev, false);
315 315
316 /* We want to give pgraph a chance to idle and get rid of all potential 316 /* We want to give pgraph a chance to idle and get rid of all
317 * errors. We need to do this before the lock, otherwise the irq handler 317 * potential errors. We need to do this without the context
318 * is unable to process them. 318 * switch lock held, otherwise the irq handler is unable to
319 * process them.
319 */ 320 */
320 if (pgraph->channel(dev) == chan) 321 if (pgraph->channel(dev) == chan)
321 nouveau_wait_for_idle(dev); 322 nouveau_wait_for_idle(dev);
322 323
323 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 324 /* destroy the engine specific contexts */
324
325 pgraph->fifo_access(dev, false);
326 if (pgraph->channel(dev) == chan)
327 pgraph->unload_context(dev);
328 pgraph->destroy_context(chan);
329 pgraph->fifo_access(dev, true);
330
331 if (pfifo->channel_id(dev) == chan->id) {
332 pfifo->disable(dev);
333 pfifo->unload_context(dev);
334 pfifo->enable(dev);
335 }
336 pfifo->destroy_context(chan); 325 pfifo->destroy_context(chan);
326 pgraph->destroy_context(chan);
337 327
338 pfifo->reassign(dev, true); 328 pfifo->reassign(dev, true);
339 329
340 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
341
342 /* aside from its resources, the channel should now be dead, 330 /* aside from its resources, the channel should now be dead,
343 * remove it from the channel list 331 * remove it from the channel list
344 */ 332 */
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 699d546623b..198dabebafb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -998,14 +998,12 @@ extern int nv04_fifo_unload_context(struct drm_device *);
998extern int nv10_fifo_init(struct drm_device *); 998extern int nv10_fifo_init(struct drm_device *);
999extern int nv10_fifo_channel_id(struct drm_device *); 999extern int nv10_fifo_channel_id(struct drm_device *);
1000extern int nv10_fifo_create_context(struct nouveau_channel *); 1000extern int nv10_fifo_create_context(struct nouveau_channel *);
1001extern void nv10_fifo_destroy_context(struct nouveau_channel *);
1002extern int nv10_fifo_load_context(struct nouveau_channel *); 1001extern int nv10_fifo_load_context(struct nouveau_channel *);
1003extern int nv10_fifo_unload_context(struct drm_device *); 1002extern int nv10_fifo_unload_context(struct drm_device *);
1004 1003
1005/* nv40_fifo.c */ 1004/* nv40_fifo.c */
1006extern int nv40_fifo_init(struct drm_device *); 1005extern int nv40_fifo_init(struct drm_device *);
1007extern int nv40_fifo_create_context(struct nouveau_channel *); 1006extern int nv40_fifo_create_context(struct nouveau_channel *);
1008extern void nv40_fifo_destroy_context(struct nouveau_channel *);
1009extern int nv40_fifo_load_context(struct nouveau_channel *); 1007extern int nv40_fifo_load_context(struct nouveau_channel *);
1010extern int nv40_fifo_unload_context(struct drm_device *); 1008extern int nv40_fifo_unload_context(struct drm_device *);
1011 1009
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 513c1063fb5..1a4ba6ccafb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -137,7 +137,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
137 engine->fifo.cache_pull = nv04_fifo_cache_pull; 137 engine->fifo.cache_pull = nv04_fifo_cache_pull;
138 engine->fifo.channel_id = nv10_fifo_channel_id; 138 engine->fifo.channel_id = nv10_fifo_channel_id;
139 engine->fifo.create_context = nv10_fifo_create_context; 139 engine->fifo.create_context = nv10_fifo_create_context;
140 engine->fifo.destroy_context = nv10_fifo_destroy_context; 140 engine->fifo.destroy_context = nv04_fifo_destroy_context;
141 engine->fifo.load_context = nv10_fifo_load_context; 141 engine->fifo.load_context = nv10_fifo_load_context;
142 engine->fifo.unload_context = nv10_fifo_unload_context; 142 engine->fifo.unload_context = nv10_fifo_unload_context;
143 engine->display.early_init = nv04_display_early_init; 143 engine->display.early_init = nv04_display_early_init;
@@ -191,7 +191,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
191 engine->fifo.cache_pull = nv04_fifo_cache_pull; 191 engine->fifo.cache_pull = nv04_fifo_cache_pull;
192 engine->fifo.channel_id = nv10_fifo_channel_id; 192 engine->fifo.channel_id = nv10_fifo_channel_id;
193 engine->fifo.create_context = nv10_fifo_create_context; 193 engine->fifo.create_context = nv10_fifo_create_context;
194 engine->fifo.destroy_context = nv10_fifo_destroy_context; 194 engine->fifo.destroy_context = nv04_fifo_destroy_context;
195 engine->fifo.load_context = nv10_fifo_load_context; 195 engine->fifo.load_context = nv10_fifo_load_context;
196 engine->fifo.unload_context = nv10_fifo_unload_context; 196 engine->fifo.unload_context = nv10_fifo_unload_context;
197 engine->display.early_init = nv04_display_early_init; 197 engine->display.early_init = nv04_display_early_init;
@@ -245,7 +245,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
245 engine->fifo.cache_pull = nv04_fifo_cache_pull; 245 engine->fifo.cache_pull = nv04_fifo_cache_pull;
246 engine->fifo.channel_id = nv10_fifo_channel_id; 246 engine->fifo.channel_id = nv10_fifo_channel_id;
247 engine->fifo.create_context = nv10_fifo_create_context; 247 engine->fifo.create_context = nv10_fifo_create_context;
248 engine->fifo.destroy_context = nv10_fifo_destroy_context; 248 engine->fifo.destroy_context = nv04_fifo_destroy_context;
249 engine->fifo.load_context = nv10_fifo_load_context; 249 engine->fifo.load_context = nv10_fifo_load_context;
250 engine->fifo.unload_context = nv10_fifo_unload_context; 250 engine->fifo.unload_context = nv10_fifo_unload_context;
251 engine->display.early_init = nv04_display_early_init; 251 engine->display.early_init = nv04_display_early_init;
@@ -302,7 +302,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
302 engine->fifo.cache_pull = nv04_fifo_cache_pull; 302 engine->fifo.cache_pull = nv04_fifo_cache_pull;
303 engine->fifo.channel_id = nv10_fifo_channel_id; 303 engine->fifo.channel_id = nv10_fifo_channel_id;
304 engine->fifo.create_context = nv40_fifo_create_context; 304 engine->fifo.create_context = nv40_fifo_create_context;
305 engine->fifo.destroy_context = nv40_fifo_destroy_context; 305 engine->fifo.destroy_context = nv04_fifo_destroy_context;
306 engine->fifo.load_context = nv40_fifo_load_context; 306 engine->fifo.load_context = nv40_fifo_load_context;
307 engine->fifo.unload_context = nv40_fifo_unload_context; 307 engine->fifo.unload_context = nv40_fifo_unload_context;
308 engine->display.early_init = nv04_display_early_init; 308 engine->display.early_init = nv04_display_early_init;
diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c
index 25c439dcdfd..4c0d3a8fca6 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
diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c
index 98b9525c1eb..1e2ad394233 100644
--- a/drivers/gpu/drm/nouveau/nv04_graph.c
+++ b/drivers/gpu/drm/nouveau/nv04_graph.c
@@ -412,10 +412,25 @@ int nv04_graph_create_context(struct nouveau_channel *chan)
412 412
413void nv04_graph_destroy_context(struct nouveau_channel *chan) 413void nv04_graph_destroy_context(struct nouveau_channel *chan)
414{ 414{
415 struct drm_device *dev = chan->dev;
416 struct drm_nouveau_private *dev_priv = dev->dev_private;
417 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
415 struct graph_state *pgraph_ctx = chan->pgraph_ctx; 418 struct graph_state *pgraph_ctx = chan->pgraph_ctx;
419 unsigned long flags;
420
421 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
422 pgraph->fifo_access(dev, false);
423
424 /* Unload the context if it's the currently active one */
425 if (pgraph->channel(dev) == chan)
426 pgraph->unload_context(dev);
416 427
428 /* Free the context resources */
417 kfree(pgraph_ctx); 429 kfree(pgraph_ctx);
418 chan->pgraph_ctx = NULL; 430 chan->pgraph_ctx = NULL;
431
432 pgraph->fifo_access(dev, true);
433 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
419} 434}
420 435
421int nv04_graph_load_context(struct nouveau_channel *chan) 436int nv04_graph_load_context(struct nouveau_channel *chan)
diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c
index 39328fcce70..912556f2e33 100644
--- a/drivers/gpu/drm/nouveau/nv10_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv10_fifo.c
@@ -73,17 +73,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
73 return 0; 73 return 0;
74} 74}
75 75
76void
77nv10_fifo_destroy_context(struct nouveau_channel *chan)
78{
79 struct drm_device *dev = chan->dev;
80
81 nv_wr32(dev, NV04_PFIFO_MODE,
82 nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
83
84 nouveau_gpuobj_ref(NULL, &chan->ramfc);
85}
86
87static void 76static void
88nv10_fifo_do_load_context(struct drm_device *dev, int chid) 77nv10_fifo_do_load_context(struct drm_device *dev, int chid)
89{ 78{
diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c
index cd931b57cf0..e3a87a64c16 100644
--- a/drivers/gpu/drm/nouveau/nv10_graph.c
+++ b/drivers/gpu/drm/nouveau/nv10_graph.c
@@ -875,10 +875,25 @@ int nv10_graph_create_context(struct nouveau_channel *chan)
875 875
876void nv10_graph_destroy_context(struct nouveau_channel *chan) 876void nv10_graph_destroy_context(struct nouveau_channel *chan)
877{ 877{
878 struct drm_device *dev = chan->dev;
879 struct drm_nouveau_private *dev_priv = dev->dev_private;
880 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
878 struct graph_state *pgraph_ctx = chan->pgraph_ctx; 881 struct graph_state *pgraph_ctx = chan->pgraph_ctx;
882 unsigned long flags;
883
884 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
885 pgraph->fifo_access(dev, false);
886
887 /* Unload the context if it's the currently active one */
888 if (pgraph->channel(dev) == chan)
889 pgraph->unload_context(dev);
879 890
891 /* Free the context resources */
880 kfree(pgraph_ctx); 892 kfree(pgraph_ctx);
881 chan->pgraph_ctx = NULL; 893 chan->pgraph_ctx = NULL;
894
895 pgraph->fifo_access(dev, true);
896 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
882} 897}
883 898
884void 899void
diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
index 12ab9cd56ec..8a040201255 100644
--- a/drivers/gpu/drm/nouveau/nv20_graph.c
+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
@@ -425,9 +425,21 @@ nv20_graph_destroy_context(struct nouveau_channel *chan)
425 struct drm_device *dev = chan->dev; 425 struct drm_device *dev = chan->dev;
426 struct drm_nouveau_private *dev_priv = dev->dev_private; 426 struct drm_nouveau_private *dev_priv = dev->dev_private;
427 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; 427 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
428 unsigned long flags;
428 429
429 nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); 430 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
431 pgraph->fifo_access(dev, false);
432
433 /* Unload the context if it's the currently active one */
434 if (pgraph->channel(dev) == chan)
435 pgraph->unload_context(dev);
436
437 pgraph->fifo_access(dev, true);
438 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
439
440 /* Free the context resources */
430 nv_wo32(pgraph->ctx_table, chan->id * 4, 0); 441 nv_wo32(pgraph->ctx_table, chan->id * 4, 0);
442 nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
431} 443}
432 444
433int 445int
diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c
index 3c7be3dc8b8..311ac9ea5d5 100644
--- a/drivers/gpu/drm/nouveau/nv40_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv40_fifo.c
@@ -70,17 +70,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
70 return 0; 70 return 0;
71} 71}
72 72
73void
74nv40_fifo_destroy_context(struct nouveau_channel *chan)
75{
76 struct drm_device *dev = chan->dev;
77
78 nv_wr32(dev, NV04_PFIFO_MODE,
79 nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
80
81 nouveau_gpuobj_ref(NULL, &chan->ramfc);
82}
83
84static void 73static void
85nv40_fifo_do_load_context(struct drm_device *dev, int chid) 74nv40_fifo_do_load_context(struct drm_device *dev, int chid)
86{ 75{
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
index e0b41a26447..70d97cde49d 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -79,6 +79,22 @@ nv40_graph_create_context(struct nouveau_channel *chan)
79void 79void
80nv40_graph_destroy_context(struct nouveau_channel *chan) 80nv40_graph_destroy_context(struct nouveau_channel *chan)
81{ 81{
82 struct drm_device *dev = chan->dev;
83 struct drm_nouveau_private *dev_priv = dev->dev_private;
84 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
85 unsigned long flags;
86
87 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
88 pgraph->fifo_access(dev, false);
89
90 /* Unload the context if it's the currently active one */
91 if (pgraph->channel(dev) == chan)
92 pgraph->unload_context(dev);
93
94 pgraph->fifo_access(dev, true);
95 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
96
97 /* Free the context resources */
82 nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); 98 nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
83} 99}
84 100
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c
index 815960fe4f4..d3295aae0c4 100644
--- a/drivers/gpu/drm/nouveau/nv50_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv50_fifo.c
@@ -292,10 +292,23 @@ void
292nv50_fifo_destroy_context(struct nouveau_channel *chan) 292nv50_fifo_destroy_context(struct nouveau_channel *chan)
293{ 293{
294 struct drm_device *dev = chan->dev; 294 struct drm_device *dev = chan->dev;
295 struct drm_nouveau_private *dev_priv = dev->dev_private;
296 struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
295 struct nouveau_gpuobj *ramfc = NULL; 297 struct nouveau_gpuobj *ramfc = NULL;
298 unsigned long flags;
296 299
297 NV_DEBUG(dev, "ch%d\n", chan->id); 300 NV_DEBUG(dev, "ch%d\n", chan->id);
298 301
302 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
303 pfifo->reassign(dev, false);
304
305 /* Unload the context if it's the currently active one */
306 if (pfifo->channel_id(dev) == chan->id) {
307 pfifo->disable(dev);
308 pfifo->unload_context(dev);
309 pfifo->enable(dev);
310 }
311
299 /* This will ensure the channel is seen as disabled. */ 312 /* This will ensure the channel is seen as disabled. */
300 nouveau_gpuobj_ref(chan->ramfc, &ramfc); 313 nouveau_gpuobj_ref(chan->ramfc, &ramfc);
301 nouveau_gpuobj_ref(NULL, &chan->ramfc); 314 nouveau_gpuobj_ref(NULL, &chan->ramfc);
@@ -306,6 +319,10 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan)
306 nv50_fifo_channel_disable(dev, 127); 319 nv50_fifo_channel_disable(dev, 127);
307 nv50_fifo_playlist_update(dev); 320 nv50_fifo_playlist_update(dev);
308 321
322 pfifo->reassign(dev, true);
323 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
324
325 /* Free the channel resources */
309 nouveau_gpuobj_ref(NULL, &ramfc); 326 nouveau_gpuobj_ref(NULL, &ramfc);
310 nouveau_gpuobj_ref(NULL, &chan->cache); 327 nouveau_gpuobj_ref(NULL, &chan->cache);
311} 328}
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index 24a3f848757..dcc9175fb79 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