Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49ef5294 authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915: Move fence tracking from object to vma



In order to handle tiled partial GTT mmappings, we need to associate the
fence with an individual vma.

v2: A couple of silly drops replaced spotted by Joonas

Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20160818161718.27187-21-chris@chris-wilson.co.uk
parent a1e5afbe
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -152,11 +152,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
		seq_printf(m, "%x ",
			   i915_gem_active_get_seqno(&obj->last_read[id],
						     &obj->base.dev->struct_mutex));
	seq_printf(m, "] %x %x%s%s%s",
	seq_printf(m, "] %x %s%s%s",
		   i915_gem_active_get_seqno(&obj->last_write,
					     &obj->base.dev->struct_mutex),
		   i915_gem_active_get_seqno(&obj->last_fence,
					     &obj->base.dev->struct_mutex),
		   i915_cache_level_str(to_i915(obj->base.dev), obj->cache_level),
		   obj->dirty ? " dirty" : "",
		   obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
@@ -169,8 +167,6 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
	seq_printf(m, " (pinned x %d)", pin_count);
	if (obj->pin_display)
		seq_printf(m, " (display)");
	if (obj->fence_reg != I915_FENCE_REG_NONE)
		seq_printf(m, " (fence: %d)", obj->fence_reg);
	list_for_each_entry(vma, &obj->vma_list, obj_link) {
		if (!drm_mm_node_allocated(&vma->node))
			continue;
@@ -180,6 +176,10 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
			   vma->node.start, vma->node.size);
		if (i915_vma_is_ggtt(vma))
			seq_printf(m, ", type: %u", vma->ggtt_view.type);
		if (vma->fence)
			seq_printf(m, " , fence: %d%s",
				   vma->fence->id,
				   i915_gem_active_isset(&vma->last_fence) ? "*" : "");
		seq_puts(m, ")");
	}
	if (obj->stolen)
@@ -938,14 +938,14 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)

	seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs);
	for (i = 0; i < dev_priv->num_fence_regs; i++) {
		struct drm_i915_gem_object *obj = dev_priv->fence_regs[i].obj;
		struct i915_vma *vma = dev_priv->fence_regs[i].vma;

		seq_printf(m, "Fence %d, pin count = %d, object = ",
			   i, dev_priv->fence_regs[i].pin_count);
		if (obj == NULL)
		if (!vma)
			seq_puts(m, "unused");
		else
			describe_obj(m, obj);
			describe_obj(m, vma->obj);
		seq_putc(m, '\n');
	}

+55 −27
Original line number Diff line number Diff line
@@ -455,15 +455,21 @@ struct intel_opregion {
struct intel_overlay;
struct intel_overlay_error_state;

#define I915_FENCE_REG_NONE -1
#define I915_MAX_NUM_FENCES 32
/* 32 fences + sign bit for FENCE_REG_NONE */
#define I915_MAX_NUM_FENCE_BITS 6

struct drm_i915_fence_reg {
	struct list_head link;
	struct drm_i915_gem_object *obj;
	struct drm_i915_private *i915;
	struct i915_vma *vma;
	int pin_count;
	int id;
	/**
	 * Whether the tiling parameters for the currently
	 * associated fence register have changed. Note that
	 * for the purposes of tracking tiling changes we also
	 * treat the unfenced register, the register slot that
	 * the object occupies whilst it executes a fenced
	 * command (such as BLT on gen2/3), as a "fence".
	 */
	bool dirty;
};

struct sdvo_device_mapping {
@@ -2171,27 +2177,11 @@ struct drm_i915_gem_object {
	 */
	unsigned int dirty:1;

	/**
	 * Fence register bits (if any) for this object.  Will be set
	 * as needed when mapped into the GTT.
	 * Protected by dev->struct_mutex.
	 */
	signed int fence_reg:I915_MAX_NUM_FENCE_BITS;

	/**
	 * Advice: are the backing pages purgeable?
	 */
	unsigned int madv:2;

	/**
	 * Whether the tiling parameters for the currently associated fence
	 * register have changed. Note that for the purposes of tracking
	 * tiling changes we also treat the unfenced register, the register
	 * slot that the object occupies whilst it executes a fenced
	 * command (such as BLT on gen2/3), as a "fence".
	 */
	unsigned int fence_dirty:1;

	/**
	 * Whether the current gtt mapping needs to be mappable (and isn't just
	 * mappable by accident). Track pin and fault separate for a more
@@ -2240,7 +2230,6 @@ struct drm_i915_gem_object {
	 */
	struct i915_gem_active last_read[I915_NUM_ENGINES];
	struct i915_gem_active last_write;
	struct i915_gem_active last_fence;

	/** References from framebuffers, locks out tiling changes. */
	unsigned long framebuffer_references;
@@ -3343,11 +3332,50 @@ i915_gem_object_ggtt_offset(struct drm_i915_gem_object *o,
}

/* i915_gem_fence.c */
int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj);
int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj);
int __must_check i915_vma_get_fence(struct i915_vma *vma);
int __must_check i915_vma_put_fence(struct i915_vma *vma);

bool i915_gem_object_pin_fence(struct drm_i915_gem_object *obj);
void i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj);
/**
 * i915_vma_pin_fence - pin fencing state
 * @vma: vma to pin fencing for
 *
 * This pins the fencing state (whether tiled or untiled) to make sure the
 * vma (and its object) is ready to be used as a scanout target. Fencing
 * status must be synchronize first by calling i915_vma_get_fence():
 *
 * The resulting fence pin reference must be released again with
 * i915_vma_unpin_fence().
 *
 * Returns:
 *
 * True if the vma has a fence, false otherwise.
 */
static inline bool
i915_vma_pin_fence(struct i915_vma *vma)
{
	if (vma->fence) {
		vma->fence->pin_count++;
		return true;
	} else
		return false;
}

/**
 * i915_vma_unpin_fence - unpin fencing state
 * @vma: vma to unpin fencing for
 *
 * This releases the fence pin reference acquired through
 * i915_vma_pin_fence. It will handle both objects with and without an
 * attached fence correctly, callers do not need to distinguish this.
 */
static inline void
i915_vma_unpin_fence(struct i915_vma *vma)
{
	if (vma->fence) {
		GEM_BUG_ON(vma->fence->pin_count <= 0);
		vma->fence->pin_count--;
	}
}

void i915_gem_restore_fences(struct drm_device *dev);

+17 −13
Original line number Diff line number Diff line
@@ -829,7 +829,7 @@ i915_gem_gtt_pread(struct drm_device *dev,
	if (!IS_ERR(vma)) {
		node.start = i915_ggtt_offset(vma);
		node.allocated = false;
		ret = i915_gem_object_put_fence(obj);
		ret = i915_vma_put_fence(vma);
		if (ret) {
			i915_vma_unpin(vma);
			vma = ERR_PTR(ret);
@@ -1131,7 +1131,7 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_private *i915,
	if (!IS_ERR(vma)) {
		node.start = i915_ggtt_offset(vma);
		node.allocated = false;
		ret = i915_gem_object_put_fence(obj);
		ret = i915_vma_put_fence(vma);
		if (ret) {
			i915_vma_unpin(vma);
			vma = ERR_PTR(ret);
@@ -1751,7 +1751,7 @@ int i915_gem_fault(struct vm_area_struct *area, struct vm_fault *vmf)
	if (ret)
		goto err_unpin;

	ret = i915_gem_object_get_fence(obj);
	ret = i915_vma_get_fence(vma);
	if (ret)
		goto err_unpin;

@@ -2903,7 +2903,7 @@ int i915_vma_unbind(struct i915_vma *vma)
		i915_gem_object_finish_gtt(obj);

		/* release the fence reg _after_ flushing */
		ret = i915_gem_object_put_fence(obj);
		ret = i915_vma_put_fence(vma);
		if (ret)
			return ret;

@@ -3385,9 +3385,11 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
			 * dropped the fence as all snoopable access is
			 * supposed to be linear.
			 */
			ret = i915_gem_object_put_fence(obj);
			list_for_each_entry(vma, &obj->vma_list, obj_link) {
				ret = i915_vma_put_fence(vma);
				if (ret)
					return ret;
			}
		} else {
			/* We either have incoherent backing store and
			 * so no GTT access or the architecture is fully
@@ -4065,14 +4067,12 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
				    i915_gem_object_retire__read);
	init_request_active(&obj->last_write,
			    i915_gem_object_retire__write);
	init_request_active(&obj->last_fence, NULL);
	INIT_LIST_HEAD(&obj->obj_exec_link);
	INIT_LIST_HEAD(&obj->vma_list);
	INIT_LIST_HEAD(&obj->batch_pool_link);

	obj->ops = ops;

	obj->fence_reg = I915_FENCE_REG_NONE;
	obj->madv = I915_MADV_WILLNEED;

	i915_gem_info_add_obj(to_i915(obj->base.dev), obj->base.size);
@@ -4502,6 +4502,7 @@ void
i915_gem_load_init_fences(struct drm_i915_private *dev_priv)
{
	struct drm_device *dev = &dev_priv->drm;
	int i;

	if (INTEL_INFO(dev_priv)->gen >= 7 && !IS_VALLEYVIEW(dev_priv) &&
	    !IS_CHERRYVIEW(dev_priv))
@@ -4517,6 +4518,13 @@ i915_gem_load_init_fences(struct drm_i915_private *dev_priv)
				I915_READ(vgtif_reg(avail_rs.fence_num));

	/* Initialize fence registers to zero */
	for (i = 0; i < dev_priv->num_fence_regs; i++) {
		struct drm_i915_fence_reg *fence = &dev_priv->fence_regs[i];

		fence->i915 = dev_priv;
		fence->id = i;
		list_add_tail(&fence->link, &dev_priv->mm.fence_list);
	}
	i915_gem_restore_fences(dev);

	i915_gem_detect_bit_6_swizzle(dev);
@@ -4552,8 +4560,6 @@ i915_gem_load_init(struct drm_device *dev)
	INIT_LIST_HEAD(&dev_priv->mm.fence_list);
	for (i = 0; i < I915_NUM_ENGINES; i++)
		init_engine_lists(&dev_priv->engine[i]);
	for (i = 0; i < I915_MAX_NUM_FENCES; i++)
		INIT_LIST_HEAD(&dev_priv->fence_regs[i].link);
	INIT_DELAYED_WORK(&dev_priv->gt.retire_work,
			  i915_gem_retire_work_handler);
	INIT_DELAYED_WORK(&dev_priv->gt.idle_work,
@@ -4563,8 +4569,6 @@ i915_gem_load_init(struct drm_device *dev)

	dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL;

	INIT_LIST_HEAD(&dev_priv->mm.fence_list);

	init_waitqueue_head(&dev_priv->pending_flip_queue);

	dev_priv->mm.interruptible = true;
+6 −14
Original line number Diff line number Diff line
@@ -250,7 +250,6 @@ static void
i915_gem_execbuffer_unreserve_vma(struct i915_vma *vma)
{
	struct drm_i915_gem_exec_object2 *entry;
	struct drm_i915_gem_object *obj = vma->obj;

	if (!drm_mm_node_allocated(&vma->node))
		return;
@@ -258,7 +257,7 @@ i915_gem_execbuffer_unreserve_vma(struct i915_vma *vma)
	entry = vma->exec_entry;

	if (entry->flags & __EXEC_OBJECT_HAS_FENCE)
		i915_gem_object_unpin_fence(obj);
		i915_vma_unpin_fence(vma);

	if (entry->flags & __EXEC_OBJECT_HAS_PIN)
		__i915_vma_unpin(vma);
@@ -455,7 +454,7 @@ static void *reloc_iomap(struct drm_i915_gem_object *obj,
			if (ret)
				return ERR_PTR(ret);
		} else {
			ret = i915_gem_object_put_fence(obj);
			ret = i915_vma_put_fence(vma);
			if (ret) {
				i915_vma_unpin(vma);
				return ERR_PTR(ret);
@@ -811,11 +810,11 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
	entry->flags |= __EXEC_OBJECT_HAS_PIN;

	if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
		ret = i915_gem_object_get_fence(obj);
		ret = i915_vma_get_fence(vma);
		if (ret)
			return ret;

		if (i915_gem_object_pin_fence(obj))
		if (i915_vma_pin_fence(vma))
			entry->flags |= __EXEC_OBJECT_HAS_FENCE;
	}

@@ -1305,15 +1304,8 @@ void i915_vma_move_to_active(struct i915_vma *vma,
		obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
	}

	if (flags & EXEC_OBJECT_NEEDS_FENCE) {
		i915_gem_active_set(&obj->last_fence, req);
		if (flags & __EXEC_OBJECT_HAS_FENCE) {
			struct drm_i915_private *dev_priv = req->i915;

			list_move_tail(&dev_priv->fence_regs[obj->fence_reg].link,
				       &dev_priv->mm.fence_list);
		}
	}
	if (flags & EXEC_OBJECT_NEEDS_FENCE)
		i915_gem_active_set(&vma->last_fence, req);

	i915_vma_set_active(vma, idx);
	i915_gem_active_set(&vma->last_read[idx], req);
+161 −261
Original line number Diff line number Diff line
@@ -55,23 +55,45 @@
 * CPU ptes into GTT mmaps (not the GTT ptes themselves) as needed.
 */

static void i965_write_fence_reg(struct drm_device *dev, int reg,
				 struct drm_i915_gem_object *obj)
#define pipelined 0

static void i965_write_fence_reg(struct drm_i915_fence_reg *fence,
				 struct i915_vma *vma)
{
	struct drm_i915_private *dev_priv = to_i915(dev);
	i915_reg_t fence_reg_lo, fence_reg_hi;
	int fence_pitch_shift;
	u64 val;

	if (INTEL_INFO(dev)->gen >= 6) {
		fence_reg_lo = FENCE_REG_GEN6_LO(reg);
		fence_reg_hi = FENCE_REG_GEN6_HI(reg);
	if (INTEL_INFO(fence->i915)->gen >= 6) {
		fence_reg_lo = FENCE_REG_GEN6_LO(fence->id);
		fence_reg_hi = FENCE_REG_GEN6_HI(fence->id);
		fence_pitch_shift = GEN6_FENCE_PITCH_SHIFT;

	} else {
		fence_reg_lo = FENCE_REG_965_LO(reg);
		fence_reg_hi = FENCE_REG_965_HI(reg);
		fence_reg_lo = FENCE_REG_965_LO(fence->id);
		fence_reg_hi = FENCE_REG_965_HI(fence->id);
		fence_pitch_shift = I965_FENCE_PITCH_SHIFT;
	}

	val = 0;
	if (vma) {
		unsigned int tiling = i915_gem_object_get_tiling(vma->obj);
		bool is_y_tiled = tiling == I915_TILING_Y;
		unsigned int stride = i915_gem_object_get_stride(vma->obj);
		u32 row_size = stride * (is_y_tiled ? 32 : 8);
		u32 size = rounddown((u32)vma->node.size, row_size);

		val = ((vma->node.start + size - 4096) & 0xfffff000) << 32;
		val |= vma->node.start & 0xfffff000;
		val |= (u64)((stride / 128) - 1) << fence_pitch_shift;
		if (is_y_tiled)
			val |= BIT(I965_FENCE_TILING_Y_SHIFT);
		val |= I965_FENCE_REG_VALID;
	}

	if (!pipelined) {
		struct drm_i915_private *dev_priv = fence->i915;

		/* To w/a incoherency with non-atomic 64-bit register updates,
		 * we split the 64-bit update into two 32-bit writes. In order
		 * for a partial fence not to be evaluated between writes, we
@@ -84,45 +106,22 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg,
		I915_WRITE(fence_reg_lo, 0);
		POSTING_READ(fence_reg_lo);

	if (obj) {
		struct i915_vma *vma = i915_gem_object_to_ggtt(obj, NULL);
		unsigned int tiling = i915_gem_object_get_tiling(obj);
		unsigned int stride = i915_gem_object_get_stride(obj);
		u32 size = vma->node.size;
		u32 row_size = stride * (tiling == I915_TILING_Y ? 32 : 8);
		u64 val;

		/* Adjust fence size to match tiled area */
		size = rounddown(size, row_size);

		val = ((vma->node.start + size - 4096) & 0xfffff000) << 32;
		val |= vma->node.start & 0xfffff000;
		val |= (u64)((stride / 128) - 1) << fence_pitch_shift;
		if (tiling == I915_TILING_Y)
			val |= 1 << I965_FENCE_TILING_Y_SHIFT;
		val |= I965_FENCE_REG_VALID;

		I915_WRITE(fence_reg_hi, val >> 32);
		POSTING_READ(fence_reg_hi);

		I915_WRITE(fence_reg_lo, val);
		I915_WRITE(fence_reg_hi, upper_32_bits(val));
		I915_WRITE(fence_reg_lo, lower_32_bits(val));
		POSTING_READ(fence_reg_lo);
	} else {
		I915_WRITE(fence_reg_hi, 0);
		POSTING_READ(fence_reg_hi);
	}
}

static void i915_write_fence_reg(struct drm_device *dev, int reg,
				 struct drm_i915_gem_object *obj)
static void i915_write_fence_reg(struct drm_i915_fence_reg *fence,
				 struct i915_vma *vma)
{
	struct drm_i915_private *dev_priv = to_i915(dev);
	u32 val;

	if (obj) {
		struct i915_vma *vma = i915_gem_object_to_ggtt(obj, NULL);
		unsigned int tiling = i915_gem_object_get_tiling(obj);
		unsigned int stride = i915_gem_object_get_stride(obj);
	val = 0;
	if (vma) {
		unsigned int tiling = i915_gem_object_get_tiling(vma->obj);
		bool is_y_tiled = tiling == I915_TILING_Y;
		unsigned int stride = i915_gem_object_get_stride(vma->obj);
		int pitch_val;
		int tile_width;

@@ -134,7 +133,7 @@ static void i915_write_fence_reg(struct drm_device *dev, int reg,
		     i915_vma_is_map_and_fenceable(vma),
		     vma->node.size);

		if (tiling == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))
		if (is_y_tiled && HAS_128_BYTE_Y_TILING(fence->i915))
			tile_width = 128;
		else
			tile_width = 512;
@@ -144,28 +143,32 @@ static void i915_write_fence_reg(struct drm_device *dev, int reg,
		pitch_val = ffs(pitch_val) - 1;

		val = vma->node.start;
		if (tiling == I915_TILING_Y)
			val |= 1 << I830_FENCE_TILING_Y_SHIFT;
		if (is_y_tiled)
			val |= BIT(I830_FENCE_TILING_Y_SHIFT);
		val |= I915_FENCE_SIZE_BITS(vma->node.size);
		val |= pitch_val << I830_FENCE_PITCH_SHIFT;
		val |= I830_FENCE_REG_VALID;
	} else
		val = 0;
	}

	if (!pipelined) {
		struct drm_i915_private *dev_priv = fence->i915;
		i915_reg_t reg = FENCE_REG(fence->id);

	I915_WRITE(FENCE_REG(reg), val);
	POSTING_READ(FENCE_REG(reg));
		I915_WRITE(reg, val);
		POSTING_READ(reg);
	}
}

static void i830_write_fence_reg(struct drm_device *dev, int reg,
				struct drm_i915_gem_object *obj)
static void i830_write_fence_reg(struct drm_i915_fence_reg *fence,
				 struct i915_vma *vma)
{
	struct drm_i915_private *dev_priv = to_i915(dev);
	u32 val;

	if (obj) {
		struct i915_vma *vma = i915_gem_object_to_ggtt(obj, NULL);
		unsigned int tiling = i915_gem_object_get_tiling(obj);
		unsigned int stride = i915_gem_object_get_stride(obj);
	val = 0;
	if (vma) {
		unsigned int tiling = i915_gem_object_get_tiling(vma->obj);
		bool is_y_tiled = tiling == I915_TILING_Y;
		unsigned int stride = i915_gem_object_get_stride(vma->obj);
		u32 pitch_val;

		WARN((vma->node.start & ~I830_FENCE_START_MASK) ||
@@ -178,104 +181,102 @@ static void i830_write_fence_reg(struct drm_device *dev, int reg,
		pitch_val = ffs(pitch_val) - 1;

		val = vma->node.start;
		if (tiling == I915_TILING_Y)
			val |= 1 << I830_FENCE_TILING_Y_SHIFT;
		if (is_y_tiled)
			val |= BIT(I830_FENCE_TILING_Y_SHIFT);
		val |= I830_FENCE_SIZE_BITS(vma->node.size);
		val |= pitch_val << I830_FENCE_PITCH_SHIFT;
		val |= I830_FENCE_REG_VALID;
	} else
		val = 0;
	}

	if (!pipelined) {
		struct drm_i915_private *dev_priv = fence->i915;
		i915_reg_t reg = FENCE_REG(fence->id);

	I915_WRITE(FENCE_REG(reg), val);
	POSTING_READ(FENCE_REG(reg));
		I915_WRITE(reg, val);
		POSTING_READ(reg);
	}
}

inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj)
static void fence_write(struct drm_i915_fence_reg *fence,
			struct i915_vma *vma)
{
	return obj && obj->base.read_domains & I915_GEM_DOMAIN_GTT;
	/* Previous access through the fence register is marshalled by
	 * the mb() inside the fault handlers (i915_gem_release_mmaps)
	 * and explicitly managed for internal users.
	 */

	if (IS_GEN2(fence->i915))
		i830_write_fence_reg(fence, vma);
	else if (IS_GEN3(fence->i915))
		i915_write_fence_reg(fence, vma);
	else
		i965_write_fence_reg(fence, vma);

	/* Access through the fenced region afterwards is
	 * ordered by the posting reads whilst writing the registers.
	 */

	fence->dirty = false;
}

static void i915_gem_write_fence(struct drm_device *dev, int reg,
				 struct drm_i915_gem_object *obj)
static int fence_update(struct drm_i915_fence_reg *fence,
			struct i915_vma *vma)
{
	struct drm_i915_private *dev_priv = to_i915(dev);
	int ret;

	/* Ensure that all CPU reads are completed before installing a fence
	 * and all writes before removing the fence.
	 */
	if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj))
		mb();
	if (vma) {
		if (!i915_vma_is_map_and_fenceable(vma))
			return -EINVAL;

	WARN(obj &&
	     (!i915_gem_object_get_stride(obj) ||
	      !i915_gem_object_get_tiling(obj)),
		if (WARN(!i915_gem_object_get_stride(vma->obj) ||
			 !i915_gem_object_get_tiling(vma->obj),
			 "bogus fence setup with stride: 0x%x, tiling mode: %i\n",
	     i915_gem_object_get_stride(obj),
	     i915_gem_object_get_tiling(obj));

	if (IS_GEN2(dev))
		i830_write_fence_reg(dev, reg, obj);
	else if (IS_GEN3(dev))
		i915_write_fence_reg(dev, reg, obj);
	else if (INTEL_INFO(dev)->gen >= 4)
		i965_write_fence_reg(dev, reg, obj);

	/* And similarly be paranoid that no direct access to this region
	 * is reordered to before the fence is installed.
	 */
	if (i915_gem_object_needs_mb(obj))
		mb();
			 i915_gem_object_get_stride(vma->obj),
			 i915_gem_object_get_tiling(vma->obj)))
			return -EINVAL;

		ret = i915_gem_active_retire(&vma->last_fence,
					     &vma->obj->base.dev->struct_mutex);
		if (ret)
			return ret;
	}

static inline int fence_number(struct drm_i915_private *dev_priv,
			       struct drm_i915_fence_reg *fence)
{
	return fence - dev_priv->fence_regs;
	if (fence->vma) {
		ret = i915_gem_active_retire(&fence->vma->last_fence,
				      &fence->vma->obj->base.dev->struct_mutex);
		if (ret)
			return ret;
	}

static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
					 struct drm_i915_fence_reg *fence,
					 bool enable)
{
	struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
	int reg = fence_number(dev_priv, fence);
	if (fence->vma && fence->vma != vma) {
		/* Ensure that all userspace CPU access is completed before
		 * stealing the fence.
		 */
		i915_gem_release_mmap(fence->vma->obj);

	i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL);
		fence->vma->fence = NULL;
		fence->vma = NULL;

	if (enable) {
		obj->fence_reg = reg;
		fence->obj = obj;
		list_move_tail(&fence->link, &dev_priv->mm.fence_list);
	} else {
		obj->fence_reg = I915_FENCE_REG_NONE;
		fence->obj = NULL;
		list_del_init(&fence->link);
	}
	obj->fence_dirty = false;
		list_move(&fence->link, &fence->i915->mm.fence_list);
	}

static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj)
{
	if (i915_gem_object_is_tiled(obj))
		i915_gem_release_mmap(obj);
	fence_write(fence, vma);

	/* As we do not have an associated fence register, we will force
	 * a tiling change if we ever need to acquire one.
	 */
	obj->fence_dirty = false;
	obj->fence_reg = I915_FENCE_REG_NONE;
	if (vma) {
		if (fence->vma != vma) {
			vma->fence = fence;
			fence->vma = vma;
		}

static int
i915_gem_object_wait_fence(struct drm_i915_gem_object *obj)
{
	return i915_gem_active_retire(&obj->last_fence,
				      &obj->base.dev->struct_mutex);
		list_move_tail(&fence->link, &fence->i915->mm.fence_list);
	}

	return 0;
}

/**
 * i915_gem_object_put_fence - force-remove fence for an object
 * @obj: object to map through a fence reg
 * i915_vma_put_fence - force-remove fence for a VMA
 * @vma: vma to map linearly (not through a fence reg)
 *
 * This function force-removes any fence from the given object, which is useful
 * if the kernel wants to do untiled GTT access.
@@ -285,70 +286,40 @@ i915_gem_object_wait_fence(struct drm_i915_gem_object *obj)
 * 0 on success, negative error code on failure.
 */
int
i915_gem_object_put_fence(struct drm_i915_gem_object *obj)
i915_vma_put_fence(struct i915_vma *vma)
{
	struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
	struct drm_i915_fence_reg *fence;
	int ret;
	struct drm_i915_fence_reg *fence = vma->fence;

	ret = i915_gem_object_wait_fence(obj);
	if (ret)
		return ret;

	if (obj->fence_reg == I915_FENCE_REG_NONE)
	if (!fence)
		return 0;

	fence = &dev_priv->fence_regs[obj->fence_reg];

	if (fence->pin_count)
		return -EBUSY;

	i915_gem_object_fence_lost(obj);
	i915_gem_object_update_fence(obj, fence, false);

	return 0;
	return fence_update(fence, NULL);
}

static struct drm_i915_fence_reg *
i915_find_fence_reg(struct drm_device *dev)
static struct drm_i915_fence_reg *fence_find(struct drm_i915_private *dev_priv)
{
	struct drm_i915_private *dev_priv = to_i915(dev);
	struct drm_i915_fence_reg *reg, *avail;
	int i;

	/* First try to find a free reg */
	avail = NULL;
	for (i = 0; i < dev_priv->num_fence_regs; i++) {
		reg = &dev_priv->fence_regs[i];
		if (!reg->obj)
			return reg;

		if (!reg->pin_count)
			avail = reg;
	}

	if (avail == NULL)
		goto deadlock;
	struct drm_i915_fence_reg *fence;

	/* None available, try to steal one or wait for a user to finish */
	list_for_each_entry(reg, &dev_priv->mm.fence_list, link) {
		if (reg->pin_count)
	list_for_each_entry(fence, &dev_priv->mm.fence_list, link) {
		if (fence->pin_count)
			continue;

		return reg;
		return fence;
	}

deadlock:
	/* Wait for completion of pending flips which consume fences */
	if (intel_has_pending_fb_unpin(dev))
	if (intel_has_pending_fb_unpin(&dev_priv->drm))
		return ERR_PTR(-EAGAIN);

	return ERR_PTR(-EDEADLK);
}

/**
 * i915_gem_object_get_fence - set up fencing for an object
 * @obj: object to map through a fence reg
 * i915_vma_get_fence - set up fencing for a vma
 * @vma: vma to map through a fence reg
 *
 * When mapping objects through the GTT, userspace wants to be able to write
 * to them without having to worry about swizzling if the object is tiled.
@@ -365,93 +336,27 @@ i915_find_fence_reg(struct drm_device *dev)
 * 0 on success, negative error code on failure.
 */
int
i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
i915_vma_get_fence(struct i915_vma *vma)
{
	struct drm_device *dev = obj->base.dev;
	struct drm_i915_private *dev_priv = to_i915(dev);
	bool enable = i915_gem_object_is_tiled(obj);
	struct drm_i915_fence_reg *reg;
	int ret;

	/* Have we updated the tiling parameters upon the object and so
	 * will need to serialise the write to the associated fence register?
	 */
	if (obj->fence_dirty) {
		ret = i915_gem_object_wait_fence(obj);
		if (ret)
			return ret;
	}
	struct drm_i915_fence_reg *fence;
	struct i915_vma *set = i915_gem_object_is_tiled(vma->obj) ? vma : NULL;

	/* Just update our place in the LRU if our fence is getting reused. */
	if (obj->fence_reg != I915_FENCE_REG_NONE) {
		reg = &dev_priv->fence_regs[obj->fence_reg];
		if (!obj->fence_dirty) {
			list_move_tail(&reg->link, &dev_priv->mm.fence_list);
	if (vma->fence) {
		fence = vma->fence;
		if (!fence->dirty) {
			list_move_tail(&fence->link,
				       &fence->i915->mm.fence_list);
			return 0;
		}
	} else if (enable) {
		reg = i915_find_fence_reg(dev);
		if (IS_ERR(reg))
			return PTR_ERR(reg);

		if (reg->obj) {
			struct drm_i915_gem_object *old = reg->obj;

			ret = i915_gem_object_wait_fence(old);
			if (ret)
				return ret;

			i915_gem_object_fence_lost(old);
		}
	} else if (set) {
		fence = fence_find(to_i915(vma->vm->dev));
		if (IS_ERR(fence))
			return PTR_ERR(fence);
	} else
		return 0;

	i915_gem_object_update_fence(obj, reg, enable);

	return 0;
}

/**
 * i915_gem_object_pin_fence - pin fencing state
 * @obj: object to pin fencing for
 *
 * This pins the fencing state (whether tiled or untiled) to make sure the
 * object is ready to be used as a scanout target. Fencing status must be
 * synchronize first by calling i915_gem_object_get_fence():
 *
 * The resulting fence pin reference must be released again with
 * i915_gem_object_unpin_fence().
 *
 * Returns:
 *
 * True if the object has a fence, false otherwise.
 */
bool
i915_gem_object_pin_fence(struct drm_i915_gem_object *obj)
{
	if (obj->fence_reg != I915_FENCE_REG_NONE) {
		to_i915(obj->base.dev)->fence_regs[obj->fence_reg].pin_count++;
		return true;
	} else
		return false;
}

/**
 * i915_gem_object_unpin_fence - unpin fencing state
 * @obj: object to unpin fencing for
 *
 * This releases the fence pin reference acquired through
 * i915_gem_object_pin_fence. It will handle both objects with and without an
 * attached fence correctly, callers do not need to distinguish this.
 */
void
i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj)
{
	if (obj->fence_reg != I915_FENCE_REG_NONE) {
		struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
		WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count <= 0);
		dev_priv->fence_regs[obj->fence_reg].pin_count--;
	}
	return fence_update(fence, set);
}

/**
@@ -473,12 +378,7 @@ void i915_gem_restore_fences(struct drm_device *dev)
		 * Commit delayed tiling changes if we have an object still
		 * attached to the fence, otherwise just clear the fence.
		 */
		if (reg->obj) {
			i915_gem_object_update_fence(reg->obj, reg,
						     i915_gem_object_get_tiling(reg->obj));
		} else {
			i915_gem_write_fence(dev, i, NULL);
		}
		fence_write(reg, reg->vma);
	}
}

Loading