summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shared-core/i915_dma.c135
-rw-r--r--shared-core/i915_drm.h10
2 files changed, 68 insertions, 77 deletions
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index a36ca37e..ed563086 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -739,9 +739,15 @@ int i915_apply_reloc(struct drm_file *file_priv, int num_buffers,
unsigned index;
unsigned long new_cmd_offset;
u32 val;
- int ret;
+ int ret, i;
+ int buf_index = -1;
+
+ for (i = 0; i <= num_buffers; i++)
+ if (buffers[i].buffer)
+ if (reloc[2] == buffers[i].buffer->base.hash.key)
+ buf_index = i;
- if (reloc[2] >= num_buffers) {
+ if (buf_index == -1) {
DRM_ERROR("Illegal relocation buffer %08X\n", reloc[2]);
return -EINVAL;
}
@@ -750,7 +756,7 @@ int i915_apply_reloc(struct drm_file *file_priv, int num_buffers,
* Short-circuit relocations that were correctly
* guessed by the client
*/
- if (buffers[reloc[2]].presumed_offset_correct && !DRM_DEBUG_RELOCATION)
+ if (buffers[buf_index].presumed_offset_correct && !DRM_DEBUG_RELOCATION)
return 0;
new_cmd_offset = reloc[0];
@@ -777,17 +783,17 @@ int i915_apply_reloc(struct drm_file *file_priv, int num_buffers,
relocatee->page_offset = (relocatee->offset & PAGE_MASK);
}
- val = buffers[reloc[2]].buffer->offset;
+ val = buffers[buf_index].buffer->offset;
index = (reloc[0] - relocatee->page_offset) >> 2;
/* add in validate */
val = val + reloc[1];
if (DRM_DEBUG_RELOCATION) {
- if (buffers[reloc[2]].presumed_offset_correct &&
+ if (buffers[buf_index].presumed_offset_correct &&
relocatee->data_page[index] != val) {
DRM_DEBUG ("Relocation mismatch source %d target %d buffer %d user %08x kernel %08x\n",
- reloc[0], reloc[1], reloc[2], relocatee->data_page[index], val);
+ reloc[0], reloc[1], buf_index, relocatee->data_page[index], val);
}
}
relocatee->data_page[index] = val;
@@ -796,94 +802,79 @@ int i915_apply_reloc(struct drm_file *file_priv, int num_buffers,
int i915_process_relocs(struct drm_file *file_priv,
uint32_t buf_handle,
- uint32_t *reloc_buf_handle,
+ uint32_t __user **reloc_user_ptr,
struct i915_relocatee_info *relocatee,
struct drm_i915_validate_buffer *buffers,
uint32_t num_buffers)
{
- struct drm_device *dev = file_priv->head->dev;
- struct drm_buffer_object *reloc_list_object;
- uint32_t cur_handle = *reloc_buf_handle;
- uint32_t *reloc_page;
- int ret, reloc_is_iomem, reloc_stride;
- uint32_t num_relocs, reloc_offset, reloc_end, reloc_page_offset, next_offset, cur_offset;
- struct drm_bo_kmap_obj reloc_kmap;
-
- memset(&reloc_kmap, 0, sizeof(reloc_kmap));
-
- mutex_lock(&dev->struct_mutex);
- reloc_list_object = drm_lookup_buffer_object(file_priv, cur_handle, 1);
- mutex_unlock(&dev->struct_mutex);
- if (!reloc_list_object)
- return -EINVAL;
+ int ret, reloc_stride;
+ uint32_t cur_offset;
+ uint32_t reloc_count;
+ uint32_t reloc_type;
+ uint32_t reloc_buf_size;
+ uint32_t *reloc_buf = NULL;
+ int i;
- ret = drm_bo_kmap(reloc_list_object, 0, 1, &reloc_kmap);
+ /* do a copy from user from the user ptr */
+ ret = get_user(reloc_count, *reloc_user_ptr);
if (ret) {
DRM_ERROR("Could not map relocation buffer.\n");
goto out;
}
- reloc_page = drm_bmo_virtual(&reloc_kmap, &reloc_is_iomem);
- num_relocs = reloc_page[0] & 0xffff;
+ ret = get_user(reloc_type, (*reloc_user_ptr)+1);
+ if (ret) {
+ DRM_ERROR("Could not map relocation buffer.\n");
+ goto out;
+ }
- if ((reloc_page[0] >> 16) & 0xffff) {
+ if (reloc_type != 0) {
DRM_ERROR("Unsupported relocation type requested\n");
+ ret = -EINVAL;
goto out;
}
- /* get next relocate buffer handle */
- *reloc_buf_handle = reloc_page[1];
- reloc_stride = I915_RELOC0_STRIDE * sizeof(uint32_t); /* may be different for other types of relocs */
-
- DRM_DEBUG("num relocs is %d, next is %08X\n", num_relocs, reloc_page[1]);
-
- reloc_page_offset = 0;
- reloc_offset = I915_RELOC_HEADER * sizeof(uint32_t);
- reloc_end = reloc_offset + (num_relocs * reloc_stride);
-
- do {
- next_offset = drm_bo_offset_end(reloc_offset, reloc_end);
+ reloc_buf_size = reloc_count * I915_RELOC0_STRIDE * sizeof(uint32_t);
+ reloc_buf = kmalloc(reloc_buf_size, GFP_KERNEL);
+ if (!reloc_buf) {
+ DRM_ERROR("Out of memory for reloc buffer\n");
+ ret = -ENOMEM;
+ goto out;
+ }
- do {
- cur_offset = ((reloc_offset + reloc_page_offset) & ~PAGE_MASK) / sizeof(uint32_t);
- ret = i915_apply_reloc(file_priv, num_buffers,
- buffers, relocatee, &reloc_page[cur_offset]);
- if (ret)
- goto out;
+ if (copy_from_user(reloc_buf, *reloc_user_ptr, reloc_buf_size)) {
+ ret = -EFAULT;
+ goto out;
+ }
- reloc_offset += reloc_stride;
- } while (reloc_offset < next_offset);
+ /* get next relocate buffer handle */
+ *reloc_user_ptr = (uint32_t *)*(unsigned long *)&reloc_buf[2];
- drm_bo_kunmap(&reloc_kmap);
+ reloc_stride = I915_RELOC0_STRIDE * sizeof(uint32_t); /* may be different for other types of relocs */
- reloc_offset = next_offset;
- if (reloc_offset != reloc_end) {
- ret = drm_bo_kmap(reloc_list_object, reloc_offset >> PAGE_SHIFT, 1, &reloc_kmap);
- if (ret) {
- DRM_ERROR("Could not map relocation buffer.\n");
- goto out;
- }
+ DRM_DEBUG("num relocs is %d, next is %p\n", reloc_count, *reloc_user_ptr);
- reloc_page = drm_bmo_virtual(&reloc_kmap, &reloc_is_iomem);
- reloc_page_offset = reloc_offset & ~PAGE_MASK;
- }
+ for (i = 0; i < reloc_count; i++) {
+ cur_offset = I915_RELOC_HEADER + (i * I915_RELOC0_STRIDE);
+
+ ret = i915_apply_reloc(file_priv, num_buffers, buffers,
+ relocatee, reloc_buf + cur_offset);
+ if (ret)
+ goto out;
+ }
- } while (reloc_offset != reloc_end);
out:
+
+ if (reloc_buf)
+ kfree(reloc_buf);
drm_bo_kunmap(&relocatee->kmap);
relocatee->data_page = NULL;
- drm_bo_kunmap(&reloc_kmap);
-
- mutex_lock(&dev->struct_mutex);
- drm_bo_usage_deref_locked(&reloc_list_object);
- mutex_unlock(&dev->struct_mutex);
-
return ret;
}
static int i915_exec_reloc(struct drm_file *file_priv, drm_handle_t buf_handle,
- drm_handle_t buf_reloc_handle,
+ uint32_t __user *reloc_user_ptr,
struct drm_i915_validate_buffer *buffers,
uint32_t buf_count)
{
@@ -917,8 +908,8 @@ static int i915_exec_reloc(struct drm_file *file_priv, drm_handle_t buf_handle,
goto out_err;
}
- while (buf_reloc_handle) {
- ret = i915_process_relocs(file_priv, buf_handle, &buf_reloc_handle, &relocatee, buffers, buf_count);
+ while (reloc_user_ptr) {
+ ret = i915_process_relocs(file_priv, buf_handle, &reloc_user_ptr, &relocatee, buffers, buf_count);
if (ret) {
DRM_ERROR("process relocs failed\n");
break;
@@ -948,8 +939,8 @@ int i915_validate_buffer_list(struct drm_file *file_priv,
int ret = 0;
unsigned buf_count = 0;
struct drm_device *dev = file_priv->head->dev;
- uint32_t buf_reloc_handle, buf_handle;
-
+ uint32_t buf_handle;
+ uint32_t __user *reloc_user_ptr;
do {
if (buf_count >= *num_buffers) {
@@ -984,10 +975,10 @@ int i915_validate_buffer_list(struct drm_file *file_priv,
}
buf_handle = req->bo_req.handle;
- buf_reloc_handle = arg.reloc_handle;
+ reloc_user_ptr = (uint32_t *)(unsigned long)arg.reloc_ptr;
- if (buf_reloc_handle) {
- ret = i915_exec_reloc(file_priv, buf_handle, buf_reloc_handle, buffers, buf_count);
+ if (reloc_user_ptr) {
+ ret = i915_exec_reloc(file_priv, buf_handle, reloc_user_ptr, buffers, buf_count);
if (ret)
goto out_err;
DRM_MEMORYBARRIER();
diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h
index cfa3f93a..c8a9cb76 100644
--- a/shared-core/i915_drm.h
+++ b/shared-core/i915_drm.h
@@ -329,9 +329,9 @@ typedef struct drm_i915_hws_addr {
/*
* Relocation header is 4 uint32_ts
- * 0 - (16-bit relocation type << 16)| 16 bit reloc count
- * 1 - buffer handle for another list of relocs
- * 2-3 - spare.
+ * 0 - 32 bit reloc count
+ * 1 - 32-bit relocation type
+ * 2-3 - 64-bit user buffer handle ptr for another list of relocs.
*/
#define I915_RELOC_HEADER 4
@@ -339,7 +339,7 @@ typedef struct drm_i915_hws_addr {
* type 0 relocation has 4-uint32_t stride
* 0 - offset into buffer
* 1 - delta to add in
- * 2 - index into buffer list
+ * 2 - buffer handle
* 3 - reserved (for optimisations later).
*/
#define I915_RELOC_TYPE_0 0
@@ -347,7 +347,7 @@ typedef struct drm_i915_hws_addr {
struct drm_i915_op_arg {
uint64_t next;
- uint32_t reloc_handle;
+ uint64_t reloc_ptr;
int handled;
union {
struct drm_bo_op_req req;