summaryrefslogtreecommitdiff
path: root/linux-core/i915_execbuf.c
diff options
context:
space:
mode:
authorPekka Paalanen <pq@iki.fi>2009-02-16 20:43:02 +0200
committerPekka Paalanen <pq@iki.fi>2009-02-16 20:43:02 +0200
commite32aa6226fe98d8342647acf34decd3699eff5e4 (patch)
tree234a77fcca08f429d5c497f005d8ca8d59862430 /linux-core/i915_execbuf.c
parent709b82e1a5971fa58d627912402aa14a6d231cdd (diff)
Remove i915 driver sources from linux-core
Intel developers have stated, that their DRM development continues elsewhere in some Linux kernel trees. This makes the code in drm.git just dead weight. This removal allows further cleanup of compatibility code. shared-core and bsd-core are left untouched this time. Signed-off-by: Pekka Paalanen <pq@iki.fi> Acked-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'linux-core/i915_execbuf.c')
-rw-r--r--linux-core/i915_execbuf.c917
1 files changed, 0 insertions, 917 deletions
diff --git a/linux-core/i915_execbuf.c b/linux-core/i915_execbuf.c
deleted file mode 100644
index 804f3ac1..00000000
--- a/linux-core/i915_execbuf.c
+++ /dev/null
@@ -1,917 +0,0 @@
-/*
- * Copyright 2003-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
- * Dave Airlie
- * Keith Packard
- * ... ?
- */
-
-#include "drmP.h"
-#include "drm.h"
-#include "i915_drm.h"
-#include "i915_drv.h"
-
-#if DRM_DEBUG_CODE
-#define DRM_DEBUG_RELOCATION (drm_debug != 0)
-#else
-#define DRM_DEBUG_RELOCATION 0
-#endif
-
-enum i915_buf_idle {
- I915_RELOC_UNCHECKED,
- I915_RELOC_IDLE,
- I915_RELOC_BUSY
-};
-
-struct i915_relocatee_info {
- struct drm_buffer_object *buf;
- unsigned long offset;
- uint32_t *data_page;
- unsigned page_offset;
- struct drm_bo_kmap_obj kmap;
- int is_iomem;
- int dst;
- int idle;
- int performed_ring_relocs;
-#ifdef DRM_KMAP_ATOMIC_PROT_PFN
- unsigned long pfn;
- pgprot_t pg_prot;
-#endif
-};
-
-struct drm_i915_validate_buffer {
- struct drm_buffer_object *buffer;
- int presumed_offset_correct;
- void __user *data;
- int ret;
- enum i915_buf_idle idle;
-};
-
-/*
- * I'd like to use MI_STORE_DATA_IMM here, but I can't make
- * it work. Seems like GART writes are broken with that
- * instruction. Also I'm not sure that MI_FLUSH will
- * act as a memory barrier for that instruction. It will
- * for this single dword 2D blit.
- */
-
-static void i915_emit_ring_reloc(struct drm_device *dev, uint32_t offset,
- uint32_t value)
-{
- struct drm_i915_private *dev_priv =
- (struct drm_i915_private *)dev->dev_private;
-
- RING_LOCALS;
- i915_kernel_lost_context(dev);
- BEGIN_LP_RING(6);
- OUT_RING((0x02 << 29) | (0x40 << 22) | (0x3 << 20) | (0x3));
- OUT_RING((0x3 << 24) | (0xF0 << 16) | (0x40));
- OUT_RING((0x1 << 16) | (0x4));
- OUT_RING(offset);
- OUT_RING(value);
- OUT_RING(0);
- ADVANCE_LP_RING();
-}
-
-static void i915_dereference_buffers_locked(struct drm_i915_validate_buffer
- *buffers, unsigned num_buffers)
-{
- while (num_buffers--)
- drm_bo_usage_deref_locked(&buffers[num_buffers].buffer);
-}
-
-int i915_apply_reloc(struct drm_file *file_priv, int num_buffers,
- struct drm_i915_validate_buffer *buffers,
- struct i915_relocatee_info *relocatee, uint32_t * reloc)
-{
- unsigned index;
- unsigned long new_cmd_offset;
- u32 val;
- int ret, i;
- int buf_index = -1;
-
- /*
- * FIXME: O(relocs * buffers) complexity.
- */
-
- for (i = 0; i <= num_buffers; i++)
- if (buffers[i].buffer)
- if (reloc[2] == buffers[i].buffer->base.hash.key)
- buf_index = i;
-
- if (buf_index == -1) {
- DRM_ERROR("Illegal relocation buffer %08X\n", reloc[2]);
- return -EINVAL;
- }
-
- /*
- * Short-circuit relocations that were correctly
- * guessed by the client
- */
- if (buffers[buf_index].presumed_offset_correct && !DRM_DEBUG_RELOCATION)
- return 0;
-
- new_cmd_offset = reloc[0];
- if (!relocatee->data_page ||
- !drm_bo_same_page(relocatee->offset, new_cmd_offset)) {
- struct drm_bo_mem_reg *mem = &relocatee->buf->mem;
-
- drm_bo_kunmap(&relocatee->kmap);
- relocatee->data_page = NULL;
- relocatee->offset = new_cmd_offset;
-
- if (unlikely(relocatee->idle == I915_RELOC_UNCHECKED)) {
- ret = drm_bo_wait(relocatee->buf, 0, 1, 0, 0);
- if (ret)
- return ret;
- relocatee->idle = I915_RELOC_IDLE;
- }
-
- if (unlikely((mem->mem_type != DRM_BO_MEM_LOCAL) &&
- (mem->flags & DRM_BO_FLAG_CACHED_MAPPED)))
- drm_bo_evict_cached(relocatee->buf);
-
- ret = drm_bo_kmap(relocatee->buf, new_cmd_offset >> PAGE_SHIFT,
- 1, &relocatee->kmap);
- if (ret) {
- DRM_ERROR
- ("Could not map command buffer to apply relocs\n %08lx",
- new_cmd_offset);
- return ret;
- }
- relocatee->data_page = drm_bmo_virtual(&relocatee->kmap,
- &relocatee->is_iomem);
- relocatee->page_offset = (relocatee->offset & PAGE_MASK);
- }
-
- 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[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], buf_index,
- relocatee->data_page[index], val);
- }
- }
-
- if (relocatee->is_iomem)
- iowrite32(val, relocatee->data_page + index);
- else
- relocatee->data_page[index] = val;
- return 0;
-}
-
-int i915_process_relocs(struct drm_file *file_priv,
- uint32_t buf_handle,
- uint32_t __user ** reloc_user_ptr,
- struct i915_relocatee_info *relocatee,
- struct drm_i915_validate_buffer *buffers,
- uint32_t num_buffers)
-{
- 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;
-
- /* 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;
- }
-
- ret = get_user(reloc_type, (*reloc_user_ptr) + 1);
- if (ret) {
- DRM_ERROR("Could not map relocation buffer.\n");
- goto out;
- }
-
- if (reloc_type != 0) {
- DRM_ERROR("Unsupported relocation type requested\n");
- ret = -EINVAL;
- goto out;
- }
-
- reloc_buf_size =
- (I915_RELOC_HEADER +
- (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;
- }
-
- if (copy_from_user(reloc_buf, *reloc_user_ptr, reloc_buf_size)) {
- ret = -EFAULT;
- goto out;
- }
-
- /* get next relocate buffer handle */
- *reloc_user_ptr = (uint32_t *) * (unsigned long *)&reloc_buf[2];
-
- reloc_stride = I915_RELOC0_STRIDE * sizeof(uint32_t); /* may be different for other types of relocs */
-
- DRM_DEBUG("num relocs is %d, next is %p\n", reloc_count,
- *reloc_user_ptr);
-
- 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;
- }
-
- out:
- if (reloc_buf)
- kfree(reloc_buf);
-
- if (relocatee->data_page) {
- drm_bo_kunmap(&relocatee->kmap);
- relocatee->data_page = NULL;
- }
-
- return ret;
-}
-
-static int i915_exec_reloc(struct drm_file *file_priv, drm_handle_t buf_handle,
- uint32_t __user * reloc_user_ptr,
- struct drm_i915_validate_buffer *buffers,
- uint32_t buf_count)
-{
- struct drm_device *dev = file_priv->minor->dev;
- struct i915_relocatee_info relocatee;
- int ret = 0;
- int b;
-
- /*
- * Short circuit relocations when all previous
- * buffers offsets were correctly guessed by
- * the client
- */
- if (!DRM_DEBUG_RELOCATION) {
- for (b = 0; b < buf_count; b++)
- if (!buffers[b].presumed_offset_correct)
- break;
-
- if (b == buf_count)
- return 0;
- }
-
- memset(&relocatee, 0, sizeof(relocatee));
- relocatee.idle = I915_RELOC_UNCHECKED;
-
- mutex_lock(&dev->struct_mutex);
- relocatee.buf = drm_lookup_buffer_object(file_priv, buf_handle, 1);
- mutex_unlock(&dev->struct_mutex);
- if (!relocatee.buf) {
- DRM_DEBUG("relocatee buffer invalid %08x\n", buf_handle);
- ret = -EINVAL;
- goto out_err;
- }
-
- mutex_lock(&relocatee.buf->mutex);
- 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");
- goto out_err1;
- }
- }
-
- out_err1:
- mutex_unlock(&relocatee.buf->mutex);
- drm_bo_usage_deref_unlocked(&relocatee.buf);
- out_err:
- return ret;
-}
-
-static void i915_clear_relocatee(struct i915_relocatee_info *relocatee)
-{
- if (relocatee->data_page) {
-#ifndef DRM_KMAP_ATOMIC_PROT_PFN
- drm_bo_kunmap(&relocatee->kmap);
-#else
- kunmap_atomic(relocatee->data_page, KM_USER0);
-#endif
- relocatee->data_page = NULL;
- }
- relocatee->buf = NULL;
- relocatee->dst = ~0;
-}
-
-static int i915_update_relocatee(struct i915_relocatee_info *relocatee,
- struct drm_i915_validate_buffer *buffers,
- unsigned int dst, unsigned long dst_offset)
-{
- int ret;
-
- if (unlikely(dst != relocatee->dst || NULL == relocatee->buf)) {
- i915_clear_relocatee(relocatee);
- relocatee->dst = dst;
- relocatee->buf = buffers[dst].buffer;
- relocatee->idle = buffers[dst].idle;
-
- /*
- * Check for buffer idle. If the buffer is busy, revert to
- * ring relocations.
- */
-
- if (relocatee->idle == I915_RELOC_UNCHECKED) {
- preempt_enable();
- mutex_lock(&relocatee->buf->mutex);
-
- ret = drm_bo_wait(relocatee->buf, 0, 1, 1, 0);
- if (ret == 0)
- relocatee->idle = I915_RELOC_IDLE;
- else {
- relocatee->idle = I915_RELOC_BUSY;
- relocatee->performed_ring_relocs = 1;
- }
- mutex_unlock(&relocatee->buf->mutex);
- preempt_disable();
- buffers[dst].idle = relocatee->idle;
- }
- }
-
- if (relocatee->idle == I915_RELOC_BUSY)
- return 0;
-
- if (unlikely(dst_offset > relocatee->buf->num_pages * PAGE_SIZE)) {
- DRM_ERROR("Relocation destination out of bounds.\n");
- return -EINVAL;
- }
- if (unlikely(!drm_bo_same_page(relocatee->page_offset, dst_offset) ||
- NULL == relocatee->data_page)) {
-#ifdef DRM_KMAP_ATOMIC_PROT_PFN
- if (NULL != relocatee->data_page) {
- kunmap_atomic(relocatee->data_page, KM_USER0);
- relocatee->data_page = NULL;
- }
- ret = drm_bo_pfn_prot(relocatee->buf, dst_offset,
- &relocatee->pfn, &relocatee->pg_prot);
- if (ret) {
- DRM_ERROR("Can't map relocation destination.\n");
- return -EINVAL;
- }
- relocatee->data_page =
- kmap_atomic_prot_pfn(relocatee->pfn, KM_USER0,
- relocatee->pg_prot);
-#else
- if (NULL != relocatee->data_page) {
- drm_bo_kunmap(&relocatee->kmap);
- relocatee->data_page = NULL;
- }
-
- ret = drm_bo_kmap(relocatee->buf, dst_offset >> PAGE_SHIFT,
- 1, &relocatee->kmap);
- if (ret) {
- DRM_ERROR("Can't map relocation destination.\n");
- return ret;
- }
-
- relocatee->data_page = drm_bmo_virtual(&relocatee->kmap,
- &relocatee->is_iomem);
-#endif
- relocatee->page_offset = dst_offset & PAGE_MASK;
- }
- return 0;
-}
-
-static int i915_apply_post_reloc(uint32_t reloc[],
- struct drm_i915_validate_buffer *buffers,
- uint32_t num_buffers,
- struct i915_relocatee_info *relocatee)
-{
- uint32_t reloc_buffer = reloc[2];
- uint32_t dst_buffer = reloc[3];
- uint32_t val;
- uint32_t index;
- int ret;
-
- if (likely(buffers[reloc_buffer].presumed_offset_correct))
- return 0;
- if (unlikely(reloc_buffer >= num_buffers)) {
- DRM_ERROR("Invalid reloc buffer index.\n");
- return -EINVAL;
- }
- if (unlikely(dst_buffer >= num_buffers)) {
- DRM_ERROR("Invalid dest buffer index.\n");
- return -EINVAL;
- }
-
- ret = i915_update_relocatee(relocatee, buffers, dst_buffer, reloc[0]);
- if (unlikely(ret))
- return ret;
-
- val = buffers[reloc_buffer].buffer->offset;
- index = (reloc[0] - relocatee->page_offset) >> 2;
- val = val + reloc[1];
-
- if (relocatee->idle == I915_RELOC_BUSY) {
- i915_emit_ring_reloc(relocatee->buf->dev,
- relocatee->buf->offset + reloc[0], val);
- return 0;
- }
-#ifdef DRM_KMAP_ATOMIC_PROT_PFN
- relocatee->data_page[index] = val;
-#else
- if (likely(relocatee->is_iomem))
- iowrite32(val, relocatee->data_page + index);
- else
- relocatee->data_page[index] = val;
-#endif
-
- return 0;
-}
-
-static int i915_post_relocs(struct drm_file *file_priv,
- uint32_t __user * new_reloc_ptr,
- struct drm_i915_validate_buffer *buffers,
- unsigned int num_buffers)
-{
- uint32_t *reloc;
- uint32_t reloc_stride = I915_RELOC0_STRIDE * sizeof(uint32_t);
- uint32_t header_size = I915_RELOC_HEADER * sizeof(uint32_t);
- struct i915_relocatee_info relocatee;
- uint32_t reloc_type;
- uint32_t num_relocs;
- uint32_t count;
- int ret = 0;
- int i;
- int short_circuit = 1;
- uint32_t __user *reloc_ptr;
- uint64_t new_reloc_data;
- uint32_t reloc_buf_size;
- uint32_t *reloc_buf;
-
- for (i = 0; i < num_buffers; ++i) {
- if (unlikely(!buffers[i].presumed_offset_correct)) {
- short_circuit = 0;
- break;
- }
- }
-
- if (likely(short_circuit))
- return 0;
-
- memset(&relocatee, 0, sizeof(relocatee));
-
- while (new_reloc_ptr) {
- reloc_ptr = new_reloc_ptr;
-
- ret = get_user(num_relocs, reloc_ptr);
- if (unlikely(ret))
- goto out;
- if (unlikely(!access_ok(VERIFY_READ, reloc_ptr,
- header_size +
- num_relocs * reloc_stride)))
- return -EFAULT;
-
- ret = __get_user(reloc_type, reloc_ptr + 1);
- if (unlikely(ret))
- goto out;
-
- if (unlikely(reloc_type != 1)) {
- DRM_ERROR("Unsupported relocation type requested.\n");
- ret = -EINVAL;
- goto out;
- }
-
- ret = __get_user(new_reloc_data, reloc_ptr + 2);
- new_reloc_ptr = (uint32_t __user *) (unsigned long)
- new_reloc_data;
-
- reloc_ptr += I915_RELOC_HEADER;
-
- if (num_relocs == 0)
- goto out;
-
- reloc_buf_size =
- (num_relocs * 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;
- }
-
- if (__copy_from_user(reloc_buf, reloc_ptr, reloc_buf_size)) {
- ret = -EFAULT;
- goto out;
- }
- reloc = reloc_buf;
- preempt_disable();
- for (count = 0; count < num_relocs; ++count) {
- ret = i915_apply_post_reloc(reloc, buffers,
- num_buffers, &relocatee);
- if (unlikely(ret)) {
- preempt_enable();
- goto out;
- }
- reloc += I915_RELOC0_STRIDE;
- }
- preempt_enable();
-
- if (reloc_buf) {
- kfree(reloc_buf);
- reloc_buf = NULL;
- }
- i915_clear_relocatee(&relocatee);
- }
-
- out:
- /*
- * Flush ring relocs so the command parser will pick them up.
- */
-
- if (relocatee.performed_ring_relocs)
- (void)i915_emit_mi_flush(file_priv->minor->dev, 0);
-
- i915_clear_relocatee(&relocatee);
- if (reloc_buf) {
- kfree(reloc_buf);
- reloc_buf = NULL;
- }
-
- return ret;
-}
-
-static int i915_check_presumed(struct drm_i915_op_arg *arg,
- struct drm_buffer_object *bo,
- uint32_t __user * data, int *presumed_ok)
-{
- struct drm_bo_op_req *req = &arg->d.req;
- uint32_t hint_offset;
- uint32_t hint = req->bo_req.hint;
-
- *presumed_ok = 0;
-
- if (!(hint & DRM_BO_HINT_PRESUMED_OFFSET))
- return 0;
- if (bo->offset == req->bo_req.presumed_offset) {
- *presumed_ok = 1;
- return 0;
- }
-
- /*
- * We need to turn off the HINT_PRESUMED_OFFSET for this buffer in
- * the user-space IOCTL argument list, since the buffer has moved,
- * we're about to apply relocations and we might subsequently
- * hit an -EAGAIN. In that case the argument list will be reused by
- * user-space, but the presumed offset is no longer valid.
- *
- * Needless to say, this is a bit ugly.
- */
-
- hint_offset = (uint32_t *) & req->bo_req.hint - (uint32_t *) arg;
- hint &= ~DRM_BO_HINT_PRESUMED_OFFSET;
- return __put_user(hint, data + hint_offset);
-}
-
-/*
- * Validate, add fence and relocate a block of bos from a userspace list
- */
-int i915_validate_buffer_list(struct drm_file *file_priv,
- unsigned int fence_class, uint64_t data,
- struct drm_i915_validate_buffer *buffers,
- uint32_t * num_buffers,
- uint32_t __user ** post_relocs)
-{
- struct drm_i915_op_arg arg;
- struct drm_bo_op_req *req = &arg.d.req;
- int ret = 0;
- unsigned buf_count = 0;
- uint32_t buf_handle;
- uint32_t __user *reloc_user_ptr;
- struct drm_i915_validate_buffer *item = buffers;
- *post_relocs = NULL;
-
- do {
- if (buf_count >= *num_buffers) {
- DRM_ERROR("Buffer count exceeded %d\n.", *num_buffers);
- ret = -EINVAL;
- goto out_err;
- }
- item = buffers + buf_count;
- item->buffer = NULL;
- item->presumed_offset_correct = 0;
- item->idle = I915_RELOC_UNCHECKED;
-
- if (copy_from_user
- (&arg, (void __user *)(unsigned long)data, sizeof(arg))) {
- ret = -EFAULT;
- goto out_err;
- }
-
- ret = 0;
- if (req->op != drm_bo_validate) {
- DRM_ERROR
- ("Buffer object operation wasn't \"validate\".\n");
- ret = -EINVAL;
- goto out_err;
- }
- item->ret = 0;
- item->data = (void __user *)(unsigned long)data;
-
- buf_handle = req->bo_req.handle;
- reloc_user_ptr = (uint32_t *) (unsigned long)arg.reloc_ptr;
-
- /*
- * Switch mode to post-validation relocations?
- */
-
- if (unlikely((buf_count == 0) && (*post_relocs == NULL) &&
- (reloc_user_ptr != NULL))) {
- uint32_t reloc_type;
-
- ret = get_user(reloc_type, reloc_user_ptr + 1);
- if (ret)
- goto out_err;
-
- if (reloc_type == 1)
- *post_relocs = reloc_user_ptr;
-
- }
-
- if ((*post_relocs == NULL) && (reloc_user_ptr != NULL)) {
- ret =
- i915_exec_reloc(file_priv, buf_handle,
- reloc_user_ptr, buffers, buf_count);
- if (ret)
- goto out_err;
- DRM_MEMORYBARRIER();
- }
-
- ret = drm_bo_handle_validate(file_priv, req->bo_req.handle,
- req->bo_req.flags,
- req->bo_req.mask, req->bo_req.hint,
- req->bo_req.fence_class,
- NULL, &item->buffer);
- if (ret) {
- DRM_ERROR("error on handle validate %d\n", ret);
- goto out_err;
- }
-
- buf_count++;
-
- ret = i915_check_presumed(&arg, item->buffer,
- (uint32_t __user *)
- (unsigned long)data,
- &item->presumed_offset_correct);
- if (ret)
- goto out_err;
-
- data = arg.next;
- } while (data != 0);
- out_err:
- *num_buffers = buf_count;
- item->ret = (ret != -EAGAIN) ? ret : 0;
- return ret;
-}
-
-/*
- * Remove all buffers from the unfenced list.
- * If the execbuffer operation was aborted, for example due to a signal,
- * this also make sure that buffers retain their original state and
- * fence pointers.
- * Copy back buffer information to user-space unless we were interrupted
- * by a signal. In which case the IOCTL must be rerun.
- */
-
-static int i915_handle_copyback(struct drm_device *dev,
- struct drm_i915_validate_buffer *buffers,
- unsigned int num_buffers, int ret)
-{
- int err = ret;
- int i;
- struct drm_i915_op_arg arg;
- struct drm_buffer_object *bo;
-
- if (ret)
- drm_putback_buffer_objects(dev);
-
- if (ret != -EAGAIN) {
- for (i = 0; i < num_buffers; ++i) {
- arg.handled = 1;
- arg.d.rep.ret = buffers->ret;
- bo = buffers->buffer;
- mutex_lock(&bo->mutex);
- drm_bo_fill_rep_arg(bo, &arg.d.rep.bo_info);
- mutex_unlock(&bo->mutex);
- if (__copy_to_user(buffers->data, &arg, sizeof(arg)))
- err = -EFAULT;
- buffers++;
- }
- }
-
- return err;
-}
-
-/*
- * Create a fence object, and if that fails, pretend that everything is
- * OK and just idle the GPU.
- */
-
-void i915_fence_or_sync(struct drm_file *file_priv,
- uint32_t fence_flags,
- struct drm_fence_arg *fence_arg,
- struct drm_fence_object **fence_p)
-{
- struct drm_device *dev = file_priv->minor->dev;
- int ret;
- struct drm_fence_object *fence;
-
- ret = drm_fence_buffer_objects(dev, NULL, fence_flags, NULL, &fence);
-
- if (ret) {
-
- /*
- * Fence creation failed.
- * Fall back to synchronous operation and idle the engine.
- */
-
- (void)i915_emit_mi_flush(dev, MI_READ_FLUSH);
- (void)i915_quiescent(dev);
-
- if (!(fence_flags & DRM_FENCE_FLAG_NO_USER)) {
-
- /*
- * Communicate to user-space that
- * fence creation has failed and that
- * the engine is idle.
- */
-
- fence_arg->handle = ~0;
- fence_arg->error = ret;
- }
- drm_putback_buffer_objects(dev);
- if (fence_p)
- *fence_p = NULL;
- return;
- }
-
- if (!(fence_flags & DRM_FENCE_FLAG_NO_USER)) {
-
- ret = drm_fence_add_user_object(file_priv, fence,
- fence_flags &
- DRM_FENCE_FLAG_SHAREABLE);
- if (!ret)
- drm_fence_fill_arg(fence, fence_arg);
- else {
- /*
- * Fence user object creation failed.
- * We must idle the engine here as well, as user-
- * space expects a fence object to wait on. Since we
- * have a fence object we wait for it to signal
- * to indicate engine "sufficiently" idle.
- */
-
- (void)drm_fence_object_wait(fence, 0, 1, fence->type);
- drm_fence_usage_deref_unlocked(&fence);
- fence_arg->handle = ~0;
- fence_arg->error = ret;
- }
- }
-
- if (fence_p)
- *fence_p = fence;
- else if (fence)
- drm_fence_usage_deref_unlocked(&fence);
-}
-
-int i915_execbuffer(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
- dev_priv->sarea_priv;
- struct drm_i915_execbuffer *exec_buf = data;
- struct drm_i915_batchbuffer *batch = &exec_buf->batch;
- struct drm_fence_arg *fence_arg = &exec_buf->fence_arg;
- int num_buffers;
- int ret;
- uint32_t __user *post_relocs;
-
- if (!dev_priv->allow_batchbuffer) {
- DRM_ERROR("Batchbuffer ioctl disabled\n");
- return -EINVAL;
- }
-
- if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
- batch->num_cliprects *
- sizeof(struct
- drm_clip_rect)))
- return -EFAULT;
-
- if (exec_buf->num_buffers > dev_priv->max_validate_buffers)
- return -EINVAL;
-
- ret = drm_bo_read_lock(&dev->bm.bm_lock, 1);
- if (ret)
- return ret;
-
- /*
- * The cmdbuf_mutex makes sure the validate-submit-fence
- * operation is atomic.
- */
-
- ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
- if (ret) {
- drm_bo_read_unlock(&dev->bm.bm_lock);
- return -EAGAIN;
- }
-
- num_buffers = exec_buf->num_buffers;
-
- if (!dev_priv->val_bufs) {
- dev_priv->val_bufs =
- vmalloc(sizeof(struct drm_i915_validate_buffer) *
- dev_priv->max_validate_buffers);
- }
- if (!dev_priv->val_bufs) {
- drm_bo_read_unlock(&dev->bm.bm_lock);
- mutex_unlock(&dev_priv->cmdbuf_mutex);
- return -ENOMEM;
- }
-
- /* validate buffer list + fixup relocations */
- ret = i915_validate_buffer_list(file_priv, 0, exec_buf->ops_list,
- dev_priv->val_bufs, &num_buffers,
- &post_relocs);
- if (ret)
- goto out_err0;
-
- if (post_relocs) {
- ret = i915_post_relocs(file_priv, post_relocs,
- dev_priv->val_bufs, num_buffers);
- if (ret)
- goto out_err0;
- }
-
- /* make sure all previous memory operations have passed */
- DRM_MEMORYBARRIER();
-
- if (!post_relocs) {
- drm_agp_chipset_flush(dev);
- batch->start =
- dev_priv->val_bufs[num_buffers - 1].buffer->offset;
- } else {
- batch->start += dev_priv->val_bufs[0].buffer->offset;
- }
-
- DRM_DEBUG("i915 exec batchbuffer, start %x used %d cliprects %d\n",
- batch->start, batch->used, batch->num_cliprects);
-
- ret = i915_dispatch_batchbuffer(dev, batch);
- if (ret)
- goto out_err0;
- if (sarea_priv)
- sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- i915_fence_or_sync(file_priv, fence_arg->flags, fence_arg, NULL);
-
- out_err0:
- ret = i915_handle_copyback(dev, dev_priv->val_bufs, num_buffers, ret);
- mutex_lock(&dev->struct_mutex);
- i915_dereference_buffers_locked(dev_priv->val_bufs, num_buffers);
- mutex_unlock(&dev->struct_mutex);
- mutex_unlock(&dev_priv->cmdbuf_mutex);
- drm_bo_read_unlock(&dev->bm.bm_lock);
- return ret;
-}