Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[powerpc.git] / drivers / char / drm / r300_cmdbuf.c
index c08fa50..26bdf2c 100644 (file)
@@ -214,13 +214,13 @@ void r300_init_reg_flags(void)
        ADD_RANGE(0x4F54, 1);
 
        ADD_RANGE(R300_TX_FILTER_0, 16);
-       ADD_RANGE(R300_TX_UNK1_0, 16);
+       ADD_RANGE(R300_TX_FILTER1_0, 16);
        ADD_RANGE(R300_TX_SIZE_0, 16);
        ADD_RANGE(R300_TX_FORMAT_0, 16);
        ADD_RANGE(R300_TX_PITCH_0, 16);
        /* Texture offset is dangerous and needs more checking */
        ADD_RANGE_MARK(R300_TX_OFFSET_0, 16, MARK_CHECK_OFFSET);
-       ADD_RANGE(R300_TX_UNK4_0, 16);
+       ADD_RANGE(R300_TX_CHROMA_KEY_0, 16);
        ADD_RANGE(R300_TX_BORDER_COLOR_0, 16);
 
        /* Sporadic registers used as primitives are emitted */
@@ -242,8 +242,10 @@ static __inline__ int r300_check_range(unsigned reg, int count)
        return 0;
 }
 
-  /* we expect offsets passed to the framebuffer to be either within video memory or
-     within AGP space */
+/*
+ * we expect offsets passed to the framebuffer to be either within video 
+ * memory or within AGP space 
+ */
 static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv,
                                        u32 offset)
 {
@@ -251,11 +253,11 @@ static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv,
           but this value is not being kept.
           This code is correct for now (does the same thing as the
           code that sets MC_FB_LOCATION) in radeon_cp.c */
-       if ((offset >= dev_priv->fb_location) &&
-           (offset < dev_priv->gart_vm_start))
+       if (offset >= dev_priv->fb_location &&
+           offset < (dev_priv->fb_location + dev_priv->fb_size))
                return 0;
-       if ((offset >= dev_priv->gart_vm_start) &&
-           (offset < dev_priv->gart_vm_start + dev_priv->gart_size))
+       if (offset >= dev_priv->gart_vm_start &&
+           offset < (dev_priv->gart_vm_start + dev_priv->gart_size))
                return 0;
        return 1;
 }
@@ -490,6 +492,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
 
        return 0;
 }
+
 static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
                                             drm_radeon_kcmd_buffer_t *cmdbuf)
 {
@@ -701,6 +704,64 @@ static void r300_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
        buf->used = 0;
 }
 
+static int r300_scratch(drm_radeon_private_t *dev_priv,
+                       drm_radeon_kcmd_buffer_t *cmdbuf,
+                       drm_r300_cmd_header_t header)
+{
+       u32 *ref_age_base;
+       u32 i, buf_idx, h_pending;
+       RING_LOCALS;
+       
+       if (cmdbuf->bufsz < 
+           (sizeof(u64) + header.scratch.n_bufs * sizeof(buf_idx))) {
+               return DRM_ERR(EINVAL);
+       }
+       
+       if (header.scratch.reg >= 5) {
+               return DRM_ERR(EINVAL);
+       }
+       
+       dev_priv->scratch_ages[header.scratch.reg]++;
+       
+       ref_age_base =  (u32 *)(unsigned long)*((uint64_t *)cmdbuf->buf);
+       
+       cmdbuf->buf += sizeof(u64);
+       cmdbuf->bufsz -= sizeof(u64);
+       
+       for (i=0; i < header.scratch.n_bufs; i++) {
+               buf_idx = *(u32 *)cmdbuf->buf;
+               buf_idx *= 2; /* 8 bytes per buf */
+               
+               if (DRM_COPY_TO_USER(ref_age_base + buf_idx, &dev_priv->scratch_ages[header.scratch.reg], sizeof(u32))) {
+                       return DRM_ERR(EINVAL);
+               }
+                                       
+               if (DRM_COPY_FROM_USER(&h_pending, ref_age_base + buf_idx + 1, sizeof(u32))) {
+                       return DRM_ERR(EINVAL);
+               }
+                                       
+               if (h_pending == 0) {
+                       return DRM_ERR(EINVAL);
+               }
+                                       
+               h_pending--;
+                                               
+               if (DRM_COPY_TO_USER(ref_age_base + buf_idx + 1, &h_pending, sizeof(u32))) {
+                       return DRM_ERR(EINVAL);
+               }
+                                       
+               cmdbuf->buf += sizeof(buf_idx);
+               cmdbuf->bufsz -= sizeof(buf_idx);
+       }
+       
+       BEGIN_RING(2);
+       OUT_RING(CP_PACKET0(RADEON_SCRATCH_REG0 + header.scratch.reg * 4, 0));
+       OUT_RING(dev_priv->scratch_ages[header.scratch.reg]);
+       ADVANCE_RING();
+       
+       return 0;
+}
+
 /**
  * Parses and validates a user-supplied command buffer and emits appropriate
  * commands on the DMA ring buffer.
@@ -838,6 +899,15 @@ int r300_do_cp_cmdbuf(drm_device_t *dev,
                        }
                        break;
 
+               case R300_CMD_SCRATCH:
+                       DRM_DEBUG("R300_CMD_SCRATCH\n");
+                       ret = r300_scratch(dev_priv, cmdbuf, header);
+                       if (ret) {
+                               DRM_ERROR("r300_scratch failed\n");
+                               goto cleanup;
+                       }
+                       break;
+                       
                default:
                        DRM_ERROR("bad cmd_type %i at %p\n",
                                  header.header.cmd_type,