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

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

drm/i915/overlay: Use a continuation hook to finish work after a flip.



Slightly easier to follow than the state machine and now possible as the
control structure is opaque and hw_wedged is no longer interferred with.

Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 23f09ce3
Loading
Loading
Loading
Loading
+44 −66
Original line number Original line Diff line number Diff line
@@ -186,11 +186,7 @@ struct intel_overlay {
	struct drm_i915_gem_object *reg_bo;
	struct drm_i915_gem_object *reg_bo;
	/* flip handling */
	/* flip handling */
	uint32_t last_flip_req;
	uint32_t last_flip_req;
	int hw_wedged;
	void (*flip_tail)(struct intel_overlay *);
#define HW_WEDGED		1
#define NEEDS_WAIT_FOR_FLIP	2
#define RELEASE_OLD_VID		3
#define SWITCH_OFF		4
};
};


static struct overlay_registers *
static struct overlay_registers *
@@ -243,25 +239,25 @@ static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
					 struct drm_i915_gem_request *request,
					 struct drm_i915_gem_request *request,
					 bool interruptible,
					 bool interruptible,
					 int stage)
					 void (*tail)(struct intel_overlay *))
{
{
	struct drm_device *dev = overlay->dev;
	struct drm_device *dev = overlay->dev;
	drm_i915_private_t *dev_priv = dev->dev_private;
	drm_i915_private_t *dev_priv = dev->dev_private;
	int ret;
	int ret;


	BUG_ON(overlay->last_flip_req);
	overlay->last_flip_req =
	overlay->last_flip_req =
		i915_add_request(dev, NULL, request, &dev_priv->render_ring);
		i915_add_request(dev, NULL, request, &dev_priv->render_ring);
	if (overlay->last_flip_req == 0)
	if (overlay->last_flip_req == 0)
		return -ENOMEM;
		return -ENOMEM;


	overlay->hw_wedged = stage;
	overlay->flip_tail = tail;
	ret = i915_do_wait_request(dev,
	ret = i915_do_wait_request(dev,
				   overlay->last_flip_req, true,
				   overlay->last_flip_req, true,
				   &dev_priv->render_ring);
				   &dev_priv->render_ring);
	if (ret)
	if (ret)
		return ret;
		return ret;


	overlay->hw_wedged = 0;
	overlay->last_flip_req = 0;
	overlay->last_flip_req = 0;
	return 0;
	return 0;
}
}
@@ -344,8 +340,7 @@ static int intel_overlay_on(struct intel_overlay *overlay)
	OUT_RING(MI_NOOP);
	OUT_RING(MI_NOOP);
	ADVANCE_LP_RING();
	ADVANCE_LP_RING();


	ret = intel_overlay_do_wait_request(overlay, request, true,
	ret = intel_overlay_do_wait_request(overlay, request, true, NULL);
					    NEEDS_WAIT_FOR_FLIP);
out:
out:
	if (pipe_a_quirk)
	if (pipe_a_quirk)
		i830_deactivate_pipe_a(dev);
		i830_deactivate_pipe_a(dev);
@@ -387,6 +382,33 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
	return 0;
	return 0;
}
}


static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
{
	struct drm_gem_object *obj = &overlay->old_vid_bo->base;

	i915_gem_object_unpin(obj);
	drm_gem_object_unreference(obj);

	overlay->old_vid_bo = NULL;
}

static void intel_overlay_off_tail(struct intel_overlay *overlay)
{
	struct drm_gem_object *obj;

	/* never have the overlay hw on without showing a frame */
	BUG_ON(!overlay->vid_bo);
	obj = &overlay->vid_bo->base;

	i915_gem_object_unpin(obj);
	drm_gem_object_unreference(obj);
	overlay->vid_bo = NULL;

	overlay->crtc->overlay = NULL;
	overlay->crtc = NULL;
	overlay->active = 0;
}

/* overlay needs to be disabled in OCMD reg */
/* overlay needs to be disabled in OCMD reg */
static int intel_overlay_off(struct intel_overlay *overlay,
static int intel_overlay_off(struct intel_overlay *overlay,
			     bool interruptible)
			     bool interruptible)
@@ -419,34 +441,7 @@ static int intel_overlay_off(struct intel_overlay *overlay,
	ADVANCE_LP_RING();
	ADVANCE_LP_RING();


	return intel_overlay_do_wait_request(overlay, request, interruptible,
	return intel_overlay_do_wait_request(overlay, request, interruptible,
					     SWITCH_OFF);
					     intel_overlay_off_tail);
}

static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
{
	struct drm_gem_object *obj = &overlay->old_vid_bo->base;

	i915_gem_object_unpin(obj);
	drm_gem_object_unreference(obj);

	overlay->old_vid_bo = NULL;
}

static void intel_overlay_off_tail(struct intel_overlay *overlay)
{
	struct drm_gem_object *obj;

	/* never have the overlay hw on without showing a frame */
	BUG_ON(!overlay->vid_bo);
	obj = &overlay->vid_bo->base;

	i915_gem_object_unpin(obj);
	drm_gem_object_unreference(obj);
	overlay->vid_bo = NULL;

	overlay->crtc->overlay = NULL;
	overlay->crtc = NULL;
	overlay->active = 0;
}
}


/* recover from an interruption due to a signal
/* recover from an interruption due to a signal
@@ -458,28 +453,17 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
	drm_i915_private_t *dev_priv = dev->dev_private;
	drm_i915_private_t *dev_priv = dev->dev_private;
	int ret;
	int ret;


	if (overlay->hw_wedged == HW_WEDGED)
	if (overlay->last_flip_req == 0)
		return -EIO;
		return 0;


	ret = i915_do_wait_request(dev, overlay->last_flip_req,
	ret = i915_do_wait_request(dev, overlay->last_flip_req,
				   interruptible, &dev_priv->render_ring);
				   interruptible, &dev_priv->render_ring);
	if (ret)
	if (ret)
		return ret;
		return ret;


	switch (overlay->hw_wedged) {
	if (overlay->flip_tail)
	case RELEASE_OLD_VID:
		overlay->flip_tail(overlay);
		intel_overlay_release_old_vid_tail(overlay);
		break;


	case SWITCH_OFF:
		intel_overlay_off_tail(overlay);
		break;

	default:
		BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP);
	}

	overlay->hw_wedged = 0;
	overlay->last_flip_req = 0;
	overlay->last_flip_req = 0;
	return 0;
	return 0;
}
}
@@ -514,7 +498,7 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
		ADVANCE_LP_RING();
		ADVANCE_LP_RING();


		ret = intel_overlay_do_wait_request(overlay, request, true,
		ret = intel_overlay_do_wait_request(overlay, request, true,
						    RELEASE_OLD_VID);
						    intel_overlay_release_old_vid_tail);
		if (ret)
		if (ret)
			return ret;
			return ret;
	}
	}
@@ -889,12 +873,9 @@ int intel_overlay_switch_off(struct intel_overlay *overlay,
	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
	BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
	BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));


	if (overlay->hw_wedged) {
	ret = intel_overlay_recover_from_interrupt(overlay, interruptible);
		ret = intel_overlay_recover_from_interrupt(overlay,
							   interruptible);
	if (ret != 0)
	if (ret != 0)
		return ret;
		return ret;
	}


	if (!overlay->active)
	if (!overlay->active)
		return 0;
		return 0;
@@ -912,7 +893,6 @@ int intel_overlay_switch_off(struct intel_overlay *overlay,
		return ret;
		return ret;


	intel_overlay_off_tail(overlay);
	intel_overlay_off_tail(overlay);

	return 0;
	return 0;
}
}


@@ -1153,11 +1133,9 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
	mutex_lock(&dev->mode_config.mutex);
	mutex_lock(&dev->mode_config.mutex);
	mutex_lock(&dev->struct_mutex);
	mutex_lock(&dev->struct_mutex);


	if (overlay->hw_wedged) {
	ret = intel_overlay_recover_from_interrupt(overlay, true);
		ret = intel_overlay_recover_from_interrupt(overlay, 1);
	if (ret != 0)
	if (ret != 0)
		goto out_unlock;
		goto out_unlock;
	}


	if (overlay->crtc != crtc) {
	if (overlay->crtc != crtc) {
		struct drm_display_mode *mode = &crtc->base.mode;
		struct drm_display_mode *mode = &crtc->base.mode;