summaryrefslogtreecommitdiff
path: root/shared-core/i915_dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared-core/i915_dma.c')
-rw-r--r--shared-core/i915_dma.c235
1 files changed, 151 insertions, 84 deletions
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index 24a4ec4a..a36ca37e 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -3,7 +3,7 @@
/*
* Copyright 2003 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
@@ -11,11 +11,11 @@
* 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.
@@ -23,7 +23,7 @@
* 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.
- *
+ *
*/
#include "drmP.h"
@@ -51,8 +51,6 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
if (ring->space >= n)
return 0;
- dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
-
if (ring->head != last_head)
i = 0;
@@ -73,9 +71,6 @@ void i915_kernel_lost_context(struct drm_device * dev)
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->Size;
-
- if (ring->head == ring->tail)
- dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
}
static int i915_dma_cleanup(struct drm_device * dev)
@@ -165,6 +160,8 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
* private backbuffer/depthbuffer usage.
*/
dev_priv->use_mi_batchbuffer_start = 0;
+ if (IS_I965G(dev)) /* 965 doesn't support older method */
+ dev_priv->use_mi_batchbuffer_start = 1;
/* Allow hardware batchbuffers unless told otherwise.
*/
@@ -172,11 +169,11 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
/* Enable vblank on pipe A for older X servers
*/
- dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
+ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
/* Program Hardware Status Page */
if (!IS_G33(dev)) {
- dev_priv->status_page_dmah =
+ dev_priv->status_page_dmah =
drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);
if (!dev_priv->status_page_dmah) {
@@ -192,7 +189,9 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
I915_WRITE(0x02080, dev_priv->dma_status_page);
}
DRM_DEBUG("Enabled hardware status page\n");
+#ifdef I915_HAVE_BUFFER
mutex_init(&dev_priv->cmdbuf_mutex);
+#endif
return 0;
}
@@ -200,7 +199,7 @@ static int i915_dma_resume(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("\n");
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
@@ -329,12 +328,12 @@ static int validate_cmd(int cmd)
{
int ret = do_validate_cmd(cmd);
-/* printk("validate_cmd( %x ): %d\n", cmd, ret); */
+/* printk("validate_cmd( %x ): %d\n", cmd, ret); */
return ret;
}
-static int i915_emit_cmds(struct drm_device * dev, int __user * buffer,
+static int i915_emit_cmds(struct drm_device *dev, int __user *buffer,
int dwords)
{
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -365,12 +364,12 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer,
OUT_RING(cmd);
}
}
-
+
if (dwords & 1)
OUT_RING(0);
ADVANCE_LP_RING();
-
+
return 0;
}
@@ -414,7 +413,7 @@ static int i915_emit_box(struct drm_device * dev,
}
/* XXX: Emitting the counter should really be moved to part of the IRQ
- * emit. For now, do it in both places:
+ * emit. For now, do it in both places:
*/
void i915_emit_breadcrumb(struct drm_device *dev)
@@ -490,7 +489,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
return ret;
}
- i915_emit_breadcrumb( dev );
+ i915_emit_breadcrumb(dev);
#ifdef I915_HAVE_FENCE
drm_fence_flush_old(dev, 0, dev_priv->counter);
#endif
@@ -544,7 +543,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
}
}
- i915_emit_breadcrumb( dev );
+ i915_emit_breadcrumb(dev);
#ifdef I915_HAVE_FENCE
drm_fence_flush_old(dev, 0, dev_priv->counter);
#endif
@@ -608,8 +607,7 @@ void i915_dispatch_flip(struct drm_device * dev, int planes, int sync)
drm_i915_private_t *dev_priv = dev->dev_private;
int i;
- DRM_DEBUG("%s: planes=0x%x pfCurrentPage=%d\n",
- __FUNCTION__,
+ DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n",
planes, dev_priv->sarea_priv->pf_current_page);
i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH);
@@ -625,7 +623,7 @@ void i915_dispatch_flip(struct drm_device * dev, int planes, int sync)
#endif
}
-static int i915_quiescent(struct drm_device * dev)
+static int i915_quiescent(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -704,7 +702,14 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
return 0;
}
+#if DRM_DEBUG_CODE
+#define DRM_DEBUG_RELOCATION (drm_debug != 0)
+#else
+#define DRM_DEBUG_RELOCATION 0
+#endif
+
#ifdef I915_HAVE_BUFFER
+
struct i915_relocatee_info {
struct drm_buffer_object *buf;
unsigned long offset;
@@ -714,15 +719,20 @@ struct i915_relocatee_info {
int is_iomem;
};
-static void i915_dereference_buffers_locked(struct drm_buffer_object **buffers,
+struct drm_i915_validate_buffer {
+ struct drm_buffer_object *buffer;
+ int presumed_offset_correct;
+};
+
+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]);
+ drm_bo_usage_deref_locked(&buffers[num_buffers].buffer);
}
int i915_apply_reloc(struct drm_file *file_priv, int num_buffers,
- struct drm_buffer_object **buffers,
+ struct drm_i915_validate_buffer *buffers,
struct i915_relocatee_info *relocatee,
uint32_t *reloc)
{
@@ -736,11 +746,25 @@ int i915_apply_reloc(struct drm_file *file_priv, int num_buffers,
return -EINVAL;
}
+ /*
+ * Short-circuit relocations that were correctly
+ * guessed by the client
+ */
+ if (buffers[reloc[2]].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)) {
drm_bo_kunmap(&relocatee->kmap);
relocatee->offset = new_cmd_offset;
+ mutex_lock (&relocatee->buf->mutex);
+ ret = drm_bo_wait (relocatee->buf, 0, 0, FALSE);
+ mutex_unlock (&relocatee->buf->mutex);
+ if (ret) {
+ DRM_ERROR("Could not wait for buffer to apply relocs\n %08lx", new_cmd_offset);
+ return ret;
+ }
ret = drm_bo_kmap(relocatee->buf, new_cmd_offset >> PAGE_SHIFT,
1, &relocatee->kmap);
if (ret) {
@@ -753,12 +777,19 @@ int i915_apply_reloc(struct drm_file *file_priv, int num_buffers,
relocatee->page_offset = (relocatee->offset & PAGE_MASK);
}
- val = buffers[reloc[2]]->offset;
+ val = buffers[reloc[2]].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 &&
+ 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);
+ }
+ }
relocatee->data_page[index] = val;
return 0;
}
@@ -767,7 +798,7 @@ int i915_process_relocs(struct drm_file *file_priv,
uint32_t buf_handle,
uint32_t *reloc_buf_handle,
struct i915_relocatee_info *relocatee,
- struct drm_buffer_object **buffers,
+ struct drm_i915_validate_buffer *buffers,
uint32_t num_buffers)
{
struct drm_device *dev = file_priv->head->dev;
@@ -853,15 +884,30 @@ out:
static int i915_exec_reloc(struct drm_file *file_priv, drm_handle_t buf_handle,
drm_handle_t buf_reloc_handle,
- struct drm_buffer_object **buffers,
+ struct drm_i915_validate_buffer *buffers,
uint32_t buf_count)
{
struct drm_device *dev = file_priv->head->dev;
struct i915_relocatee_info relocatee;
int ret = 0;
+ int b;
- memset(&relocatee, 0, sizeof(relocatee));
+ /*
+ * 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));
+
mutex_lock(&dev->struct_mutex);
relocatee.buf = drm_lookup_buffer_object(file_priv, buf_handle, 1);
mutex_unlock(&dev->struct_mutex);
@@ -870,7 +916,7 @@ static int i915_exec_reloc(struct drm_file *file_priv, drm_handle_t buf_handle,
ret = -EINVAL;
goto out_err;
}
-
+
while (buf_reloc_handle) {
ret = i915_process_relocs(file_priv, buf_handle, &buf_reloc_handle, &relocatee, buffers, buf_count);
if (ret) {
@@ -878,11 +924,11 @@ static int i915_exec_reloc(struct drm_file *file_priv, drm_handle_t buf_handle,
break;
}
}
-
+
mutex_lock(&dev->struct_mutex);
drm_bo_usage_deref_locked(&relocatee.buf);
mutex_unlock(&dev->struct_mutex);
-
+
out_err:
return ret;
}
@@ -892,7 +938,7 @@ out_err:
*/
int i915_validate_buffer_list(struct drm_file *file_priv,
unsigned int fence_class, uint64_t data,
- struct drm_buffer_object **buffers,
+ struct drm_i915_validate_buffer *buffers,
uint32_t *num_buffers)
{
struct drm_i915_op_arg arg;
@@ -912,9 +958,10 @@ int i915_validate_buffer_list(struct drm_file *file_priv,
goto out_err;
}
- buffers[buf_count] = NULL;
+ buffers[buf_count].buffer = NULL;
+ buffers[buf_count].presumed_offset_correct = 0;
- if (copy_from_user(&arg, (void __user *)(unsigned)data, sizeof(arg))) {
+ if (copy_from_user(&arg, (void __user *)(unsigned long)data, sizeof(arg))) {
ret = -EFAULT;
goto out_err;
}
@@ -922,7 +969,7 @@ int i915_validate_buffer_list(struct drm_file *file_priv,
if (arg.handled) {
data = arg.next;
mutex_lock(&dev->struct_mutex);
- buffers[buf_count] = drm_lookup_buffer_object(file_priv, req->arg_handle, 1);
+ buffers[buf_count].buffer = drm_lookup_buffer_object(file_priv, req->arg_handle, 1);
mutex_unlock(&dev->struct_mutex);
buf_count++;
continue;
@@ -947,25 +994,31 @@ int i915_validate_buffer_list(struct drm_file *file_priv,
}
rep.ret = drm_bo_handle_validate(file_priv, req->bo_req.handle,
- req->bo_req.fence_class,
- req->bo_req.flags,
- req->bo_req.mask,
+ req->bo_req.flags, req->bo_req.mask,
req->bo_req.hint,
- 0,
+ req->bo_req.fence_class, 0,
&rep.bo_info,
- &buffers[buf_count]);
+ &buffers[buf_count].buffer);
if (rep.ret) {
DRM_ERROR("error on handle validate %d\n", rep.ret);
goto out_err;
}
-
+ /*
+ * If the user provided a presumed offset hint, check whether
+ * the buffer is in the same place, if so, relocations relative to
+ * this buffer need not be performed
+ */
+ if ((req->bo_req.hint & DRM_BO_HINT_PRESUMED_OFFSET) &&
+ buffers[buf_count].buffer->offset == req->bo_req.presumed_offset) {
+ buffers[buf_count].presumed_offset_correct = 1;
+ }
next = arg.next;
arg.handled = 1;
arg.d.rep = rep;
- if (copy_to_user((void __user *)(unsigned)data, &arg, sizeof(arg)))
+ if (copy_to_user((void __user *)(unsigned long)data, &arg, sizeof(arg)))
return -EFAULT;
data = next;
@@ -993,7 +1046,7 @@ static int i915_execbuffer(struct drm_device *dev, void *data,
struct drm_fence_arg *fence_arg = &exec_buf->fence_arg;
int num_buffers;
int ret;
- struct drm_buffer_object **buffers;
+ struct drm_i915_validate_buffer *buffers;
struct drm_fence_object *fence;
if (!dev_priv->allow_batchbuffer) {
@@ -1012,12 +1065,12 @@ static int i915_execbuffer(struct drm_device *dev, void *data,
ret = drm_bo_read_lock(&dev->bm.bm_lock);
- if (ret)
+ if (ret)
return ret;
/*
* The cmdbuf_mutex makes sure the validate-submit-fence
- * operation is atomic.
+ * operation is atomic.
*/
ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
@@ -1028,12 +1081,12 @@ static int i915_execbuffer(struct drm_device *dev, void *data,
num_buffers = exec_buf->num_buffers;
- buffers = drm_calloc(num_buffers, sizeof(struct drm_buffer_object *), DRM_MEM_DRIVER);
+ buffers = drm_calloc(num_buffers, sizeof(struct drm_i915_validate_buffer), DRM_MEM_DRIVER);
if (!buffers) {
- drm_bo_read_unlock(&dev->bm.bm_lock);
+ 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,
@@ -1043,9 +1096,10 @@ static int i915_execbuffer(struct drm_device *dev, void *data,
/* make sure all previous memory operations have passed */
DRM_MEMORYBARRIER();
+ drm_agp_chipset_flush(dev);
/* submit buffer */
- batch->start = buffers[num_buffers-1]->offset;
+ batch->start = buffers[num_buffers-1].buffer->offset;
DRM_DEBUG("i915 exec batchbuffer, start %x used %d cliprects %d\n",
batch->start, batch->used, batch->num_cliprects);
@@ -1057,7 +1111,8 @@ static int i915_execbuffer(struct drm_device *dev, void *data,
sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
/* fence */
- ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence);
+ ret = drm_fence_buffer_objects(dev, NULL, fence_arg->flags,
+ NULL, &fence);
if (ret)
goto out_err0;
@@ -1092,13 +1147,13 @@ static int i915_do_cleanup_pageflip(struct drm_device * dev)
drm_i915_private_t *dev_priv = dev->dev_private;
int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("\n");
for (i = 0, planes = 0; i < 2; i++)
if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) {
dev_priv->sarea_priv->pf_current_page =
(dev_priv->sarea_priv->pf_current_page &
- ~(0x3 << (2 * i))) | (num_pages - 1) << (2 * i);
+ ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i));
planes |= 1 << i;
}
@@ -1113,7 +1168,7 @@ static int i915_flip_bufs(struct drm_device *dev, void *data, struct drm_file *f
{
drm_i915_flip_t *param = data;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("\n");
LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -1138,7 +1193,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
int value;
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
@@ -1172,13 +1227,14 @@ static int i915_setparam(struct drm_device *dev, void *data,
drm_i915_setparam_t *param = data;
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
switch (param->param) {
case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
- dev_priv->use_mi_batchbuffer_start = param->value;
+ if (!IS_I965G(dev))
+ dev_priv->use_mi_batchbuffer_start = param->value;
break;
case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
dev_priv->tex_lru_log_granularity = param->value;
@@ -1199,7 +1255,7 @@ drm_i915_mmio_entry_t mmio_table[] = {
I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE,
0x2350,
8
- }
+ }
};
static int mmio_table_size = sizeof(mmio_table)/sizeof(drm_i915_mmio_entry_t);
@@ -1209,13 +1265,13 @@ static int i915_mmio(struct drm_device *dev, void *data,
{
uint32_t buf[8];
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_mmio_entry_t *e;
+ drm_i915_mmio_entry_t *e;
drm_i915_mmio_t *mmio = data;
void __iomem *base;
int i;
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
@@ -1226,27 +1282,27 @@ static int i915_mmio(struct drm_device *dev, void *data,
base = (u8 *) dev_priv->mmio_map->handle + e->offset;
switch (mmio->read_write) {
- case I915_MMIO_READ:
- if (!(e->flag & I915_MMIO_MAY_READ))
- return -EINVAL;
- for (i = 0; i < e->size / 4; i++)
- buf[i] = I915_READ(e->offset + i * 4);
- if (DRM_COPY_TO_USER(mmio->data, buf, e->size)) {
- DRM_ERROR("DRM_COPY_TO_USER failed\n");
- return -EFAULT;
- }
- break;
-
- case I915_MMIO_WRITE:
- if (!(e->flag & I915_MMIO_MAY_WRITE))
- return -EINVAL;
- if(DRM_COPY_FROM_USER(buf, mmio->data, e->size)) {
- DRM_ERROR("DRM_COPY_TO_USER failed\n");
- return -EFAULT;
- }
- for (i = 0; i < e->size / 4; i++)
- I915_WRITE(e->offset + i * 4, buf[i]);
- break;
+ case I915_MMIO_READ:
+ if (!(e->flag & I915_MMIO_MAY_READ))
+ return -EINVAL;
+ for (i = 0; i < e->size / 4; i++)
+ buf[i] = I915_READ(e->offset + i * 4);
+ if (DRM_COPY_TO_USER(mmio->data, buf, e->size)) {
+ DRM_ERROR("DRM_COPY_TO_USER failed\n");
+ return -EFAULT;
+ }
+ break;
+
+ case I915_MMIO_WRITE:
+ if (!(e->flag & I915_MMIO_MAY_WRITE))
+ return -EINVAL;
+ if (DRM_COPY_FROM_USER(buf, mmio->data, e->size)) {
+ DRM_ERROR("DRM_COPY_TO_USER failed\n");
+ return -EFAULT;
+ }
+ for (i = 0; i < e->size / 4; i++)
+ I915_WRITE(e->offset + i * 4, buf[i]);
+ break;
}
return 0;
}
@@ -1258,7 +1314,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
drm_i915_hws_addr_t *hws = data;
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
DRM_DEBUG("set status page addr 0x%08x\n", (u32)hws->addr);
@@ -1314,8 +1370,14 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
base = drm_get_resource_start(dev, mmio_bar);
size = drm_get_resource_len(dev, mmio_bar);
- ret = drm_addmap(dev, base, size, _DRM_REGISTERS, _DRM_KERNEL,
- &dev_priv->mmio_map);
+ ret = drm_addmap(dev, base, size, _DRM_REGISTERS,
+ _DRM_KERNEL | _DRM_DRIVER, &dev_priv->mmio_map);
+
+#ifdef __linux__
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+ intel_init_chipset_flush_compat(dev);
+#endif
+#endif
return ret;
}
@@ -1329,6 +1391,11 @@ int i915_driver_unload(struct drm_device *dev)
drm_free(dev->dev_private, sizeof(drm_i915_private_t),
DRM_MEM_DRIVER);
+#ifdef __linux__
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+ intel_fini_chipset_flush_compat(dev);
+#endif
+#endif
return 0;
}