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

Commit c470af0a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'drm-intel-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel:
  drm/i915: Rephrase pwrite bounds checking to avoid any potential overflow
  drm/i915: Sanity check pread/pwrite
  drm/i915: Use pipe state to tell when pipe is off
  drm/i915: vblank status not valid while training display port
  drivers/gpu/drm/i915/i915_gem.c: Add missing error handling code
  drm/i915: Fix refleak during eviction.
  drm/i915: fix GMCH power reporting
parents 4e31635c 7dcd2499
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -1787,9 +1787,9 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
		}
	}

	div_u64(diff, diff1);
	diff = div_u64(diff, diff1);
	ret = ((m * diff) + c);
	div_u64(ret, 10);
	ret = div_u64(ret, 10);

	dev_priv->last_count1 = total_count;
	dev_priv->last_time1 = now;
@@ -1858,7 +1858,7 @@ void i915_update_gfx_val(struct drm_i915_private *dev_priv)

	/* More magic constants... */
	diff = diff * 1181;
	div_u64(diff, diffms * 10);
	diff = div_u64(diff, diffms * 10);
	dev_priv->gfx_power = diff;
}

+26 −20
Original line number Diff line number Diff line
@@ -469,14 +469,17 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
		return -ENOENT;
	obj_priv = to_intel_bo(obj);

	/* Bounds check source.
	 *
	 * XXX: This could use review for overflow issues...
	 */
	if (args->offset > obj->size || args->size > obj->size ||
	    args->offset + args->size > obj->size) {
		drm_gem_object_unreference_unlocked(obj);
		return -EINVAL;
	/* Bounds check source.  */
	if (args->offset > obj->size || args->size > obj->size - args->offset) {
		ret = -EINVAL;
		goto err;
	}

	if (!access_ok(VERIFY_WRITE,
		       (char __user *)(uintptr_t)args->data_ptr,
		       args->size)) {
		ret = -EFAULT;
		goto err;
	}

	if (i915_gem_object_needs_bit17_swizzle(obj)) {
@@ -488,8 +491,8 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
							file_priv);
	}

err:
	drm_gem_object_unreference_unlocked(obj);

	return ret;
}

@@ -578,8 +581,6 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,

	user_data = (char __user *) (uintptr_t) args->data_ptr;
	remain = args->size;
	if (!access_ok(VERIFY_READ, user_data, remain))
		return -EFAULT;


	mutex_lock(&dev->struct_mutex);
@@ -932,14 +933,17 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
		return -ENOENT;
	obj_priv = to_intel_bo(obj);

	/* Bounds check destination.
	 *
	 * XXX: This could use review for overflow issues...
	 */
	if (args->offset > obj->size || args->size > obj->size ||
	    args->offset + args->size > obj->size) {
		drm_gem_object_unreference_unlocked(obj);
		return -EINVAL;
	/* Bounds check destination. */
	if (args->offset > obj->size || args->size > obj->size - args->offset) {
		ret = -EINVAL;
		goto err;
	}

	if (!access_ok(VERIFY_READ,
		       (char __user *)(uintptr_t)args->data_ptr,
		       args->size)) {
		ret = -EFAULT;
		goto err;
	}

	/* We can only do the GTT pwrite on untiled buffers, as otherwise
@@ -973,8 +977,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
		DRM_INFO("pwrite failed %d\n", ret);
#endif

err:
	drm_gem_object_unreference_unlocked(obj);

	return ret;
}

@@ -3256,6 +3260,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
				  (int) reloc->offset,
				  reloc->read_domains,
				  reloc->write_domain);
			drm_gem_object_unreference(target_obj);
			i915_gem_object_unpin(obj);
			return -EINVAL;
		}
		if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
+20 −25
Original line number Diff line number Diff line
@@ -93,7 +93,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	struct list_head eviction_list, unwind_list;
	struct drm_i915_gem_object *obj_priv, *tmp_obj_priv;
	struct drm_i915_gem_object *obj_priv;
	struct list_head *render_iter, *bsd_iter;
	int ret = 0;

@@ -175,39 +175,34 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen
	return -ENOSPC;

found:
	INIT_LIST_HEAD(&eviction_list);
	list_for_each_entry_safe(obj_priv, tmp_obj_priv,
				 &unwind_list, evict_list) {
		if (drm_mm_scan_remove_block(obj_priv->gtt_space)) {
	/* drm_mm doesn't allow any other other operations while
	 * scanning, therefore store to be evicted objects on a
	 * temporary list. */
	INIT_LIST_HEAD(&eviction_list);
	while (!list_empty(&unwind_list)) {
		obj_priv = list_first_entry(&unwind_list,
					    struct drm_i915_gem_object,
					    evict_list);
		if (drm_mm_scan_remove_block(obj_priv->gtt_space)) {
			list_move(&obj_priv->evict_list, &eviction_list);
		} else
			continue;
		}
		list_del(&obj_priv->evict_list);
		drm_gem_object_unreference(&obj_priv->base);
	}

	/* Unbinding will emit any required flushes */
	list_for_each_entry_safe(obj_priv, tmp_obj_priv,
				 &eviction_list, evict_list) {
#if WATCH_LRU
		DRM_INFO("%s: evicting %p\n", __func__, &obj_priv->base);
#endif
	while (!list_empty(&eviction_list)) {
		obj_priv = list_first_entry(&eviction_list,
					    struct drm_i915_gem_object,
					    evict_list);
		if (ret == 0)
			ret = i915_gem_object_unbind(&obj_priv->base);
		if (ret)
			return ret;

		list_del(&obj_priv->evict_list);
		drm_gem_object_unreference(&obj_priv->base);
	}

	/* The just created free hole should be on the top of the free stack
	 * maintained by drm_mm, so this BUG_ON actually executes in O(1).
	 * Furthermore all accessed data has just recently been used, so it
	 * should be really fast, too. */
	BUG_ON(!drm_mm_search_free(&dev_priv->mm.gtt_space, min_size,
				   alignment, 0));

	return 0;
	return ret;
}

int
+38 −24
Original line number Diff line number Diff line
@@ -1013,8 +1013,8 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
		DRM_DEBUG_KMS("vblank wait timed out\n");
}

/**
 * intel_wait_for_vblank_off - wait for vblank after disabling a pipe
/*
 * intel_wait_for_pipe_off - wait for pipe to turn off
 * @dev: drm device
 * @pipe: pipe to wait for
 *
@@ -1022,15 +1022,29 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
 * spinning on the vblank interrupt status bit, since we won't actually
 * see an interrupt when the pipe is disabled.
 *
 * So this function waits for the display line value to settle (it
 * usually ends up stopping at the start of the next frame).
 * On Gen4 and above:
 *   wait for the pipe register state bit to turn off
 *
 * Otherwise:
 *   wait for the display line value to settle (it usually
 *   ends up stopping at the start of the next frame).
 *  
 */
void intel_wait_for_vblank_off(struct drm_device *dev, int pipe)
static void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
{
	struct drm_i915_private *dev_priv = dev->dev_private;

	if (INTEL_INFO(dev)->gen >= 4) {
		int pipeconf_reg = (pipe == 0 ? PIPEACONF : PIPEBCONF);

		/* Wait for the Pipe State to go off */
		if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0,
			     100, 0))
			DRM_DEBUG_KMS("pipe_off wait timed out\n");
	} else {
		u32 last_line;
		int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL);
		unsigned long timeout = jiffies + msecs_to_jiffies(100);
	u32 last_line;

		/* Wait for the display line to settle */
		do {
@@ -1038,9 +1052,9 @@ void intel_wait_for_vblank_off(struct drm_device *dev, int pipe)
			mdelay(5);
		} while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) &&
			 time_after(timeout, jiffies));

		if (time_after(jiffies, timeout))
		DRM_DEBUG_KMS("vblank wait timed out\n");
			DRM_DEBUG_KMS("pipe_off wait timed out\n");
	}
}

/* Parameters have changed, update FBC info */
@@ -2328,13 +2342,13 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
			I915_READ(dspbase_reg);
		}

		/* Wait for vblank for the disable to take effect */
		intel_wait_for_vblank_off(dev, pipe);

		/* Don't disable pipe A or pipe A PLLs if needed */
		if (pipeconf_reg == PIPEACONF &&
		    (dev_priv->quirks & QUIRK_PIPEA_FORCE))
		    (dev_priv->quirks & QUIRK_PIPEA_FORCE)) {
			/* Wait for vblank for the disable to take effect */
			intel_wait_for_vblank(dev, pipe);
			goto skip_pipe_off;
		}

		/* Next, disable display pipes */
		temp = I915_READ(pipeconf_reg);
@@ -2343,8 +2357,8 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
			I915_READ(pipeconf_reg);
		}

		/* Wait for vblank for the disable to take effect. */
		intel_wait_for_vblank_off(dev, pipe);
		/* Wait for the pipe to turn off */
		intel_wait_for_pipe_off(dev, pipe);

		temp = I915_READ(dpll_reg);
		if ((temp & DPLL_VCO_ENABLE) != 0) {
+9 −10
Original line number Diff line number Diff line
@@ -1138,18 +1138,14 @@ static bool
intel_dp_set_link_train(struct intel_dp *intel_dp,
			uint32_t dp_reg_value,
			uint8_t dp_train_pat,
			uint8_t train_set[4],
			bool first)
			uint8_t train_set[4])
{
	struct drm_device *dev = intel_dp->base.enc.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc);
	int ret;

	I915_WRITE(intel_dp->output_reg, dp_reg_value);
	POSTING_READ(intel_dp->output_reg);
	if (first)
		intel_wait_for_vblank(dev, intel_crtc->pipe);

	intel_dp_aux_native_write_1(intel_dp,
				    DP_TRAINING_PATTERN_SET,
@@ -1174,10 +1170,15 @@ intel_dp_link_train(struct intel_dp *intel_dp)
	uint8_t voltage;
	bool clock_recovery = false;
	bool channel_eq = false;
	bool first = true;
	int tries;
	u32 reg;
	uint32_t DP = intel_dp->DP;
	struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc);

	/* Enable output, wait for it to become active */
	I915_WRITE(intel_dp->output_reg, intel_dp->DP);
	POSTING_READ(intel_dp->output_reg);
	intel_wait_for_vblank(dev, intel_crtc->pipe);

	/* Write the link configuration data */
	intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
@@ -1210,9 +1211,8 @@ intel_dp_link_train(struct intel_dp *intel_dp)
			reg = DP | DP_LINK_TRAIN_PAT_1;

		if (!intel_dp_set_link_train(intel_dp, reg,
					     DP_TRAINING_PATTERN_1, train_set, first))
					     DP_TRAINING_PATTERN_1, train_set))
			break;
		first = false;
		/* Set training pattern 1 */

		udelay(100);
@@ -1266,8 +1266,7 @@ intel_dp_link_train(struct intel_dp *intel_dp)

		/* channel eq pattern */
		if (!intel_dp_set_link_train(intel_dp, reg,
					     DP_TRAINING_PATTERN_2, train_set,
					     false))
					     DP_TRAINING_PATTERN_2, train_set))
			break;

		udelay(400);
Loading