diff options
| author | Keith Packard <keithp@keithp.com> | 2008-06-13 14:28:18 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2008-06-13 14:29:46 -0700 | 
| commit | baf521369478eff2842b99feda16f9d145402d27 (patch) | |
| tree | e07a8e994616a16175181e49ef840bc4b6ae4dc6 /linux-core | |
| parent | ced9ebf64543b4d64a38feee3293040af953acc0 (diff) | |
[intel-gem] Pin objects during execbuffer
Pinning the objects avoids accidentally evicting them while binding
other objects.
Diffstat (limited to 'linux-core')
| -rw-r--r-- | linux-core/i915_gem.c | 76 | 
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; | 
