aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-02-03 00:46:14 -0500
committerBen Skeggs <bskeggs@redhat.com>2011-02-24 15:45:02 -0500
commit60f60bf1bc45bef38568244f5c4e0d0f105c5032 (patch)
tree8c636475240cdafb762254877dd4c00fa53fd41c /drivers/gpu/drm/nouveau
parentf13e435c59573aa0ac398210777cc0406c476593 (diff)
drm/nv50-nvc0: request and wait on notification of modeset completion
This should prevent a number of races from occuring, the most obvious of which will be exposed when we start making use of the "display sync" evo channel for page flipping. The DS channel will reject any command stream that doesn't completely agree with the current "master" state. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.h3
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c77
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.h1
-rw-r--r--drivers/gpu/drm/nouveau/nv50_evo.c20
5 files changed, 77 insertions, 26 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h
index c36f1763fea..6c9501b3226 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.h
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.h
@@ -78,7 +78,8 @@ enum {
78 NvEvoVRAM = 0x01000000, 78 NvEvoVRAM = 0x01000000,
79 NvEvoFB16 = 0x01000001, 79 NvEvoFB16 = 0x01000001,
80 NvEvoFB32 = 0x01000002, 80 NvEvoFB32 = 0x01000002,
81 NvEvoVRAM_LP = 0x01000003 81 NvEvoVRAM_LP = 0x01000003,
82 NvEvoSync = 0xcafe0000
82}; 83};
83 84
84#define NV_MEMORY_TO_MEMORY_FORMAT 0x00000039 85#define NV_MEMORY_TO_MEMORY_FORMAT 0x00000039
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index bc5fa36677c..a94aff57cc0 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -443,6 +443,42 @@ nv50_crtc_dpms(struct drm_crtc *crtc, int mode)
443{ 443{
444} 444}
445 445
446static int
447nv50_crtc_wait_complete(struct drm_crtc *crtc)
448{
449 struct drm_device *dev = crtc->dev;
450 struct drm_nouveau_private *dev_priv = dev->dev_private;
451 struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
452 struct nv50_display *disp = nv50_display(dev);
453 struct nouveau_channel *evo = disp->master;
454 u64 start;
455 int ret;
456
457 ret = RING_SPACE(evo, 6);
458 if (ret)
459 return ret;
460 BEGIN_RING(evo, 0, 0x0084, 1);
461 OUT_RING (evo, 0x80000000);
462 BEGIN_RING(evo, 0, 0x0080, 1);
463 OUT_RING (evo, 0);
464 BEGIN_RING(evo, 0, 0x0084, 1);
465 OUT_RING (evo, 0x00000000);
466
467 nv_wo32(disp->ntfy, 0x000, 0x00000000);
468 FIRE_RING (evo);
469
470 start = ptimer->read(dev);
471 do {
472 nv_wr32(dev, 0x61002c, 0x370);
473 nv_wr32(dev, 0x000140, 1);
474
475 if (nv_ro32(disp->ntfy, 0x000))
476 return 0;
477 } while (ptimer->read(dev) - start < 2000000000ULL);
478
479 return -EBUSY;
480}
481
446static void 482static void
447nv50_crtc_prepare(struct drm_crtc *crtc) 483nv50_crtc_prepare(struct drm_crtc *crtc)
448{ 484{
@@ -459,23 +495,13 @@ static void
459nv50_crtc_commit(struct drm_crtc *crtc) 495nv50_crtc_commit(struct drm_crtc *crtc)
460{ 496{
461 struct drm_device *dev = crtc->dev; 497 struct drm_device *dev = crtc->dev;
462 struct nouveau_channel *evo = nv50_display(dev)->master;
463 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 498 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
464 int ret;
465 499
466 NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); 500 NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
467 501
468 nv50_crtc_blank(nv_crtc, false); 502 nv50_crtc_blank(nv_crtc, false);
469 drm_vblank_post_modeset(dev, nv_crtc->index); 503 drm_vblank_post_modeset(dev, nv_crtc->index);
470 504 nv50_crtc_wait_complete(crtc);
471 ret = RING_SPACE(evo, 2);
472 if (ret) {
473 NV_ERROR(dev, "no space while committing crtc\n");
474 return;
475 }
476 BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
477 OUT_RING (evo, 0);
478 FIRE_RING (evo);
479} 505}
480 506
481static bool 507static bool
@@ -488,7 +514,7 @@ nv50_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
488static int 514static int
489nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, 515nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
490 struct drm_framebuffer *passed_fb, 516 struct drm_framebuffer *passed_fb,
491 int x, int y, bool update, bool atomic) 517 int x, int y, bool atomic)
492{ 518{
493 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 519 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
494 struct drm_device *dev = nv_crtc->base.dev; 520 struct drm_device *dev = nv_crtc->base.dev;
@@ -598,15 +624,6 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
598 nv50_crtc_lut_load(crtc); 624 nv50_crtc_lut_load(crtc);
599 } 625 }
600 626
601 if (update) {
602 ret = RING_SPACE(evo, 2);
603 if (ret)
604 return ret;
605 BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
606 OUT_RING(evo, 0);
607 FIRE_RING(evo);
608 }
609
610 return 0; 627 return 0;
611} 628}
612 629
@@ -696,14 +713,20 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
696 nv_crtc->set_dither(nv_crtc, nv_connector->use_dithering, false); 713 nv_crtc->set_dither(nv_crtc, nv_connector->use_dithering, false);
697 nv_crtc->set_scale(nv_crtc, nv_connector->scaling_mode, false); 714 nv_crtc->set_scale(nv_crtc, nv_connector->scaling_mode, false);
698 715
699 return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false, false); 716 return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
700} 717}
701 718
702static int 719static int
703nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 720nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
704 struct drm_framebuffer *old_fb) 721 struct drm_framebuffer *old_fb)
705{ 722{
706 return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, true, false); 723 int ret;
724
725 ret = nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
726 if (ret)
727 return ret;
728
729 return nv50_crtc_wait_complete(crtc);
707} 730}
708 731
709static int 732static int
@@ -711,7 +734,13 @@ nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
711 struct drm_framebuffer *fb, 734 struct drm_framebuffer *fb,
712 int x, int y, enum mode_set_atomic state) 735 int x, int y, enum mode_set_atomic state)
713{ 736{
714 return nv50_crtc_do_mode_set_base(crtc, fb, x, y, true, true); 737 int ret;
738
739 ret = nv50_crtc_do_mode_set_base(crtc, fb, x, y, true);
740 if (ret)
741 return ret;
742
743 return nv50_crtc_wait_complete(crtc);
715} 744}
716 745
717static const struct drm_crtc_helper_funcs nv50_crtc_helper_funcs = { 746static const struct drm_crtc_helper_funcs nv50_crtc_helper_funcs = {
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index e295a17d68f..09d7994ea09 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -183,7 +183,7 @@ nv50_display_init(struct drm_device *dev)
183 return ret; 183 return ret;
184 BEGIN_RING(evo, 0, NV50_EVO_UNK84, 2); 184 BEGIN_RING(evo, 0, NV50_EVO_UNK84, 2);
185 OUT_RING(evo, NV50_EVO_UNK84_NOTIFY_DISABLED); 185 OUT_RING(evo, NV50_EVO_UNK84_NOTIFY_DISABLED);
186 OUT_RING(evo, NV50_EVO_DMA_NOTIFY_HANDLE_NONE); 186 OUT_RING(evo, NvEvoSync);
187 BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, FB_DMA), 1); 187 BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, FB_DMA), 1);
188 OUT_RING(evo, NV50_EVO_CRTC_FB_DMA_HANDLE_NONE); 188 OUT_RING(evo, NV50_EVO_CRTC_FB_DMA_HANDLE_NONE);
189 BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK0800), 1); 189 BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK0800), 1);
diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h
index ea37f230aee..a51b8853a92 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.h
+++ b/drivers/gpu/drm/nouveau/nv50_display.h
@@ -37,6 +37,7 @@
37 37
38struct nv50_display { 38struct nv50_display {
39 struct nouveau_channel *master; 39 struct nouveau_channel *master;
40 struct nouveau_gpuobj *ntfy;
40 41
41 struct tasklet_struct tasklet; 42 struct tasklet_struct tasklet;
42 struct { 43 struct {
diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c
index 9703f759b71..eea96205fca 100644
--- a/drivers/gpu/drm/nouveau/nv50_evo.c
+++ b/drivers/gpu/drm/nouveau/nv50_evo.c
@@ -203,6 +203,7 @@ nv50_evo_destroy(struct drm_device *dev)
203{ 203{
204 struct nv50_display *disp = nv50_display(dev); 204 struct nv50_display *disp = nv50_display(dev);
205 205
206 nouveau_gpuobj_ref(NULL, &disp->ntfy);
206 nv50_evo_channel_del(&disp->master); 207 nv50_evo_channel_del(&disp->master);
207} 208}
208 209
@@ -251,6 +252,25 @@ nv50_evo_create(struct drm_device *dev)
251 if (ret) 252 if (ret)
252 goto err; 253 goto err;
253 254
255 /* not sure exactly what this is..
256 *
257 * the first dword of the structure is used by nvidia to wait on
258 * full completion of an EVO "update" command.
259 *
260 * method 0x8c on the master evo channel will fill a lot more of
261 * this structure with some undefined info
262 */
263 ret = nouveau_gpuobj_new(dev, disp->master, 0x1000, 0,
264 NVOBJ_FLAG_ZERO_ALLOC, &disp->ntfy);
265 if (ret)
266 goto err;
267
268 ret = nv50_evo_dmaobj_new(disp->master, 0x3d, NvEvoSync, 0, 0x19,
269 disp->ntfy->vinst, disp->ntfy->vinst +
270 disp->ntfy->size, 0x00010000);
271 if (ret)
272 goto err;
273
254 /* create some default objects for the scanout memtypes we support */ 274 /* create some default objects for the scanout memtypes we support */
255 if (dev_priv->card_type >= NV_C0) { 275 if (dev_priv->card_type >= NV_C0) {
256 ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB32, 0xfe, 0x19, 276 ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB32, 0xfe, 0x19,