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 <[email protected]>

---
 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));
                }
        }
 

_______________________________________________
Nouveau mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/nouveau

Reply via email to