summaryrefslogtreecommitdiff
path: root/linux-core/i915_gem.c
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2008-06-13 14:28:18 -0700
committerKeith Packard <keithp@keithp.com>2008-06-13 14:29:46 -0700
commitbaf521369478eff2842b99feda16f9d145402d27 (patch)
treee07a8e994616a16175181e49ef840bc4b6ae4dc6 /linux-core/i915_gem.c
parentced9ebf64543b4d64a38feee3293040af953acc0 (diff)
[intel-gem] Pin objects during execbuffer
Pinning the objects avoids accidentally evicting them while binding other objects.
Diffstat (limited to 'linux-core/i915_gem.c')
-rw-r--r--linux-core/i915_gem.c76
1 files changed, 52 insertions, 24 deletions
diff --git a/linux-core/i915_gem.c b/linux-core/i915_gem.c
index c2d1fab6..d14b2f2d 100644
--- a/linux-core/i915_gem.c
+++ b/linux-core/i915_gem.c
@@ -1298,27 +1298,25 @@ i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
#endif
/**
- * Bind an object to the GTT and evaluate the relocations landing in it.
+ * Pin an object to the GTT and evaluate the relocations landing in it.
*/
static int
-i915_gem_object_bind_and_relocate(struct drm_gem_object *obj,
- struct drm_file *file_priv,
- struct drm_i915_gem_exec_object *entry)
+i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
+ struct drm_file *file_priv,
+ struct drm_i915_gem_exec_object *entry)
{
struct drm_device *dev = obj->dev;
struct drm_i915_gem_relocation_entry reloc;
struct drm_i915_gem_relocation_entry __user *relocs;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
- int i;
+ int i, ret;
uint32_t last_reloc_offset = -1;
void *reloc_page = NULL;
/* Choose the GTT offset for our buffer and put it there. */
- if (obj_priv->gtt_space == NULL) {
- i915_gem_object_bind_to_gtt(obj, (unsigned) entry->alignment);
- if (obj_priv->gtt_space == NULL)
- return -ENOMEM;
- }
+ ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment);
+ if (ret)
+ return ret;
entry->offset = obj_priv->gtt_offset;
@@ -1334,13 +1332,17 @@ i915_gem_object_bind_and_relocate(struct drm_gem_object *obj,
int ret;
ret = copy_from_user(&reloc, relocs + i, sizeof(reloc));
- if (ret != 0)
+ if (ret != 0) {
+ i915_gem_object_unpin(obj);
return ret;
+ }
target_obj = drm_gem_object_lookup(obj->dev, file_priv,
reloc.target_handle);
- if (target_obj == NULL)
+ if (target_obj == NULL) {
+ i915_gem_object_unpin(obj);
return -EINVAL;
+ }
target_obj_priv = target_obj->driver_private;
/* The target buffer should have appeared before us in the
@@ -1350,6 +1352,7 @@ i915_gem_object_bind_and_relocate(struct drm_gem_object *obj,
DRM_ERROR("No GTT space found for object %d\n",
reloc.target_handle);
drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
return -EINVAL;
}
@@ -1359,6 +1362,7 @@ i915_gem_object_bind_and_relocate(struct drm_gem_object *obj,
obj, reloc.target_handle,
(int) reloc.offset, (int) obj->size);
drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
return -EINVAL;
}
if (reloc.offset & 3) {
@@ -1367,6 +1371,7 @@ i915_gem_object_bind_and_relocate(struct drm_gem_object *obj,
obj, reloc.target_handle,
(int) reloc.offset);
drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
return -EINVAL;
}
@@ -1380,6 +1385,7 @@ i915_gem_object_bind_and_relocate(struct drm_gem_object *obj,
reloc.write_domain,
target_obj->pending_write_domain);
drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
return -EINVAL;
}
@@ -1440,6 +1446,7 @@ i915_gem_object_bind_and_relocate(struct drm_gem_object *obj,
last_reloc_offset = reloc_offset;
if (reloc_page == NULL) {
drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
return -ENOMEM;
}
}
@@ -1462,6 +1469,7 @@ i915_gem_object_bind_and_relocate(struct drm_gem_object *obj,
ret = copy_to_user(relocs + i, &reloc, sizeof(reloc));
if (ret != 0) {
drm_gem_object_unreference(target_obj);
+ i915_gem_object_unpin(obj);
return ret;
}
@@ -1573,7 +1581,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
struct drm_i915_gem_exec_object *exec_list = NULL;
struct drm_gem_object **object_list = NULL;
struct drm_gem_object *batch_obj;
- int ret, i;
+ int ret, i, pinned = 0;
uint64_t exec_offset;
uint32_t seqno, flush_domains;
@@ -1632,13 +1640,14 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
object_list[i]->pending_read_domains = 0;
object_list[i]->pending_write_domain = 0;
- ret = i915_gem_object_bind_and_relocate(object_list[i],
- file_priv,
- &exec_list[i]);
+ ret = i915_gem_object_pin_and_relocate(object_list[i],
+ file_priv,
+ &exec_list[i]);
if (ret) {
DRM_ERROR("object bind and relocate failed %d\n", ret);
goto err;
}
+ pinned = i;
}
/* Set the pending read domains for the batch buffer to COMMAND */
@@ -1735,6 +1744,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
args->buffer_count, ret);
err:
if (object_list != NULL) {
+ for (i = 0; i < pinned; i++)
+ i915_gem_object_unpin (object_list[i]);
for (i = 0; i < args->buffer_count; i++)
drm_gem_object_unreference(object_list[i]);
}
@@ -1752,32 +1763,47 @@ pre_mutex_err:
int
i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
{
- struct drm_device *dev = obj->dev;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
int ret;
if (obj_priv->gtt_space == NULL) {
ret = i915_gem_object_bind_to_gtt(obj, alignment);
if (ret != 0) {
- DRM_ERROR("Failure to bind in "
- "i915_gem_pin_ioctl(): %d\n",
- ret);
- drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
+ DRM_ERROR("Failure to bind: %d", ret);
return ret;
}
}
-
obj_priv->pin_count++;
+
+ /* If the object is not active and not pending a flush,
+ * remove it from the inactive list
+ */
+ if (obj_priv->pin_count == 1 &&
+ !obj_priv->active &&
+ obj->write_domain == 0)
+ list_del_init(&obj_priv->list);
+
return 0;
}
void
i915_gem_object_unpin(struct drm_gem_object *obj)
{
+ struct drm_device *dev = obj->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
obj_priv->pin_count--;
+ BUG_ON(obj_priv->pin_count < 0);
+ BUG_ON(obj_priv->gtt_space == NULL);
+
+ /* If the object is no longer pinned, and is
+ * neither active nor being flushed, then stick it on
+ * the inactive list
+ */
+ if (obj_priv->pin_count == 0 &&
+ !obj_priv->active && obj->write_domain == 0)
+ list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
}
int
@@ -1963,8 +1989,10 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
obj_priv = obj->driver_private;
ret = i915_gem_object_pin(obj, 4096);
- if (ret != 0)
+ if (ret != 0) {
+ drm_gem_object_unreference(obj);
return ret;
+ }
/* Set up the kernel mapping for the ring. */
dev_priv->ring.Size = obj->size;