|
@@ -704,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 **)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.
|
|
@@ -841,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,
|