drm/nv50: Keep track of the head a channel is vsync'ing to.
authorFrancisco Jerez <currojerez@riseup.net>
Sun, 24 Oct 2010 12:15:58 +0000 (14:15 +0200)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 3 Dec 2010 05:11:16 +0000 (15:11 +1000)
In a multihead setup vblank interrupts may end up enabled in both
heads. In that case we want to ignore the vblank interrupts coming
from the wrong CRTC to avoid tearing and unbalanced calls to
drm_vblank_get/put (fdo bug 31074).

Reported-by: Felix Leimbach <felix.leimbach@gmx.net>
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_graph.c

index 2bb1f1572a558bb4d1573b696cf48a885f5e0108..5814db82f778cc297ab6205f643af591c2f566b5 100644 (file)
@@ -257,6 +257,7 @@ struct nouveau_channel {
 
        struct {
                struct nouveau_gpuobj *vblsem;
+               uint32_t vblsem_head;
                uint32_t vblsem_offset;
                uint32_t vblsem_rval;
                struct list_head vbl_wait;
index 17b950abf20024f47a92c24bb8b1566237a23d7f..41b2128018703cc7832c21b9253cc2acedc024ac 100644 (file)
@@ -432,6 +432,9 @@ nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc)
 
        list_for_each_entry_safe(chan, tmp, &dev_priv->vbl_waiting,
                                 nvsw.vbl_wait) {
+               if (chan->nvsw.vblsem_head != crtc)
+                       continue;
+
                nouveau_bo_wr32(chan->notifier_bo, chan->nvsw.vblsem_offset,
                                                chan->nvsw.vblsem_rval);
                list_del(&chan->nvsw.vbl_wait);
index 6d81f4dab37d45fa76aa5975c02260d460b05d8b..e0f52942b2eb93aa80ea6298e1c20f075170b032 100644 (file)
@@ -387,7 +387,10 @@ nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan,
                return -EINVAL;
 
        drm_vblank_get(dev, data);
+
+       chan->nvsw.vblsem_head = data;
        list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting);
+
        return 0;
 }