Skip to contentSkip to conversation

nouveau: add vblank methods on newer cards

PATCH New Maarten Lankhorst 1 participant 1 message Jul 27, 2012

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 3/3 nouveau: add vblank methods on newer cards

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.

---
 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(-)
drivers/gpu/drm/nouveau/nouveau_abi16.c +1 -8
index ff23d88..e3a3a0b 100644
@@ -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))
drivers/gpu/drm/nouveau/nouveau_display.c +6 -2
index 69688ef..fa0cf14 100644
@@ -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
drivers/gpu/drm/nouveau/nouveau_drv.h +1 -0
index fbf5fbf..ab1bf0d 100644
@@ -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 *,
drivers/gpu/drm/nouveau/nv50_display.c +18 -7
index b244d99..ec0ad95 100644
@@ -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);
 	}
 
drivers/gpu/drm/nouveau/nv50_software.c +1 -1
index df554d9..1f3ef11 100644
@@ -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);
drivers/gpu/drm/nouveau/nvc0_software.c +63 -0

80 lines not on this page · raw message

drivers/gpu/drm/nouveau/nvd0_display.c +5 -0
index dac525b..2985a5a 100644
@@ -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));
 		}
 	}