diff options
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 37 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem_tiling.c | 67 | 
3 files changed, 88 insertions, 17 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 451b547352b..7a84f04e843 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -647,6 +647,7 @@ int i915_gem_object_unbind(struct drm_gem_object *obj);  void i915_gem_lastclose(struct drm_device *dev);  uint32_t i915_get_gem_seqno(struct drm_device *dev);  int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); +int i915_gem_object_put_fence_reg(struct drm_gem_object *obj);  void i915_gem_retire_requests(struct drm_device *dev);  void i915_gem_retire_work_handler(struct work_struct *work);  void i915_gem_clflush_object(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4f345414fe7..174aef2d648 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2162,7 +2162,6 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)  	val |= I830_FENCE_REG_VALID;  	I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); -  }  /** @@ -2329,6 +2328,42 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)  }  /** + * i915_gem_object_put_fence_reg - waits on outstanding fenced access + * to the buffer to finish, and then resets the fence register. + * @obj: tiled object holding a fence register. + * + * Zeroes out the fence register itself and clears out the associated + * data structures in dev_priv and obj_priv. + */ +int +i915_gem_object_put_fence_reg(struct drm_gem_object *obj) +{ +	struct drm_device *dev = obj->dev; +	struct drm_i915_gem_object *obj_priv = obj->driver_private; + +	if (obj_priv->fence_reg == I915_FENCE_REG_NONE) +		return 0; + +	/* On the i915, GPU access to tiled buffers is via a fence, +	 * therefore we must wait for any outstanding access to complete +	 * before clearing the fence. +	 */ +	if (!IS_I965G(dev)) { +		int ret; + +		i915_gem_object_flush_gpu_write_domain(obj); +		i915_gem_object_flush_gtt_write_domain(obj); +		ret = i915_gem_object_wait_rendering(obj); +		if (ret != 0) +			return ret; +	} + +	i915_gem_clear_fence_reg (obj); + +	return 0; +} + +/**   * Finds free space in the GTT aperture and binds the object there.   */  static int diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 9a05cadaa4a..5c1ceec49f5 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -408,7 +408,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)  	if (stride & (stride - 1))  		return false; -	/* We don't handle the aperture area covered by the fence being bigger +	/* We don't 0handle the aperture area covered by the fence being bigger  	 * than the object size.  	 */  	if (i915_get_fence_size(dev, size) != size) @@ -417,6 +417,33 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)  	return true;  } +static bool +i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode) +{ +	struct drm_device *dev = obj->dev; +	struct drm_i915_gem_object *obj_priv = obj->driver_private; + +	if (obj_priv->gtt_space == NULL) +		return true; + +	if (tiling_mode == I915_TILING_NONE) +		return true; + +	if (!IS_I965G(dev)) { +		if (obj_priv->gtt_offset & (obj->size - 1)) +			return false; +		if (IS_I9XX(dev)) { +			if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK) +				return false; +		} else { +			if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK) +				return false; +		} +	} + +	return true; +} +  /**   * Sets the tiling mode of an object, returning the required swizzling of   * bit 6 of addresses in the object. @@ -429,6 +456,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,  	drm_i915_private_t *dev_priv = dev->dev_private;  	struct drm_gem_object *obj;  	struct drm_i915_gem_object *obj_priv; +	int ret = 0;  	obj = drm_gem_object_lookup(dev, file_priv, args->handle);  	if (obj == NULL) @@ -436,14 +464,15 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,  	obj_priv = obj->driver_private;  	if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) { +		mutex_lock(&dev->struct_mutex);  		drm_gem_object_unreference(obj); +		mutex_unlock(&dev->struct_mutex);  		return -EINVAL;  	} -	mutex_lock(&dev->struct_mutex); -  	if (args->tiling_mode == I915_TILING_NONE) {  		args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; +		args->stride = 0;  	} else {  		if (args->tiling_mode == I915_TILING_X)  			args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x; @@ -466,32 +495,38 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,  		if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) {  			args->tiling_mode = I915_TILING_NONE;  			args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; +			args->stride = 0;  		}  	} -	if (args->tiling_mode != obj_priv->tiling_mode) { -		int ret; -		/* Unbind the object, as switching tiling means we're -		 * switching the cache organization due to fencing, probably. +	mutex_lock(&dev->struct_mutex); +	if (args->tiling_mode != obj_priv->tiling_mode || +	    args->stride != obj_priv->stride) { +		/* We need to rebind the object if its current allocation +		 * no longer meets the alignment restrictions for its new +		 * tiling mode. Otherwise we can just leave it alone, but +		 * need to ensure that any fence register is cleared.  		 */ -		ret = i915_gem_object_unbind(obj); +		if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode)) +		    ret = i915_gem_object_unbind(obj); +		else +		    ret = i915_gem_object_put_fence_reg(obj);  		if (ret != 0) {  			WARN(ret != -ERESTARTSYS, -			     "failed to unbind object for tiling switch"); +			     "failed to reset object for tiling switch");  			args->tiling_mode = obj_priv->tiling_mode; -			mutex_unlock(&dev->struct_mutex); -			drm_gem_object_unreference(obj); - -			return ret; +			args->stride = obj_priv->stride; +			goto err;  		} +  		obj_priv->tiling_mode = args->tiling_mode; +		obj_priv->stride = args->stride;  	} -	obj_priv->stride = args->stride; - +err:  	drm_gem_object_unreference(obj);  	mutex_unlock(&dev->struct_mutex); -	return 0; +	return ret;  }  /**  |