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

Commit 8e1f80c0 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm-intel-fixes-2013-09-19' of...

Merge tag 'drm-intel-fixes-2013-09-19' of git://people.freedesktop.org/~danvet/drm-intel into drm-fixes

Some more dealock fixes around pageflips and gpu hangs, fixes for hsw hangs
when doing modesets/dpms. And a few minor things to rectify issues with our
modeset state tracking which the checker spotted.

* tag 'drm-intel-fixes-2013-09-19' of git://people.freedesktop.org/~danvet/drm-intel:
  drm/i915: Don't enable the cursor on a disable pipe
  drm/i915: do not update cursor in crtc mode set
  drm/i915: kill set_need_resched
  drm/i915/dvo: set crtc timings again for panel fixed modes
  drm/i915/sdvo: Robustify the dtd<->drm_mode conversions
  drm/i915/sdvo: Fully translate sync flags in the dtd->mode conversion
  drm/i915: Use proper print format for debug prints
  drm/i915: fix wait_for_pending_flips vs gpu hang deadlock
  drm/i915: Track pfit enable state separately from size
parents c21eb21c f2f5f771
Loading
Loading
Loading
Loading
+4 −7
Original line number Diff line number Diff line
@@ -1390,14 +1390,11 @@ out:
		if (i915_terminally_wedged(&dev_priv->gpu_error))
			return VM_FAULT_SIGBUS;
	case -EAGAIN:
		/* Give the error handler a chance to run and move the
		 * objects off the GPU active list. Next time we service the
		 * fault, we should be able to transition the page into the
		 * GTT without touching the GPU (and so avoid further
		 * EIO/EGAIN). If the GPU is wedged, then there is no issue
		 * with coherency, just lost writes.
		/*
		 * EAGAIN means the gpu is hung and we'll wait for the error
		 * handler to reset everything when re-faulting in
		 * i915_mutex_lock_interruptible.
		 */
		set_need_resched();
	case 0:
	case -ERESTARTSYS:
	case -EINTR:
+54 −14
Original line number Diff line number Diff line
@@ -1469,6 +1469,34 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
	return ret;
}

static void i915_error_wake_up(struct drm_i915_private *dev_priv,
			       bool reset_completed)
{
	struct intel_ring_buffer *ring;
	int i;

	/*
	 * Notify all waiters for GPU completion events that reset state has
	 * been changed, and that they need to restart their wait after
	 * checking for potential errors (and bail out to drop locks if there is
	 * a gpu reset pending so that i915_error_work_func can acquire them).
	 */

	/* Wake up __wait_seqno, potentially holding dev->struct_mutex. */
	for_each_ring(ring, dev_priv, i)
		wake_up_all(&ring->irq_queue);

	/* Wake up intel_crtc_wait_for_pending_flips, holding crtc->mutex. */
	wake_up_all(&dev_priv->pending_flip_queue);

	/*
	 * Signal tasks blocked in i915_gem_wait_for_error that the pending
	 * reset state is cleared.
	 */
	if (reset_completed)
		wake_up_all(&dev_priv->gpu_error.reset_queue);
}

/**
 * i915_error_work_func - do process context error handling work
 * @work: work struct
@@ -1483,11 +1511,10 @@ static void i915_error_work_func(struct work_struct *work)
	drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t,
						    gpu_error);
	struct drm_device *dev = dev_priv->dev;
	struct intel_ring_buffer *ring;
	char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
	char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
	char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
	int i, ret;
	int ret;

	kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);

@@ -1506,8 +1533,16 @@ static void i915_error_work_func(struct work_struct *work)
		kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE,
				   reset_event);

		/*
		 * All state reset _must_ be completed before we update the
		 * reset counter, for otherwise waiters might miss the reset
		 * pending state and not properly drop locks, resulting in
		 * deadlocks with the reset work.
		 */
		ret = i915_reset(dev);

		intel_display_handle_reset(dev);

		if (ret == 0) {
			/*
			 * After all the gem state is reset, increment the reset
@@ -1528,12 +1563,11 @@ static void i915_error_work_func(struct work_struct *work)
			atomic_set(&error->reset_counter, I915_WEDGED);
		}

		for_each_ring(ring, dev_priv, i)
			wake_up_all(&ring->irq_queue);

		intel_display_handle_reset(dev);

		wake_up_all(&dev_priv->gpu_error.reset_queue);
		/*
		 * Note: The wake_up also serves as a memory barrier so that
		 * waiters see the update value of the reset counter atomic_t.
		 */
		i915_error_wake_up(dev_priv, true);
	}
}

@@ -1642,8 +1676,6 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
void i915_handle_error(struct drm_device *dev, bool wedged)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_ring_buffer *ring;
	int i;

	i915_capture_error_state(dev);
	i915_report_and_clear_eir(dev);
@@ -1653,11 +1685,19 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
				&dev_priv->gpu_error.reset_counter);

		/*
		 * Wakeup waiting processes so that the reset work item
		 * doesn't deadlock trying to grab various locks.
		 * Wakeup waiting processes so that the reset work function
		 * i915_error_work_func doesn't deadlock trying to grab various
		 * locks. By bumping the reset counter first, the woken
		 * processes will see a reset in progress and back off,
		 * releasing their locks and then wait for the reset completion.
		 * We must do this for _all_ gpu waiters that might hold locks
		 * that the reset work needs to acquire.
		 *
		 * Note: The wake_up serves as the required memory barrier to
		 * ensure that the waiters see the updated value of the reset
		 * counter atomic_t.
		 */
		for_each_ring(ring, dev_priv, i)
			wake_up_all(&ring->irq_queue);
		i915_error_wake_up(dev_priv, false);
	}

	/*
+1 −1
Original line number Diff line number Diff line
@@ -778,7 +778,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
			/* Can only use the always-on power well for eDP when
			 * not using the panel fitter, and when not using motion
			  * blur mitigation (which we don't support). */
			if (intel_crtc->config.pch_pfit.size)
			if (intel_crtc->config.pch_pfit.enabled)
				temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
			else
				temp |= TRANS_DDI_EDP_INPUT_A_ON;
+20 −22
Original line number Diff line number Diff line
@@ -2249,7 +2249,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
		I915_WRITE(PIPESRC(intel_crtc->pipe),
			   ((crtc->mode.hdisplay - 1) << 16) |
			   (crtc->mode.vdisplay - 1));
		if (!intel_crtc->config.pch_pfit.size &&
		if (!intel_crtc->config.pch_pfit.enabled &&
		    (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
		     intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
			I915_WRITE(PF_CTL(intel_crtc->pipe), 0);
@@ -3203,7 +3203,7 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc)
	struct drm_i915_private *dev_priv = dev->dev_private;
	int pipe = crtc->pipe;

	if (crtc->config.pch_pfit.size) {
	if (crtc->config.pch_pfit.enabled) {
		/* Force use of hard-coded filter coefficients
		 * as some pre-programmed values are broken,
		 * e.g. x201.
@@ -3428,7 +3428,7 @@ static void ironlake_pfit_disable(struct intel_crtc *crtc)

	/* To avoid upsetting the power well on haswell only disable the pfit if
	 * it's in use. The hw state code will make sure we get this right. */
	if (crtc->config.pch_pfit.size) {
	if (crtc->config.pch_pfit.enabled) {
		I915_WRITE(PF_CTL(pipe), 0);
		I915_WRITE(PF_WIN_POS(pipe), 0);
		I915_WRITE(PF_WIN_SZ(pipe), 0);
@@ -4877,9 +4877,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
		return -EINVAL;
	}

	/* Ensure that the cursor is valid for the new mode before changing... */
	intel_crtc_update_cursor(crtc, true);

	if (is_lvds && dev_priv->lvds_downclock_avail) {
		/*
		 * Ensure we match the reduced clock's P to the target clock.
@@ -5768,9 +5765,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
		intel_crtc->config.dpll.p2 = clock.p2;
	}

	/* Ensure that the cursor is valid for the new mode before changing... */
	intel_crtc_update_cursor(crtc, true);

	/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
	if (intel_crtc->config.has_pch_encoder) {
		fp = i9xx_dpll_compute_fp(&intel_crtc->config.dpll);
@@ -5859,6 +5853,7 @@ static void ironlake_get_pfit_config(struct intel_crtc *crtc,
	tmp = I915_READ(PF_CTL(crtc->pipe));

	if (tmp & PF_ENABLE) {
		pipe_config->pch_pfit.enabled = true;
		pipe_config->pch_pfit.pos = I915_READ(PF_WIN_POS(crtc->pipe));
		pipe_config->pch_pfit.size = I915_READ(PF_WIN_SZ(crtc->pipe));

@@ -6236,7 +6231,7 @@ static void haswell_modeset_global_resources(struct drm_device *dev)
		if (!crtc->base.enabled)
			continue;

		if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.size ||
		if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.enabled ||
		    crtc->config.cpu_transcoder != TRANSCODER_EDP)
			enable = true;
	}
@@ -6259,9 +6254,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
	if (!intel_ddi_pll_mode_set(crtc))
		return -EINVAL;

	/* Ensure that the cursor is valid for the new mode before changing... */
	intel_crtc_update_cursor(crtc, true);

	if (intel_crtc->config.has_dp_encoder)
		intel_dp_set_m_n(intel_crtc);

@@ -6494,15 +6486,15 @@ static void haswell_write_eld(struct drm_connector *connector,

	/* Set ELD valid state */
	tmp = I915_READ(aud_cntrl_st2);
	DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%8x\n", tmp);
	DRM_DEBUG_DRIVER("HDMI audio: pin eld vld status=0x%08x\n", tmp);
	tmp |= (AUDIO_ELD_VALID_A << (pipe * 4));
	I915_WRITE(aud_cntrl_st2, tmp);
	tmp = I915_READ(aud_cntrl_st2);
	DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%8x\n", tmp);
	DRM_DEBUG_DRIVER("HDMI audio: eld vld status=0x%08x\n", tmp);

	/* Enable HDMI mode */
	tmp = I915_READ(aud_config);
	DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%8x\n", tmp);
	DRM_DEBUG_DRIVER("HDMI audio: audio conf: 0x%08x\n", tmp);
	/* clear N_programing_enable and N_value_index */
	tmp &= ~(AUD_CONFIG_N_VALUE_INDEX | AUD_CONFIG_N_PROG_ENABLE);
	I915_WRITE(aud_config, tmp);
@@ -6937,6 +6929,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
	intel_crtc->cursor_width = width;
	intel_crtc->cursor_height = height;

	if (intel_crtc->active)
		intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);

	return 0;
@@ -6956,6 +6949,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
	intel_crtc->cursor_x = x;
	intel_crtc->cursor_y = y;

	if (intel_crtc->active)
		intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);

	return 0;
@@ -8205,9 +8199,10 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
		      pipe_config->gmch_pfit.control,
		      pipe_config->gmch_pfit.pgm_ratios,
		      pipe_config->gmch_pfit.lvds_border_bits);
	DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x\n",
	DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x, %s\n",
		      pipe_config->pch_pfit.pos,
		      pipe_config->pch_pfit.size);
		      pipe_config->pch_pfit.size,
		      pipe_config->pch_pfit.enabled ? "enabled" : "disabled");
	DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled);
}

@@ -8603,8 +8598,11 @@ intel_pipe_config_compare(struct drm_device *dev,
	if (INTEL_INFO(dev)->gen < 4)
		PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios);
	PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits);
	PIPE_CONF_CHECK_I(pch_pfit.enabled);
	if (current_config->pch_pfit.enabled) {
		PIPE_CONF_CHECK_I(pch_pfit.pos);
		PIPE_CONF_CHECK_I(pch_pfit.size);
	}

	PIPE_CONF_CHECK_I(ips_enabled);

+1 −0
Original line number Diff line number Diff line
@@ -280,6 +280,7 @@ struct intel_crtc_config {
	struct {
		u32 pos;
		u32 size;
		bool enabled;
	} pch_pfit;

	/* FDI configuration, only valid if has_pch_encoder is set. */
Loading