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

Commit e1f99ce6 authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915: Propagate errors from writing to ringbuffer



Preparing the ringbuffer for adding new commands can fail (a timeout
whilst waiting for the GPU to catch up and free some space). So check
for any potential error before overwriting HEAD with new commands, and
propagate that error back to the user where possible.

Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
parent 78501eac
Loading
Loading
Loading
Loading
+61 −58
Original line number Diff line number Diff line
@@ -263,7 +263,7 @@ static int i915_dma_init(struct drm_device *dev, void *data,
 * instruction detected will be given a size of zero, which is a
 * signal to abort the rest of the buffer.
 */
static int do_validate_cmd(int cmd)
static int validate_cmd(int cmd)
{
	switch (((cmd >> 29) & 0x7)) {
	case 0x0:
@@ -321,40 +321,27 @@ static int do_validate_cmd(int cmd)
	return 0;
}

static int validate_cmd(int cmd)
{
	int ret = do_validate_cmd(cmd);

/*	printk("validate_cmd( %x ): %d\n", cmd, ret); */

	return ret;
}

static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords)
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	int i;
	int i, ret;

	if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.size - 8)
		return -EINVAL;

	BEGIN_LP_RING((dwords+1)&~1);

	for (i = 0; i < dwords;) {
		int cmd, sz;

		cmd = buffer[i];

		if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
		int sz = validate_cmd(buffer[i]);
		if (sz == 0 || i + sz > dwords)
			return -EINVAL;
		i += sz;
	}

		OUT_RING(cmd);
	ret = BEGIN_LP_RING((dwords+1)&~1);
	if (ret)
		return ret;

		while (++i, --sz) {
	for (i = 0; i < dwords; i++)
		OUT_RING(buffer[i]);
		}
	}

	if (dwords & 1)
		OUT_RING(0);

@@ -368,7 +355,9 @@ i915_emit_box(struct drm_device *dev,
	      struct drm_clip_rect *boxes,
	      int i, int DR1, int DR4)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct drm_clip_rect box = boxes[i];
	int ret;

	if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
		DRM_ERROR("Bad box %d,%d..%d,%d\n",
@@ -377,22 +366,27 @@ i915_emit_box(struct drm_device *dev,
	}

	if (INTEL_INFO(dev)->gen >= 4) {
		BEGIN_LP_RING(4);
		ret = BEGIN_LP_RING(4);
		if (ret)
			return ret;

		OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
		OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
		OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
		OUT_RING(DR4);
		ADVANCE_LP_RING();
	} else {
		BEGIN_LP_RING(6);
		ret = BEGIN_LP_RING(6);
		if (ret)
			return ret;

		OUT_RING(GFX_OP_DRAWRECT_INFO);
		OUT_RING(DR1);
		OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
		OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
		OUT_RING(DR4);
		OUT_RING(0);
		ADVANCE_LP_RING();
	}
	ADVANCE_LP_RING();

	return 0;
}
@@ -412,13 +406,14 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
	if (master_priv->sarea_priv)
		master_priv->sarea_priv->last_enqueue = dev_priv->counter;

	BEGIN_LP_RING(4);
	if (BEGIN_LP_RING(4) == 0) {
		OUT_RING(MI_STORE_DWORD_INDEX);
		OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
		OUT_RING(dev_priv->counter);
		OUT_RING(0);
		ADVANCE_LP_RING();
	}
}

static int i915_dispatch_cmdbuffer(struct drm_device * dev,
				   drm_i915_cmdbuffer_t *cmd,
@@ -458,8 +453,9 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
				     drm_i915_batchbuffer_t * batch,
				     struct drm_clip_rect *cliprects)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	int nbox = batch->num_cliprects;
	int i = 0, count;
	int i, count, ret;

	if ((batch->start | batch->used) & 0x7) {
		DRM_ERROR("alignment");
@@ -469,17 +465,19 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
	i915_kernel_lost_context(dev);

	count = nbox ? nbox : 1;

	for (i = 0; i < count; i++) {
		if (i < nbox) {
			int ret = i915_emit_box(dev, cliprects, i,
			ret = i915_emit_box(dev, cliprects, i,
					    batch->DR1, batch->DR4);
			if (ret)
				return ret;
		}

		if (!IS_I830(dev) && !IS_845G(dev)) {
			BEGIN_LP_RING(2);
			ret = BEGIN_LP_RING(2);
			if (ret)
				return ret;

			if (INTEL_INFO(dev)->gen >= 4) {
				OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
				OUT_RING(batch->start);
@@ -487,26 +485,29 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
				OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
				OUT_RING(batch->start | MI_BATCH_NON_SECURE);
			}
			ADVANCE_LP_RING();
		} else {
			BEGIN_LP_RING(4);
			ret = BEGIN_LP_RING(4);
			if (ret)
				return ret;

			OUT_RING(MI_BATCH_BUFFER);
			OUT_RING(batch->start | MI_BATCH_NON_SECURE);
			OUT_RING(batch->start + batch->used - 4);
			OUT_RING(0);
			ADVANCE_LP_RING();
		}
		ADVANCE_LP_RING();
	}


	if (IS_G4X(dev) || IS_GEN5(dev)) {
		BEGIN_LP_RING(2);
		if (BEGIN_LP_RING(2) == 0) {
			OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP);
			OUT_RING(MI_NOOP);
			ADVANCE_LP_RING();
		}
	i915_emit_breadcrumb(dev);
	}

	i915_emit_breadcrumb(dev);
	return 0;
}

@@ -515,6 +516,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
	drm_i915_private_t *dev_priv = dev->dev_private;
	struct drm_i915_master_private *master_priv =
		dev->primary->master->driver_priv;
	int ret;

	if (!master_priv->sarea_priv)
		return -EINVAL;
@@ -526,12 +528,13 @@ static int i915_dispatch_flip(struct drm_device * dev)

	i915_kernel_lost_context(dev);

	BEGIN_LP_RING(2);
	ret = BEGIN_LP_RING(10);
	if (ret)
		return ret;

	OUT_RING(MI_FLUSH | MI_READ_FLUSH);
	OUT_RING(0);
	ADVANCE_LP_RING();

	BEGIN_LP_RING(6);
	OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP);
	OUT_RING(0);
	if (dev_priv->current_page == 0) {
@@ -542,21 +545,21 @@ static int i915_dispatch_flip(struct drm_device * dev)
		dev_priv->current_page = 0;
	}
	OUT_RING(0);
	ADVANCE_LP_RING();

	BEGIN_LP_RING(2);
	OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
	OUT_RING(0);

	ADVANCE_LP_RING();

	master_priv->sarea_priv->last_enqueue = dev_priv->counter++;

	BEGIN_LP_RING(4);
	if (BEGIN_LP_RING(4) == 0) {
		OUT_RING(MI_STORE_DWORD_INDEX);
		OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
		OUT_RING(dev_priv->counter);
		OUT_RING(0);
		ADVANCE_LP_RING();
	}

	master_priv->sarea_priv->pf_current_page = dev_priv->current_page;
	return 0;
+6 −22
Original line number Diff line number Diff line
@@ -1216,30 +1216,14 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg,
#define I915_DEBUG_DISABLE_IO() (dev_priv->debug_flags &= ~(I915_DEBUG_READ | \
							    I915_DEBUG_WRITE))

#define I915_VERBOSE 0

#define BEGIN_LP_RING(n)  do { \
	drm_i915_private_t *dev_priv__ = dev->dev_private;		\
	if (I915_VERBOSE)						\
		DRM_DEBUG("   BEGIN_LP_RING %x\n", (int)(n));		\
	intel_ring_begin(&dev_priv__->render_ring, (n));		\
} while (0)
#define BEGIN_LP_RING(n) \
	intel_ring_begin(&dev_priv->render_ring, (n))

#define OUT_RING(x) \
	intel_ring_emit(&dev_priv->render_ring, x)

#define OUT_RING(x) do {						\
	drm_i915_private_t *dev_priv__ = dev->dev_private;		\
	if (I915_VERBOSE)						\
		DRM_DEBUG("   OUT_RING %x\n", (int)(x));		\
	intel_ring_emit(&dev_priv__->render_ring, x);			\
} while (0)

#define ADVANCE_LP_RING() do {						\
	drm_i915_private_t *dev_priv__ = dev->dev_private;                \
	if (I915_VERBOSE)						\
		DRM_DEBUG("ADVANCE_LP_RING %x\n",			\
				dev_priv__->render_ring.tail);		\
	intel_ring_advance(&dev_priv__->render_ring);			\
} while(0)
#define ADVANCE_LP_RING() \
	intel_ring_advance(&dev_priv->render_ring)

/**
 * Reads a dword out of the status page, which is written to from the command
+4 −1
Original line number Diff line number Diff line
@@ -3826,7 +3826,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
			else
				flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;

			intel_ring_begin(ring, 2);
			ret = intel_ring_begin(ring, 2);
			if (ret)
				goto err;

			intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask);
			intel_ring_emit(ring, MI_NOOP);
			intel_ring_advance(ring);
+7 −6
Original line number Diff line number Diff line
@@ -1101,12 +1101,13 @@ static int i915_emit_irq(struct drm_device * dev)
	if (master_priv->sarea_priv)
		master_priv->sarea_priv->last_enqueue = dev_priv->counter;

	BEGIN_LP_RING(4);
	if (BEGIN_LP_RING(4) == 0) {
		OUT_RING(MI_STORE_DWORD_INDEX);
		OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
		OUT_RING(dev_priv->counter);
		OUT_RING(MI_USER_INTERRUPT);
		ADVANCE_LP_RING();
	}

	return dev_priv->counter;
}
+29 −22
Original line number Diff line number Diff line
@@ -5090,22 +5090,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
	if (ret)
		goto cleanup_objs;

	/* Block clients from rendering to the new back buffer until
	 * the flip occurs and the object is no longer visible.
	 */
	atomic_add(1 << intel_crtc->plane,
		   &to_intel_bo(work->old_fb_obj)->pending_flip);

	work->pending_flip_obj = obj;
	obj_priv = to_intel_bo(obj);

	if (IS_GEN3(dev) || IS_GEN2(dev)) {
		u32 flip_mask;

		/* Can't queue multiple flips, so wait for the previous
		 * one to finish before executing the next.
		 */
		BEGIN_LP_RING(2);
		ret = BEGIN_LP_RING(2);
		if (ret)
			goto cleanup_objs;

		if (intel_crtc->plane)
			flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
		else
@@ -5115,12 +5109,24 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
		ADVANCE_LP_RING();
	}

	work->pending_flip_obj = obj;
	obj_priv = to_intel_bo(obj);

	work->enable_stall_check = true;

	/* Offset into the new buffer for cases of shared fbs between CRTCs */
	offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8;

	BEGIN_LP_RING(4);
	ret = BEGIN_LP_RING(4);
	if (ret)
		goto cleanup_objs;

	/* Block clients from rendering to the new back buffer until
	 * the flip occurs and the object is no longer visible.
	 */
	atomic_add(1 << intel_crtc->plane,
		   &to_intel_bo(work->old_fb_obj)->pending_flip);

	switch (INTEL_INFO(dev)->gen) {
	case 2:
		OUT_RING(MI_DISPLAY_FLIP |
@@ -5850,7 +5856,7 @@ void intel_init_clock_gating(struct drm_device *dev)
			struct drm_i915_gem_object *obj_priv;
			obj_priv = to_intel_bo(dev_priv->renderctx);
			if (obj_priv) {
				BEGIN_LP_RING(4);
				if (BEGIN_LP_RING(4) == 0) {
					OUT_RING(MI_SET_CONTEXT);
					OUT_RING(obj_priv->gtt_offset |
						 MI_MM_SPACE_GTT |
@@ -5861,6 +5867,7 @@ void intel_init_clock_gating(struct drm_device *dev)
					OUT_RING(MI_FLUSH);
					ADVANCE_LP_RING();
				}
			}
		} else
			DRM_DEBUG_KMS("Failed to allocate render context."
				       "Disable RC6\n");
Loading