nvc0: prevent interruption of m2mf push
authorChristoph Bumiller <e0425955@student.tuwien.ac.at>
Tue, 13 Sep 2011 21:02:23 +0000 (23:02 +0200)
committerChristoph Bumiller <e0425955@student.tuwien.ac.at>
Wed, 14 Sep 2011 14:19:52 +0000 (16:19 +0200)
M2MF will trap if the data stream is interrupted by a QUERY fence
and report too much or not enough data.

src/gallium/drivers/nvc0/nvc0_transfer.c

index 69d4a90..6404c8c 100644 (file)
@@ -111,33 +111,31 @@ nvc0_m2mf_push_linear(struct nouveau_context *nv,
    uint32_t *src = (uint32_t *)data;
    unsigned count = (size + 3) / 4;
 
-   MARK_RING (chan, 8, 2);
-
-   BEGIN_RING(chan, RING_MF(OFFSET_OUT_HIGH), 2);
-   OUT_RELOCh(chan, dst, offset, domain | NOUVEAU_BO_WR);
-   OUT_RELOCl(chan, dst, offset, domain | NOUVEAU_BO_WR);
-   BEGIN_RING(chan, RING_MF(LINE_LENGTH_IN), 2);
-   OUT_RING  (chan, size);
-   OUT_RING  (chan, 1);
-   BEGIN_RING(chan, RING_MF(EXEC), 1);
-   OUT_RING  (chan, 0x100111);
-
    while (count) {
-      unsigned nr = AVAIL_RING(chan);
+      unsigned nr;
 
-      if (nr < 9) {
-         FIRE_RING(chan);
-         nouveau_bo_validate(chan, dst, NOUVEAU_BO_WR);
-         continue;
-      }
-      nr = MIN2(count, nr - 1);
+      MARK_RING (chan, 16, 2);
+
+      nr = AVAIL_RING(chan) - 9;
+      nr = MIN2(count, nr);
       nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN);
-   
+
+      BEGIN_RING(chan, RING_MF(OFFSET_OUT_HIGH), 2);
+      OUT_RELOCh(chan, dst, offset, domain | NOUVEAU_BO_WR);
+      OUT_RELOCl(chan, dst, offset, domain | NOUVEAU_BO_WR);
+      BEGIN_RING(chan, RING_MF(LINE_LENGTH_IN), 2);
+      OUT_RING  (chan, nr * 4);
+      OUT_RING  (chan, 1);
+      BEGIN_RING(chan, RING_MF(EXEC), 1);
+      OUT_RING  (chan, 0x100111);
+
+      /* must not be interrupted (trap on QUERY fence, 0x50 works however) */
       BEGIN_RING_NI(chan, RING_MF(DATA), nr);
       OUT_RINGp (chan, src, nr);
 
-      src += nr;
       count -= nr;
+      src += nr;
+      offset += nr * 4;
    }
 }