[Nouveau] [PATCH 3/3] nouveau: add vblank methods on newer cards

Maarten Lankhorst maarten.lankhorst at canonical.com
Fri Jul 27 05:24:57 PDT 2012


Allow the software channel to be created now, since methods
for vblanking have been implemented.

The instmem flush seems to be needed on fermi to prevent a
race, but I enabled it on earlier cards too since they seem
to be susceptible to the same race.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst at canonical.com>

---
 drivers/gpu/drm/nouveau/nouveau_abi16.c   |    9 ----
 drivers/gpu/drm/nouveau/nouveau_display.c |    8 +++-
 drivers/gpu/drm/nouveau/nouveau_drv.h     |    1 
 drivers/gpu/drm/nouveau/nv50_display.c    |   25 ++++++++----
 drivers/gpu/drm/nouveau/nv50_software.c   |    2 -
 drivers/gpu/drm/nouveau/nvc0_software.c   |   63 +++++++++++++++++++++++++++++
 drivers/gpu/drm/nouveau/nvd0_display.c    |    5 ++
 7 files changed, 95 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index ff23d88..e3a3a0b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -173,15 +173,8 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
 		return -EINVAL;
 
 	/* compatibility with userspace that assumes 506e for all chipsets */
-	if (init->class == 0x506e) {
+	if (init->class == 0x506e)
 		init->class = nouveau_software_class(dev);
-		if (init->class == 0x906e)
-			return 0;
-	} else
-	if (init->class == 0x906e) {
-		NV_ERROR(dev, "906e not supported yet\n");
-		return -EINVAL;
-	}
 
 	chan = nouveau_channel_get(file_priv, init->channel);
 	if (IS_ERR(chan))
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 69688ef..fa0cf14 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -364,7 +364,9 @@ nouveau_vblank_enable(struct drm_device *dev, int crtc)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-	if (dev_priv->card_type >= NV_50)
+	if (dev_priv->card_type >= NV_D0)
+		nv_mask(dev, 0x6100c0 + (crtc * 0x800), 0x5, 0x5);
+	else if (dev_priv->card_type >= NV_50)
 		nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0,
 			NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc));
 	else
@@ -379,7 +381,9 @@ nouveau_vblank_disable(struct drm_device *dev, int crtc)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-	if (dev_priv->card_type >= NV_50)
+	if (dev_priv->card_type >= NV_D0)
+		nv_mask(dev, 0x6100c0 + (crtc * 0x800), 0x5, 0);
+	else if (dev_priv->card_type >= NV_50)
 		nv_mask(dev, NV50_PDISPLAY_INTR_EN_1,
 			NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0);
 	else
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index fbf5fbf..ab1bf0d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -1374,6 +1374,7 @@ int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 			   struct drm_pending_vblank_event *event);
 int nouveau_finish_page_flip(struct nouveau_channel *,
 			     struct nouveau_page_flip_state *);
+void nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc);
 int nouveau_display_dumb_create(struct drm_file *, struct drm_device *,
 				struct drm_mode_create_dumb *args);
 int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *,
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index b244d99..ec0ad95 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -643,7 +643,7 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
 	return script;
 }
 
-static void
+void
 nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -655,18 +655,29 @@ nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc)
 			continue;
 
 		spin_lock(&psw->peephole_lock);
-		nv_wr32(dev, 0x001704, pch->vblank.channel);
-		nv_wr32(dev, 0x001710, 0x80000000 | pch->vblank.ctxdma);
-		if (dev_priv->chipset == 0x50) {
-			nv_wr32(dev, 0x001570, pch->vblank.offset);
-			nv_wr32(dev, 0x001574, pch->vblank.value);
+		if (dev_priv->chipset < 0xc0) {
+			nv_wr32(dev, 0x001704, pch->vblank.channel);
+			nv_wr32(dev, 0x001710, 0x80000000 | pch->vblank.ctxdma);
+			dev_priv->engine.instmem.flush(dev);
+
+			if (dev_priv->chipset == 0x50) {
+				nv_wr32(dev, 0x001570, pch->vblank.offset);
+				nv_wr32(dev, 0x001574, pch->vblank.value);
+			} else {
+				nv_wr32(dev, 0x060010, pch->vblank.offset);
+				nv_wr32(dev, 0x060014, pch->vblank.value);
+			}
 		} else {
+			nv_wr32(dev, 0x001718, 0x80000000 | pch->vblank.channel);
+			dev_priv->engine.instmem.flush(dev);
+
+			nv_wr32(dev, 0x06000c, pch->vblank.ctxdma);
 			nv_wr32(dev, 0x060010, pch->vblank.offset);
 			nv_wr32(dev, 0x060014, pch->vblank.value);
 		}
 		spin_unlock(&psw->peephole_lock);
 
-		list_del(&pch->vblank.list);
+		list_del_init(&pch->vblank.list);
 		drm_vblank_put(dev, crtc);
 	}
 
diff --git a/drivers/gpu/drm/nouveau/nv50_software.c b/drivers/gpu/drm/nouveau/nv50_software.c
index df554d9..1f3ef11 100644
--- a/drivers/gpu/drm/nouveau/nv50_software.c
+++ b/drivers/gpu/drm/nouveau/nv50_software.c
@@ -75,7 +75,7 @@ mthd_vblsem_release(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
 	struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
 	struct drm_device *dev = chan->dev;
 
-	if (data > 1)
+	if (data > 1 || !list_empty(&pch->base.vblank.list))
 		return -EINVAL;
 
 	drm_vblank_get(dev, data);
diff --git a/drivers/gpu/drm/nouveau/nvc0_software.c b/drivers/gpu/drm/nouveau/nvc0_software.c
index 4fd14cf..5bd381c 100644
--- a/drivers/gpu/drm/nouveau/nvc0_software.c
+++ b/drivers/gpu/drm/nouveau/nvc0_software.c
@@ -48,6 +48,63 @@ nvc0_software_crtc(struct nouveau_channel *chan, int crtc)
 	return pch->dispc_vma[crtc].offset;
 }
 
+static int
+nvc0_swmthd_vblsem_offset_high(struct nouveau_channel *chan,
+			u32 class, u32 mthd, u32 data)
+{
+	struct nvc0_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
+
+	pch->base.vblank.ctxdma = data;
+	return 0;
+}
+
+static int
+nvc0_swmthd_vblsem_offset_low(struct nouveau_channel *chan,
+			u32 class, u32 mthd, u32 data)
+{
+	struct nvc0_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
+
+	pch->base.vblank.offset = data;
+	return 0;
+}
+
+static int
+nvc0_swmthd_vblsem_release_val(struct nouveau_channel *chan,
+			     u32 class, u32 mthd, u32 data)
+{
+	struct nvc0_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
+
+	pch->base.vblank.value = data;
+	return 0;
+}
+
+static int
+nvc0_swmthd_vblsem_release(struct nouveau_channel *chan,
+			   u32 class, u32 mthd, u32 data)
+{
+	struct nvc0_software_priv *psw = nv_engine(chan->dev, NVOBJ_ENGINE_SW);
+	struct nvc0_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
+	struct drm_device *dev = chan->dev;
+
+	if (data >= dev->mode_config.num_crtc ||
+	    !list_empty(&pch->base.vblank.list))
+		return -EINVAL;
+
+	drm_vblank_get(dev, data);
+
+	pch->base.vblank.head = data;
+	list_add(&pch->base.vblank.list, &psw->base.vblank);
+	return 0;
+}
+
+static int
+nvc0_swmthd_page_flip(struct nouveau_channel *chan,
+		      u32 class, u32 mthd, u32 data)
+{
+	nouveau_finish_page_flip(chan, NULL);
+	return 0;
+}
+
 bool
 nvc0_software_method(struct drm_device *dev, u32 chid, u32 class, u32 mthd, u32 data)
 {
@@ -116,6 +173,7 @@ nvc0_software_context_new(struct nouveau_channel *chan, int engine)
 		return -ENOMEM;
 
 	nouveau_software_context_new(&pch->base);
+	pch->base.vblank.channel = chan->ramin->vinst >> 12;
 	chan->engctx[engine] = pch;
 
 	/* map display semaphore buffers into channel's vm */
@@ -205,5 +263,10 @@ nvc0_software_create(struct drm_device *dev)
 
 	NVOBJ_ENGINE_ADD(dev, SW, &psw->base.base);
 	NVOBJ_CLASS(dev, 0x906e, SW);
+	NVOBJ_MTHD (dev, 0x906e, 0x0200, nvc0_swmthd_vblsem_offset_high);
+	NVOBJ_MTHD (dev, 0x906e, 0x0204, nvc0_swmthd_vblsem_offset_low);
+	NVOBJ_MTHD (dev, 0x906e, 0x0208, nvc0_swmthd_vblsem_release_val);
+	NVOBJ_MTHD (dev, 0x906e, 0x020c, nvc0_swmthd_vblsem_release);
+	NVOBJ_MTHD (dev, 0x906e, 0x0210, nvc0_swmthd_page_flip);
 	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c
index dac525b..2985a5a 100644
--- a/drivers/gpu/drm/nouveau/nvd0_display.c
+++ b/drivers/gpu/drm/nouveau/nvd0_display.c
@@ -1836,6 +1836,11 @@ nvd0_display_intr(struct drm_device *dev)
 			u32 stat = nv_rd32(dev, 0x6100bc + (i * 0x800));
 			nv_wr32(dev, 0x6100bc + (i * 0x800), stat);
 			intr &= ~mask;
+			nv50_display_vblank_crtc_handler(dev, i);
+
+			/* This read seems to be required for vblank to work
+			 * correctly a second time on nvd9 */
+			nv_rd32(dev, 0x6100c0 + (i * 0x800));
 		}
 	}
 



More information about the Nouveau mailing list