diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem.c')
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 290 | 
1 files changed, 159 insertions, 131 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 08f57aedaf5..07ad1e35408 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -36,7 +36,8 @@  #include <linux/pci.h>  #include <linux/intel-gtt.h> -static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj); +static uint32_t i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj_priv); +static uint32_t i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv);  static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,  						  bool pipelined); @@ -51,7 +52,9 @@ static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *o  static int i915_gem_object_wait_rendering(struct drm_gem_object *obj,  					  bool interruptible);  static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, -				       unsigned alignment, bool mappable); +				       unsigned alignment, +				       bool mappable, +				       bool need_fence);  static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);  static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,  				struct drm_i915_gem_pwrite *args, @@ -79,30 +82,26 @@ static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv,  }  static void i915_gem_info_add_gtt(struct drm_i915_private *dev_priv, -				  struct drm_gem_object *obj) +				  struct drm_i915_gem_object *obj)  { -	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);  	dev_priv->mm.gtt_count++; -	dev_priv->mm.gtt_memory += obj->size; -	if (obj_priv->gtt_offset < dev_priv->mm.gtt_mappable_end) { +	dev_priv->mm.gtt_memory += obj->gtt_space->size; +	if (obj->gtt_offset < dev_priv->mm.gtt_mappable_end) {  		dev_priv->mm.mappable_gtt_used += -			min_t(size_t, obj->size, -			      dev_priv->mm.gtt_mappable_end -					- obj_priv->gtt_offset); +			min_t(size_t, obj->gtt_space->size, +			      dev_priv->mm.gtt_mappable_end - obj->gtt_offset);  	}  }  static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv, -				     struct drm_gem_object *obj) +				     struct drm_i915_gem_object *obj)  { -	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);  	dev_priv->mm.gtt_count--; -	dev_priv->mm.gtt_memory -= obj->size; -	if (obj_priv->gtt_offset < dev_priv->mm.gtt_mappable_end) { +	dev_priv->mm.gtt_memory -= obj->gtt_space->size; +	if (obj->gtt_offset < dev_priv->mm.gtt_mappable_end) {  		dev_priv->mm.mappable_gtt_used -= -			min_t(size_t, obj->size, -			      dev_priv->mm.gtt_mappable_end -					- obj_priv->gtt_offset); +			min_t(size_t, obj->gtt_space->size, +			      dev_priv->mm.gtt_mappable_end - obj->gtt_offset);  	}  } @@ -113,47 +112,43 @@ static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv,   */  static void  i915_gem_info_update_mappable(struct drm_i915_private *dev_priv, -			      struct drm_gem_object *obj, +			      struct drm_i915_gem_object *obj,  			      bool mappable)  { -	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); -  	if (mappable) { -		if (obj_priv->pin_mappable && obj_priv->fault_mappable) +		if (obj->pin_mappable && obj->fault_mappable)  			/* Combined state was already mappable. */  			return;  		dev_priv->mm.gtt_mappable_count++; -		dev_priv->mm.gtt_mappable_memory += obj->size; +		dev_priv->mm.gtt_mappable_memory += obj->gtt_space->size;  	} else { -		if (obj_priv->pin_mappable || obj_priv->fault_mappable) +		if (obj->pin_mappable || obj->fault_mappable)  			/* Combined state still mappable. */  			return;  		dev_priv->mm.gtt_mappable_count--; -		dev_priv->mm.gtt_mappable_memory -= obj->size; +		dev_priv->mm.gtt_mappable_memory -= obj->gtt_space->size;  	}  }  static void i915_gem_info_add_pin(struct drm_i915_private *dev_priv, -				  struct drm_gem_object *obj, +				  struct drm_i915_gem_object *obj,  				  bool mappable)  { -	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);  	dev_priv->mm.pin_count++; -	dev_priv->mm.pin_memory += obj->size; +	dev_priv->mm.pin_memory += obj->gtt_space->size;  	if (mappable) { -		obj_priv->pin_mappable = true; +		obj->pin_mappable = true;  		i915_gem_info_update_mappable(dev_priv, obj, true);  	}  }  static void i915_gem_info_remove_pin(struct drm_i915_private *dev_priv, -				     struct drm_gem_object *obj) +				     struct drm_i915_gem_object *obj)  { -	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);  	dev_priv->mm.pin_count--; -	dev_priv->mm.pin_memory -= obj->size; -	if (obj_priv->pin_mappable) { -		obj_priv->pin_mappable = false; +	dev_priv->mm.pin_memory -= obj->gtt_space->size; +	if (obj->pin_mappable) { +		obj->pin_mappable = false;  		i915_gem_info_update_mappable(dev_priv, obj, false);  	}  } @@ -309,16 +304,6 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,  	return 0;  } -static bool -i915_gem_object_cpu_accessible(struct drm_i915_gem_object *obj) -{ -	struct drm_device *dev = obj->base.dev; -	drm_i915_private_t *dev_priv = dev->dev_private; - -	return obj->gtt_space == NULL || -		obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end; -} -  static int i915_gem_object_needs_bit17_swizzle(struct drm_gem_object *obj)  {  	drm_i915_private_t *dev_priv = obj->dev->dev_private; @@ -1083,7 +1068,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,  	else if (obj_priv->tiling_mode == I915_TILING_NONE &&  		 obj_priv->gtt_space &&  		 obj->write_domain != I915_GEM_DOMAIN_CPU) { -		ret = i915_gem_object_pin(obj, 0, true); +		ret = i915_gem_object_pin(obj, 0, true, false);  		if (ret)  			goto out; @@ -1307,11 +1292,19 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)  	/* Now bind it into the GTT if needed */  	mutex_lock(&dev->struct_mutex);  	BUG_ON(obj_priv->pin_count && !obj_priv->pin_mappable); -	if (!i915_gem_object_cpu_accessible(obj_priv)) -		i915_gem_object_unbind(obj); + +	if (obj_priv->gtt_space) { +		if (!obj_priv->mappable || +		    (obj_priv->tiling_mode && !obj_priv->fenceable)) { +			ret = i915_gem_object_unbind(obj); +			if (ret) +				goto unlock; +		} +	}  	if (!obj_priv->gtt_space) { -		ret = i915_gem_object_bind_to_gtt(obj, 0, true); +		ret = i915_gem_object_bind_to_gtt(obj, 0, +						  true, obj_priv->tiling_mode);  		if (ret)  			goto unlock;  	} @@ -1322,7 +1315,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)  	if (!obj_priv->fault_mappable) {  		obj_priv->fault_mappable = true; -		i915_gem_info_update_mappable(dev_priv, obj, true); +		i915_gem_info_update_mappable(dev_priv, obj_priv, true);  	}  	/* Need a new fence register? */ @@ -1448,7 +1441,7 @@ i915_gem_release_mmap(struct drm_gem_object *obj)  	if (obj_priv->fault_mappable) {  		obj_priv->fault_mappable = false; -		i915_gem_info_update_mappable(dev_priv, obj, false); +		i915_gem_info_update_mappable(dev_priv, obj_priv, false);  	}  } @@ -1473,32 +1466,51 @@ i915_gem_free_mmap_offset(struct drm_gem_object *obj)   * potential fence register mapping if needed.   */  static uint32_t -i915_gem_get_gtt_alignment(struct drm_gem_object *obj) +i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj_priv)  { -	struct drm_device *dev = obj->dev; -	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); -	int start, i; +	struct drm_device *dev = obj_priv->base.dev;  	/*  	 * Minimum alignment is 4k (GTT page size), but might be greater  	 * if a fence register is needed for the object.  	 */ -	if (INTEL_INFO(dev)->gen >= 4 || obj_priv->tiling_mode == I915_TILING_NONE) +	if (INTEL_INFO(dev)->gen >= 4 || +	    obj_priv->tiling_mode == I915_TILING_NONE)  		return 4096;  	/*  	 * Previous chips need to be aligned to the size of the smallest  	 * fence register that can contain the object.  	 */ +	return i915_gem_get_gtt_size(obj_priv); +} + +static uint32_t +i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv) +{ +	struct drm_device *dev = obj_priv->base.dev; +	uint32_t size; + +	/* +	 * Minimum alignment is 4k (GTT page size), but might be greater +	 * if a fence register is needed for the object. +	 */ +	if (INTEL_INFO(dev)->gen >= 4) +		return obj_priv->base.size; + +	/* +	 * Previous chips need to be aligned to the size of the smallest +	 * fence register that can contain the object. +	 */  	if (INTEL_INFO(dev)->gen == 3) -		start = 1024*1024; +		size = 1024*1024;  	else -		start = 512*1024; +		size = 512*1024; -	for (i = start; i < obj->size; i <<= 1) -		; +	while (size < obj_priv->base.size) +		size <<= 1; -	return i; +	return size;  }  /** @@ -2253,8 +2265,10 @@ i915_gem_object_unbind(struct drm_gem_object *obj)  	i915_gem_object_put_pages_gtt(obj); -	i915_gem_info_remove_gtt(dev_priv, obj); +	i915_gem_info_remove_gtt(dev_priv, obj_priv);  	list_del_init(&obj_priv->mm_list); +	obj_priv->fenceable = true; +	obj_priv->mappable = true;  	drm_mm_put_block(obj_priv->gtt_space);  	obj_priv->gtt_space = NULL; @@ -2311,16 +2325,16 @@ i915_gpu_idle(struct drm_device *dev)  	return 0;  } -static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg) +static void sandybridge_write_fence_reg(struct drm_gem_object *obj)  { -	struct drm_gem_object *obj = reg->obj;  	struct drm_device *dev = obj->dev;  	drm_i915_private_t *dev_priv = dev->dev_private;  	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); +	u32 size = i915_gem_get_gtt_size(obj_priv);  	int regnum = obj_priv->fence_reg;  	uint64_t val; -	val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) & +	val = (uint64_t)((obj_priv->gtt_offset + size - 4096) &  		    0xfffff000) << 32;  	val |= obj_priv->gtt_offset & 0xfffff000;  	val |= (uint64_t)((obj_priv->stride / 128) - 1) << @@ -2333,16 +2347,16 @@ static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg)  	I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (regnum * 8), val);  } -static void i965_write_fence_reg(struct drm_i915_fence_reg *reg) +static void i965_write_fence_reg(struct drm_gem_object *obj)  { -	struct drm_gem_object *obj = reg->obj;  	struct drm_device *dev = obj->dev;  	drm_i915_private_t *dev_priv = dev->dev_private;  	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); +	u32 size = i915_gem_get_gtt_size(obj_priv);  	int regnum = obj_priv->fence_reg;  	uint64_t val; -	val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) & +	val = (uint64_t)((obj_priv->gtt_offset + size - 4096) &  		    0xfffff000) << 32;  	val |= obj_priv->gtt_offset & 0xfffff000;  	val |= ((obj_priv->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT; @@ -2353,21 +2367,20 @@ static void i965_write_fence_reg(struct drm_i915_fence_reg *reg)  	I915_WRITE64(FENCE_REG_965_0 + (regnum * 8), val);  } -static void i915_write_fence_reg(struct drm_i915_fence_reg *reg) +static void i915_write_fence_reg(struct drm_gem_object *obj)  { -	struct drm_gem_object *obj = reg->obj;  	struct drm_device *dev = obj->dev;  	drm_i915_private_t *dev_priv = dev->dev_private;  	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); -	int regnum = obj_priv->fence_reg; +	u32 size = i915_gem_get_gtt_size(obj_priv); +	uint32_t fence_reg, val, pitch_val;  	int tile_width; -	uint32_t fence_reg, val; -	uint32_t pitch_val;  	if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) || -	    (obj_priv->gtt_offset & (obj->size - 1))) { -		WARN(1, "%s: object 0x%08x not 1M or size (0x%zx) aligned\n", -		     __func__, obj_priv->gtt_offset, obj->size); +	    (obj_priv->gtt_offset & (size - 1))) { +		WARN(1, "%s: object 0x%08x [fenceable? %d] not 1M or size (0x%08x) aligned [gtt_space offset=%lx, size=%lx]\n", +		     __func__, obj_priv->gtt_offset, obj_priv->fenceable, size, +		     obj_priv->gtt_space->start, obj_priv->gtt_space->size);  		return;  	} @@ -2390,23 +2403,24 @@ static void i915_write_fence_reg(struct drm_i915_fence_reg *reg)  	val = obj_priv->gtt_offset;  	if (obj_priv->tiling_mode == I915_TILING_Y)  		val |= 1 << I830_FENCE_TILING_Y_SHIFT; -	val |= I915_FENCE_SIZE_BITS(obj->size); +	val |= I915_FENCE_SIZE_BITS(size);  	val |= pitch_val << I830_FENCE_PITCH_SHIFT;  	val |= I830_FENCE_REG_VALID; -	if (regnum < 8) -		fence_reg = FENCE_REG_830_0 + (regnum * 4); +	fence_reg = obj_priv->fence_reg; +	if (fence_reg < 8) +		fence_reg = FENCE_REG_830_0 + fence_reg * 4;  	else -		fence_reg = FENCE_REG_945_8 + ((regnum - 8) * 4); +		fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4;  	I915_WRITE(fence_reg, val);  } -static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) +static void i830_write_fence_reg(struct drm_gem_object *obj)  { -	struct drm_gem_object *obj = reg->obj;  	struct drm_device *dev = obj->dev;  	drm_i915_private_t *dev_priv = dev->dev_private;  	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); +	u32 size = i915_gem_get_gtt_size(obj_priv);  	int regnum = obj_priv->fence_reg;  	uint32_t val;  	uint32_t pitch_val; @@ -2426,7 +2440,7 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)  	val = obj_priv->gtt_offset;  	if (obj_priv->tiling_mode == I915_TILING_Y)  		val |= 1 << I830_FENCE_TILING_Y_SHIFT; -	fence_size_bits = I830_FENCE_SIZE_BITS(obj->size); +	fence_size_bits = I830_FENCE_SIZE_BITS(size);  	WARN_ON(fence_size_bits & ~0x00000f00);  	val |= fence_size_bits;  	val |= pitch_val << I830_FENCE_PITCH_SHIFT; @@ -2438,10 +2452,9 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)  static int i915_find_fence_reg(struct drm_device *dev,  			       bool interruptible)  { -	struct drm_i915_fence_reg *reg = NULL; -	struct drm_i915_gem_object *obj_priv = NULL;  	struct drm_i915_private *dev_priv = dev->dev_private; -	struct drm_gem_object *obj = NULL; +	struct drm_i915_fence_reg *reg; +	struct drm_i915_gem_object *obj_priv = NULL;  	int i, avail, ret;  	/* First try to find a free reg */ @@ -2460,33 +2473,31 @@ static int i915_find_fence_reg(struct drm_device *dev,  		return -ENOSPC;  	/* None available, try to steal one or wait for a user to finish */ -	i = I915_FENCE_REG_NONE; +	avail = I915_FENCE_REG_NONE;  	list_for_each_entry(reg, &dev_priv->mm.fence_list,  			    lru_list) { -		obj = reg->obj; -		obj_priv = to_intel_bo(obj); - +		obj_priv = to_intel_bo(reg->obj);  		if (obj_priv->pin_count)  			continue;  		/* found one! */ -		i = obj_priv->fence_reg; +		avail = obj_priv->fence_reg;  		break;  	} -	BUG_ON(i == I915_FENCE_REG_NONE); +	BUG_ON(avail == I915_FENCE_REG_NONE);  	/* We only have a reference on obj from the active list. put_fence_reg  	 * might drop that one, causing a use-after-free in it. So hold a  	 * private reference to obj like the other callers of put_fence_reg  	 * (set_tiling ioctl) do. */ -	drm_gem_object_reference(obj); -	ret = i915_gem_object_put_fence_reg(obj, interruptible); -	drm_gem_object_unreference(obj); +	drm_gem_object_reference(&obj_priv->base); +	ret = i915_gem_object_put_fence_reg(&obj_priv->base, interruptible); +	drm_gem_object_unreference(&obj_priv->base);  	if (ret != 0)  		return ret; -	return i; +	return avail;  }  /** @@ -2551,22 +2562,23 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj,  	switch (INTEL_INFO(dev)->gen) {  	case 6: -		sandybridge_write_fence_reg(reg); +		sandybridge_write_fence_reg(obj);  		break;  	case 5:  	case 4: -		i965_write_fence_reg(reg); +		i965_write_fence_reg(obj);  		break;  	case 3: -		i915_write_fence_reg(reg); +		i915_write_fence_reg(obj);  		break;  	case 2: -		i830_write_fence_reg(reg); +		i830_write_fence_reg(obj);  		break;  	} -	trace_i915_gem_object_get_fence(obj, obj_priv->fence_reg, -			obj_priv->tiling_mode); +	trace_i915_gem_object_get_fence(obj, +					obj_priv->fence_reg, +					obj_priv->tiling_mode);  	return 0;  } @@ -2671,13 +2683,15 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj,  static int  i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,  			    unsigned alignment, -			    bool mappable) +			    bool mappable, +			    bool need_fence)  {  	struct drm_device *dev = obj->dev;  	drm_i915_private_t *dev_priv = dev->dev_private;  	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);  	struct drm_mm_node *free_space; -	gfp_t gfpmask =  __GFP_NORETRY | __GFP_NOWARN; +	gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN; +	u32 size, fence_size, fence_alignment;  	int ret;  	if (obj_priv->madv != I915_MADV_WILLNEED) { @@ -2685,13 +2699,18 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,  		return -EINVAL;  	} +	fence_size = i915_gem_get_gtt_size(obj_priv); +	fence_alignment = i915_gem_get_gtt_alignment(obj_priv); +  	if (alignment == 0) -		alignment = i915_gem_get_gtt_alignment(obj); -	if (alignment & (i915_gem_get_gtt_alignment(obj) - 1)) { +		alignment = need_fence ? fence_alignment : 4096; +	if (need_fence && alignment & (fence_alignment - 1)) {  		DRM_ERROR("Invalid object alignment requested %u\n", alignment);  		return -EINVAL;  	} +	size = need_fence ? fence_size : obj->size; +  	/* If the object is bigger than the entire aperture, reject it early  	 * before evicting everything in a vain attempt to find space.  	 */ @@ -2705,32 +2724,29 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,  	if (mappable)  		free_space =  			drm_mm_search_free_in_range(&dev_priv->mm.gtt_space, -						    obj->size, alignment, 0, +						    size, alignment, 0,  						    dev_priv->mm.gtt_mappable_end,  						    0);  	else  		free_space = drm_mm_search_free(&dev_priv->mm.gtt_space, -						obj->size, alignment, 0); +						size, alignment, 0);  	if (free_space != NULL) {  		if (mappable)  			obj_priv->gtt_space =  				drm_mm_get_block_range_generic(free_space, -							       obj->size, -							       alignment, 0, +							       size, alignment, 0,  							       dev_priv->mm.gtt_mappable_end,  							       0);  		else  			obj_priv->gtt_space = -				drm_mm_get_block(free_space, obj->size, -						 alignment); +				drm_mm_get_block(free_space, size, alignment);  	}  	if (obj_priv->gtt_space == NULL) {  		/* If the gtt is empty and we're still having trouble  		 * fitting our object in, we're out of memory.  		 */ -		ret = i915_gem_evict_something(dev, obj->size, alignment, -					       mappable); +		ret = i915_gem_evict_something(dev, size, alignment, mappable);  		if (ret)  			return ret; @@ -2744,7 +2760,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,  		if (ret == -ENOMEM) {  			/* first try to clear up some space from the GTT */ -			ret = i915_gem_evict_something(dev, obj->size, +			ret = i915_gem_evict_something(dev, size,  						       alignment, mappable);  			if (ret) {  				/* now try to shrink everyone else */ @@ -2775,8 +2791,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,  		drm_mm_put_block(obj_priv->gtt_space);  		obj_priv->gtt_space = NULL; -		ret = i915_gem_evict_something(dev, obj->size, alignment, -					       mappable); +		ret = i915_gem_evict_something(dev, size, +					       alignment, mappable);  		if (ret)  			return ret; @@ -2787,7 +2803,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,  	/* keep track of bounds object by adding it to the inactive list */  	list_add_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list); -	i915_gem_info_add_gtt(dev_priv, obj); +	i915_gem_info_add_gtt(dev_priv, obj_priv);  	/* Assert that the object is not currently in any GPU domain. As it  	 * wasn't in the GTT, there shouldn't be any way it could have been in @@ -2798,6 +2814,13 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,  	trace_i915_gem_object_bind(obj, obj_priv->gtt_offset, mappable); +	obj_priv->fenceable = +		obj_priv->gtt_space->size == fence_size && +		(obj_priv->gtt_space->start & (fence_alignment -1)) == 0; + +	obj_priv->mappable = +		obj_priv->gtt_offset + obj->size <= dev_priv->mm.gtt_mappable_end; +  	return 0;  } @@ -3516,9 +3539,8 @@ i915_gem_execbuffer_pin(struct drm_device *dev,  				entry->relocation_count ? true : need_fence;  			/* Check fence reg constraints and rebind if necessary */ -			if (need_fence && -			    !i915_gem_object_fence_offset_ok(&obj->base, -							     obj->tiling_mode)) { +			if ((need_fence && !obj->fenceable) || +			    (need_mappable && !obj->mappable)) {  				ret = i915_gem_object_unbind(&obj->base);  				if (ret)  					break; @@ -3526,7 +3548,8 @@ i915_gem_execbuffer_pin(struct drm_device *dev,  			ret = i915_gem_object_pin(&obj->base,  						  entry->alignment, -						  need_mappable); +						  need_mappable, +						  need_fence);  			if (ret)  				break; @@ -4097,7 +4120,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,  int  i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, -		    bool mappable) +		    bool mappable, bool need_fence)  {  	struct drm_device *dev = obj->dev;  	struct drm_i915_private *dev_priv = dev->dev_private; @@ -4108,14 +4131,15 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment,  	WARN_ON(i915_verify_lists(dev));  	if (obj_priv->gtt_space != NULL) { -		if (alignment == 0) -			alignment = i915_gem_get_gtt_alignment(obj); -		if (obj_priv->gtt_offset & (alignment - 1) || -		    (mappable && !i915_gem_object_cpu_accessible(obj_priv))) { +		if ((alignment && obj_priv->gtt_offset & (alignment - 1)) || +		    (need_fence && !obj_priv->fenceable) || +		    (mappable && !obj_priv->mappable)) {  			WARN(obj_priv->pin_count,  			     "bo is already pinned with incorrect alignment:" -			     " offset=%x, req.alignment=%x\n", -			     obj_priv->gtt_offset, alignment); +			     " offset=%x, req.alignment=%x, need_fence=%d, fenceable=%d, mappable=%d, cpu_accessible=%d\n", +			     obj_priv->gtt_offset, alignment, +			     need_fence, obj_priv->fenceable, +			     mappable, obj_priv->mappable);  			ret = i915_gem_object_unbind(obj);  			if (ret)  				return ret; @@ -4123,13 +4147,14 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment,  	}  	if (obj_priv->gtt_space == NULL) { -		ret = i915_gem_object_bind_to_gtt(obj, alignment, mappable); +		ret = i915_gem_object_bind_to_gtt(obj, alignment, +						  mappable, need_fence);  		if (ret)  			return ret;  	}  	if (obj_priv->pin_count++ == 0) { -		i915_gem_info_add_pin(dev_priv, obj, mappable); +		i915_gem_info_add_pin(dev_priv, obj_priv, mappable);  		if (!obj_priv->active)  			list_move_tail(&obj_priv->mm_list,  				       &dev_priv->mm.pinned_list); @@ -4155,7 +4180,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj)  		if (!obj_priv->active)  			list_move_tail(&obj_priv->mm_list,  				       &dev_priv->mm.inactive_list); -		i915_gem_info_remove_pin(dev_priv, obj); +		i915_gem_info_remove_pin(dev_priv, obj_priv);  	}  	WARN_ON(i915_verify_lists(dev));  } @@ -4196,7 +4221,8 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,  	obj_priv->user_pin_count++;  	obj_priv->pin_filp = file_priv;  	if (obj_priv->user_pin_count == 1) { -		ret = i915_gem_object_pin(obj, args->alignment, true); +		ret = i915_gem_object_pin(obj, args->alignment, +					  true, obj_priv->tiling_mode);  		if (ret)  			goto out;  	} @@ -4389,6 +4415,8 @@ struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,  	INIT_LIST_HEAD(&obj->ring_list);  	INIT_LIST_HEAD(&obj->gpu_write_list);  	obj->madv = I915_MADV_WILLNEED; +	obj->fenceable = true; +	obj->mappable = true;  	return &obj->base;  } @@ -4508,7 +4536,7 @@ i915_gem_init_pipe_control(struct drm_device *dev)  	obj_priv = to_intel_bo(obj);  	obj_priv->agp_type = AGP_USER_CACHED_MEMORY; -	ret = i915_gem_object_pin(obj, 4096, true); +	ret = i915_gem_object_pin(obj, 4096, true, false);  	if (ret)  		goto err_unref;  |