]> err.no Git - linux-2.6/blobdiff - drivers/gpu/drm/radeon/r300_cmdbuf.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[linux-2.6] / drivers / gpu / drm / radeon / r300_cmdbuf.c
index 4b3bd6303daf59ad90f20f2f75bcc0cb7d1626f0..4b27d9abb7bcba5b0b77b8ab2b8f48e60859c2f2 100644 (file)
@@ -77,6 +77,9 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
                                return -EFAULT;
                        }
 
+                       box.x2--; /* Hardware expects inclusive bottom-right corner */
+                       box.y2--;
+
                        if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
                                box.x1 = (box.x1) &
                                        R300_CLIPRECT_MASK;
@@ -95,8 +98,8 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
                                        R300_CLIPRECT_MASK;
                                box.y2 = (box.y2 + R300_CLIPRECT_OFFSET) &
                                        R300_CLIPRECT_MASK;
-
                        }
+
                        OUT_RING((box.x1 << R300_CLIPRECT_X_SHIFT) |
                                 (box.y1 << R300_CLIPRECT_Y_SHIFT));
                        OUT_RING((box.x2 << R300_CLIPRECT_X_SHIFT) |
@@ -577,22 +580,23 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
        return 0;
 }
 
-static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
-                                            drm_radeon_kcmd_buffer_t *cmdbuf)
+static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv,
+                                           drm_radeon_kcmd_buffer_t *cmdbuf)
 {
-       u32 *cmd = (u32 *) cmdbuf->buf;
-       int count, ret;
+       u32 *cmd;
+       int count;
+       int expected_count;
        RING_LOCALS;
 
-       count=(cmd[0]>>16) & 0x3fff;
+       cmd = (u32 *) cmdbuf->buf;
+       count = (cmd[0]>>16) & 0x3fff;
+       expected_count = cmd[1] >> 16;
+       if (!(cmd[1] & R300_VAP_VF_CNTL__INDEX_SIZE_32bit))
+               expected_count = (expected_count+1)/2;
 
-       if ((cmd[1] & 0x8000ffff) != 0x80000810) {
-               DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
-               return -EINVAL;
-       }
-       ret = !radeon_check_offset(dev_priv, cmd[2]);
-       if (ret) {
-               DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
+       if (count && count != expected_count) {
+               DRM_ERROR("3D_DRAW_INDX_2: packet size %i, expected %i\n",
+                       count, expected_count);
                return -EINVAL;
        }
 
@@ -604,6 +608,50 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
        cmdbuf->buf += (count+2)*4;
        cmdbuf->bufsz -= (count+2)*4;
 
+       if (!count) {
+               drm_r300_cmd_header_t header;
+
+               if (cmdbuf->bufsz < 4*4 + sizeof(header)) {
+                       DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER, but stream is too short.\n");
+                       return -EINVAL;
+               }
+
+               header.u = *(unsigned int *)cmdbuf->buf;
+
+               cmdbuf->buf += sizeof(header);
+               cmdbuf->bufsz -= sizeof(header);
+               cmd = (u32 *) cmdbuf->buf;
+
+               if (header.header.cmd_type != R300_CMD_PACKET3 ||
+                   header.packet3.packet != R300_CMD_PACKET3_RAW ||
+                   cmd[0] != CP_PACKET3(RADEON_CP_INDX_BUFFER, 2)) {
+                       DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER.\n");
+                       return -EINVAL;
+               }
+
+               if ((cmd[1] & 0x8000ffff) != 0x80000810) {
+                       DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
+                       return -EINVAL;
+               }
+               if (!radeon_check_offset(dev_priv, cmd[2])) {
+                       DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
+                       return -EINVAL;
+               }
+               if (cmd[3] != expected_count) {
+                       DRM_ERROR("INDX_BUFFER: buffer size %i, expected %i\n",
+                               cmd[3], expected_count);
+                       return -EINVAL;
+               }
+
+               BEGIN_RING(4);
+               OUT_RING(cmd[0]);
+               OUT_RING_TABLE((int *)(cmdbuf->buf + 4), 3);
+               ADVANCE_RING();
+
+               cmdbuf->buf += 4*4;
+               cmdbuf->bufsz -= 4*4;
+       }
+
        return 0;
 }
 
@@ -648,18 +696,21 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
                return r300_emit_bitblt_multi(dev_priv, cmdbuf);
 
        case RADEON_CP_INDX_BUFFER:
-               /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */
-               return r300_emit_indx_buffer(dev_priv, cmdbuf);
+               DRM_ERROR("packet3 INDX_BUFFER without preceding 3D_DRAW_INDX_2 is illegal.\n");
+               return -EINVAL;
        case RADEON_CP_3D_DRAW_IMMD_2:
                /* triggers drawing using in-packet vertex data */
        case RADEON_CP_3D_DRAW_VBUF_2:
                /* triggers drawing of vertex buffers setup elsewhere */
+               dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED |
+                                          RADEON_PURGE_EMITED);
+               break;
        case RADEON_CP_3D_DRAW_INDX_2:
                /* triggers drawing using indices to vertex buffer */
                /* whenever we send vertex we clear flush & purge */
                dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED |
                                           RADEON_PURGE_EMITED);
-               break;
+               return r300_emit_draw_indx_2(dev_priv, cmdbuf);
        case RADEON_WAIT_FOR_IDLE:
        case RADEON_CP_NOP:
                /* these packets are safe */
@@ -757,7 +808,7 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv)
 {
        uint32_t cache_z, cache_3d, cache_2d;
        RING_LOCALS;
-       
+
        cache_z = R300_ZC_FLUSH;
        cache_2d = R300_RB2D_DC_FLUSH;
        cache_3d = R300_RB3D_DC_FLUSH;