diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_fifo.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_fifo.c | 42 |
1 files changed, 37 insertions, 5 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index 1da65bd60c10..8dd04c5dac67 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "drm.h" | 28 | #include "drm.h" |
29 | #include "nouveau_drv.h" | 29 | #include "nouveau_drv.h" |
30 | #include "nouveau_ramht.h" | 30 | #include "nouveau_ramht.h" |
31 | #include "nouveau_vm.h" | ||
31 | 32 | ||
32 | static void | 33 | static void |
33 | nv50_fifo_playlist_update(struct drm_device *dev) | 34 | nv50_fifo_playlist_update(struct drm_device *dev) |
@@ -44,7 +45,8 @@ nv50_fifo_playlist_update(struct drm_device *dev) | |||
44 | 45 | ||
45 | /* We never schedule channel 0 or 127 */ | 46 | /* We never schedule channel 0 or 127 */ |
46 | for (i = 1, nr = 0; i < 127; i++) { | 47 | for (i = 1, nr = 0; i < 127; i++) { |
47 | if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) { | 48 | if (dev_priv->channels.ptr[i] && |
49 | dev_priv->channels.ptr[i]->ramfc) { | ||
48 | nv_wo32(cur, (nr * 4), i); | 50 | nv_wo32(cur, (nr * 4), i); |
49 | nr++; | 51 | nr++; |
50 | } | 52 | } |
@@ -60,7 +62,7 @@ static void | |||
60 | nv50_fifo_channel_enable(struct drm_device *dev, int channel) | 62 | nv50_fifo_channel_enable(struct drm_device *dev, int channel) |
61 | { | 63 | { |
62 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 64 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
63 | struct nouveau_channel *chan = dev_priv->fifos[channel]; | 65 | struct nouveau_channel *chan = dev_priv->channels.ptr[channel]; |
64 | uint32_t inst; | 66 | uint32_t inst; |
65 | 67 | ||
66 | NV_DEBUG(dev, "ch%d\n", channel); | 68 | NV_DEBUG(dev, "ch%d\n", channel); |
@@ -105,6 +107,7 @@ nv50_fifo_init_intr(struct drm_device *dev) | |||
105 | { | 107 | { |
106 | NV_DEBUG(dev, "\n"); | 108 | NV_DEBUG(dev, "\n"); |
107 | 109 | ||
110 | nouveau_irq_register(dev, 8, nv04_fifo_isr); | ||
108 | nv_wr32(dev, NV03_PFIFO_INTR_0, 0xFFFFFFFF); | 111 | nv_wr32(dev, NV03_PFIFO_INTR_0, 0xFFFFFFFF); |
109 | nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xFFFFFFFF); | 112 | nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xFFFFFFFF); |
110 | } | 113 | } |
@@ -118,7 +121,7 @@ nv50_fifo_init_context_table(struct drm_device *dev) | |||
118 | NV_DEBUG(dev, "\n"); | 121 | NV_DEBUG(dev, "\n"); |
119 | 122 | ||
120 | for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) { | 123 | for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) { |
121 | if (dev_priv->fifos[i]) | 124 | if (dev_priv->channels.ptr[i]) |
122 | nv50_fifo_channel_enable(dev, i); | 125 | nv50_fifo_channel_enable(dev, i); |
123 | else | 126 | else |
124 | nv50_fifo_channel_disable(dev, i); | 127 | nv50_fifo_channel_disable(dev, i); |
@@ -206,6 +209,9 @@ nv50_fifo_takedown(struct drm_device *dev) | |||
206 | if (!pfifo->playlist[0]) | 209 | if (!pfifo->playlist[0]) |
207 | return; | 210 | return; |
208 | 211 | ||
212 | nv_wr32(dev, 0x2140, 0x00000000); | ||
213 | nouveau_irq_unregister(dev, 8); | ||
214 | |||
209 | nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]); | 215 | nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]); |
210 | nouveau_gpuobj_ref(NULL, &pfifo->playlist[1]); | 216 | nouveau_gpuobj_ref(NULL, &pfifo->playlist[1]); |
211 | } | 217 | } |
@@ -256,6 +262,11 @@ nv50_fifo_create_context(struct nouveau_channel *chan) | |||
256 | } | 262 | } |
257 | ramfc = chan->ramfc; | 263 | ramfc = chan->ramfc; |
258 | 264 | ||
265 | chan->user = ioremap(pci_resource_start(dev->pdev, 0) + | ||
266 | NV50_USER(chan->id), PAGE_SIZE); | ||
267 | if (!chan->user) | ||
268 | return -ENOMEM; | ||
269 | |||
259 | spin_lock_irqsave(&dev_priv->context_switch_lock, flags); | 270 | spin_lock_irqsave(&dev_priv->context_switch_lock, flags); |
260 | 271 | ||
261 | nv_wo32(ramfc, 0x48, chan->pushbuf->cinst >> 4); | 272 | nv_wo32(ramfc, 0x48, chan->pushbuf->cinst >> 4); |
@@ -291,10 +302,23 @@ void | |||
291 | nv50_fifo_destroy_context(struct nouveau_channel *chan) | 302 | nv50_fifo_destroy_context(struct nouveau_channel *chan) |
292 | { | 303 | { |
293 | struct drm_device *dev = chan->dev; | 304 | struct drm_device *dev = chan->dev; |
305 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
306 | struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; | ||
294 | struct nouveau_gpuobj *ramfc = NULL; | 307 | struct nouveau_gpuobj *ramfc = NULL; |
308 | unsigned long flags; | ||
295 | 309 | ||
296 | NV_DEBUG(dev, "ch%d\n", chan->id); | 310 | NV_DEBUG(dev, "ch%d\n", chan->id); |
297 | 311 | ||
312 | spin_lock_irqsave(&dev_priv->context_switch_lock, flags); | ||
313 | pfifo->reassign(dev, false); | ||
314 | |||
315 | /* Unload the context if it's the currently active one */ | ||
316 | if (pfifo->channel_id(dev) == chan->id) { | ||
317 | pfifo->disable(dev); | ||
318 | pfifo->unload_context(dev); | ||
319 | pfifo->enable(dev); | ||
320 | } | ||
321 | |||
298 | /* This will ensure the channel is seen as disabled. */ | 322 | /* This will ensure the channel is seen as disabled. */ |
299 | nouveau_gpuobj_ref(chan->ramfc, &ramfc); | 323 | nouveau_gpuobj_ref(chan->ramfc, &ramfc); |
300 | nouveau_gpuobj_ref(NULL, &chan->ramfc); | 324 | nouveau_gpuobj_ref(NULL, &chan->ramfc); |
@@ -305,6 +329,14 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan) | |||
305 | nv50_fifo_channel_disable(dev, 127); | 329 | nv50_fifo_channel_disable(dev, 127); |
306 | nv50_fifo_playlist_update(dev); | 330 | nv50_fifo_playlist_update(dev); |
307 | 331 | ||
332 | pfifo->reassign(dev, true); | ||
333 | spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); | ||
334 | |||
335 | /* Free the channel resources */ | ||
336 | if (chan->user) { | ||
337 | iounmap(chan->user); | ||
338 | chan->user = NULL; | ||
339 | } | ||
308 | nouveau_gpuobj_ref(NULL, &ramfc); | 340 | nouveau_gpuobj_ref(NULL, &ramfc); |
309 | nouveau_gpuobj_ref(NULL, &chan->cache); | 341 | nouveau_gpuobj_ref(NULL, &chan->cache); |
310 | } | 342 | } |
@@ -392,7 +424,7 @@ nv50_fifo_unload_context(struct drm_device *dev) | |||
392 | if (chid < 1 || chid >= dev_priv->engine.fifo.channels - 1) | 424 | if (chid < 1 || chid >= dev_priv->engine.fifo.channels - 1) |
393 | return 0; | 425 | return 0; |
394 | 426 | ||
395 | chan = dev_priv->fifos[chid]; | 427 | chan = dev_priv->channels.ptr[chid]; |
396 | if (!chan) { | 428 | if (!chan) { |
397 | NV_ERROR(dev, "Inactive channel on PFIFO: %d\n", chid); | 429 | NV_ERROR(dev, "Inactive channel on PFIFO: %d\n", chid); |
398 | return -EINVAL; | 430 | return -EINVAL; |
@@ -467,5 +499,5 @@ nv50_fifo_unload_context(struct drm_device *dev) | |||
467 | void | 499 | void |
468 | nv50_fifo_tlb_flush(struct drm_device *dev) | 500 | nv50_fifo_tlb_flush(struct drm_device *dev) |
469 | { | 501 | { |
470 | nv50_vm_flush(dev, 5); | 502 | nv50_vm_flush_engine(dev, 5); |
471 | } | 503 | } |