diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem.c')
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 89 | 
1 files changed, 59 insertions, 30 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2e10187cd0a0..702e5b89be22 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -118,6 +118,7 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj,  			   unsigned long flags)  {  	struct intel_runtime_pm *rpm = &to_i915(obj->base.dev)->runtime_pm; +	bool vm_trylock = !!(flags & I915_GEM_OBJECT_UNBIND_VM_TRYLOCK);  	LIST_HEAD(still_in_list);  	intel_wakeref_t wakeref;  	struct i915_vma *vma; @@ -142,8 +143,6 @@ try_again:  	while (!ret && (vma = list_first_entry_or_null(&obj->vma.list,  						       struct i915_vma,  						       obj_link))) { -		struct i915_address_space *vm = vma->vm; -  		list_move_tail(&vma->obj_link, &still_in_list);  		if (!i915_vma_is_bound(vma, I915_VMA_BIND_MASK))  			continue; @@ -153,40 +152,44 @@ try_again:  			break;  		} +		/* +		 * Requiring the vm destructor to take the object lock +		 * before destroying a vma would help us eliminate the +		 * i915_vm_tryget() here, AND thus also the barrier stuff +		 * at the end. That's an easy fix, but sleeping locks in +		 * a kthread should generally be avoided. +		 */  		ret = -EAGAIN; -		if (!i915_vm_tryopen(vm)) +		if (!i915_vm_tryget(vma->vm))  			break; -		/* Prevent vma being freed by i915_vma_parked as we unbind */ -		vma = __i915_vma_get(vma);  		spin_unlock(&obj->vma.lock); -		if (vma) { -			bool vm_trylock = !!(flags & I915_GEM_OBJECT_UNBIND_VM_TRYLOCK); -			ret = -EBUSY; -			if (flags & I915_GEM_OBJECT_UNBIND_ASYNC) { -				assert_object_held(vma->obj); -				ret = i915_vma_unbind_async(vma, vm_trylock); -			} +		/* +		 * Since i915_vma_parked() takes the object lock +		 * before vma destruction, it won't race us here, +		 * and destroy the vma from under us. +		 */ -			if (ret == -EBUSY && (flags & I915_GEM_OBJECT_UNBIND_ACTIVE || -					      !i915_vma_is_active(vma))) { -				if (vm_trylock) { -					if (mutex_trylock(&vma->vm->mutex)) { -						ret = __i915_vma_unbind(vma); -						mutex_unlock(&vma->vm->mutex); -					} else { -						ret = -EBUSY; -					} -				} else { -					ret = i915_vma_unbind(vma); +		ret = -EBUSY; +		if (flags & I915_GEM_OBJECT_UNBIND_ASYNC) { +			assert_object_held(vma->obj); +			ret = i915_vma_unbind_async(vma, vm_trylock); +		} + +		if (ret == -EBUSY && (flags & I915_GEM_OBJECT_UNBIND_ACTIVE || +				      !i915_vma_is_active(vma))) { +			if (vm_trylock) { +				if (mutex_trylock(&vma->vm->mutex)) { +					ret = __i915_vma_unbind(vma); +					mutex_unlock(&vma->vm->mutex);  				} +			} else { +				ret = i915_vma_unbind(vma);  			} - -			__i915_vma_put(vma);  		} -		i915_vm_close(vm); +		i915_vm_put(vma->vm);  		spin_lock(&obj->vma.lock);  	}  	list_splice_init(&still_in_list, &obj->vma.list); @@ -936,8 +939,19 @@ new_vma:  			if (i915_vma_is_pinned(vma) || i915_vma_is_active(vma))  				return ERR_PTR(-ENOSPC); +			/* +			 * If this misplaced vma is too big (i.e, at-least +			 * half the size of aperture) or hasn't been pinned +			 * mappable before, we ignore the misplacement when +			 * PIN_NONBLOCK is set in order to avoid the ping-pong +			 * issue described above. In other words, we try to +			 * avoid the costly operation of unbinding this vma +			 * from the GGTT and rebinding it back because there +			 * may not be enough space for this vma in the aperture. +			 */  			if (flags & PIN_MAPPABLE && -			    vma->fence_size > ggtt->mappable_end / 2) +			    (vma->fence_size > ggtt->mappable_end / 2 || +			    !i915_vma_is_map_and_fenceable(vma)))  				return ERR_PTR(-ENOSPC);  		} @@ -1213,25 +1227,40 @@ void i915_gem_cleanup_early(struct drm_i915_private *dev_priv)  int i915_gem_open(struct drm_i915_private *i915, struct drm_file *file)  {  	struct drm_i915_file_private *file_priv; -	int ret; +	struct i915_drm_client *client; +	int ret = -ENOMEM;  	DRM_DEBUG("\n");  	file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);  	if (!file_priv) -		return -ENOMEM; +		goto err_alloc; + +	client = i915_drm_client_add(&i915->clients); +	if (IS_ERR(client)) { +		ret = PTR_ERR(client); +		goto err_client; +	}  	file->driver_priv = file_priv;  	file_priv->dev_priv = i915;  	file_priv->file = file; +	file_priv->client = client;  	file_priv->bsd_engine = -1;  	file_priv->hang_timestamp = jiffies;  	ret = i915_gem_context_open(i915, file);  	if (ret) -		kfree(file_priv); +		goto err_context; + +	return 0; +err_context: +	i915_drm_client_put(client); +err_client: +	kfree(file_priv); +err_alloc:  	return ret;  }  |