Commit c470af0a authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'drm-intel-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel

* '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
...@@ -1787,9 +1787,9 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) ...@@ -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); ret = ((m * diff) + c);
div_u64(ret, 10); ret = div_u64(ret, 10);
dev_priv->last_count1 = total_count; dev_priv->last_count1 = total_count;
dev_priv->last_time1 = now; dev_priv->last_time1 = now;
...@@ -1858,7 +1858,7 @@ void i915_update_gfx_val(struct drm_i915_private *dev_priv) ...@@ -1858,7 +1858,7 @@ void i915_update_gfx_val(struct drm_i915_private *dev_priv)
/* More magic constants... */ /* More magic constants... */
diff = diff * 1181; diff = diff * 1181;
div_u64(diff, diffms * 10); diff = div_u64(diff, diffms * 10);
dev_priv->gfx_power = diff; dev_priv->gfx_power = diff;
} }
......
...@@ -469,14 +469,17 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, ...@@ -469,14 +469,17 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
return -ENOENT; return -ENOENT;
obj_priv = to_intel_bo(obj); obj_priv = to_intel_bo(obj);
/* Bounds check source. /* Bounds check source. */
* if (args->offset > obj->size || args->size > obj->size - args->offset) {
* XXX: This could use review for overflow issues... ret = -EINVAL;
*/ goto err;
if (args->offset > obj->size || args->size > obj->size || }
args->offset + args->size > obj->size) {
drm_gem_object_unreference_unlocked(obj); if (!access_ok(VERIFY_WRITE,
return -EINVAL; (char __user *)(uintptr_t)args->data_ptr,
args->size)) {
ret = -EFAULT;
goto err;
} }
if (i915_gem_object_needs_bit17_swizzle(obj)) { if (i915_gem_object_needs_bit17_swizzle(obj)) {
...@@ -488,8 +491,8 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, ...@@ -488,8 +491,8 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
file_priv); file_priv);
} }
err:
drm_gem_object_unreference_unlocked(obj); drm_gem_object_unreference_unlocked(obj);
return ret; return ret;
} }
...@@ -578,8 +581,6 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, ...@@ -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; user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size; remain = args->size;
if (!access_ok(VERIFY_READ, user_data, remain))
return -EFAULT;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
...@@ -932,14 +933,17 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, ...@@ -932,14 +933,17 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
return -ENOENT; return -ENOENT;
obj_priv = to_intel_bo(obj); obj_priv = to_intel_bo(obj);
/* Bounds check destination. /* Bounds check destination. */
* if (args->offset > obj->size || args->size > obj->size - args->offset) {
* XXX: This could use review for overflow issues... ret = -EINVAL;
*/ goto err;
if (args->offset > obj->size || args->size > obj->size || }
args->offset + args->size > obj->size) {
drm_gem_object_unreference_unlocked(obj); if (!access_ok(VERIFY_READ,
return -EINVAL; (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 /* 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, ...@@ -973,8 +977,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
DRM_INFO("pwrite failed %d\n", ret); DRM_INFO("pwrite failed %d\n", ret);
#endif #endif
err:
drm_gem_object_unreference_unlocked(obj); drm_gem_object_unreference_unlocked(obj);
return ret; return ret;
} }
...@@ -3256,6 +3260,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, ...@@ -3256,6 +3260,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
(int) reloc->offset, (int) reloc->offset,
reloc->read_domains, reloc->read_domains,
reloc->write_domain); reloc->write_domain);
drm_gem_object_unreference(target_obj);
i915_gem_object_unpin(obj);
return -EINVAL; return -EINVAL;
} }
if (reloc->write_domain & I915_GEM_DOMAIN_CPU || if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
......
...@@ -93,7 +93,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen ...@@ -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; drm_i915_private_t *dev_priv = dev->dev_private;
struct list_head eviction_list, unwind_list; 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; struct list_head *render_iter, *bsd_iter;
int ret = 0; int ret = 0;
...@@ -175,39 +175,34 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen ...@@ -175,39 +175,34 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen
return -ENOSPC; return -ENOSPC;
found: found:
/* 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); INIT_LIST_HEAD(&eviction_list);
list_for_each_entry_safe(obj_priv, tmp_obj_priv, while (!list_empty(&unwind_list)) {
&unwind_list, evict_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)) { 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. */
list_move(&obj_priv->evict_list, &eviction_list); list_move(&obj_priv->evict_list, &eviction_list);
} else continue;
drm_gem_object_unreference(&obj_priv->base); }
list_del(&obj_priv->evict_list);
drm_gem_object_unreference(&obj_priv->base);
} }
/* Unbinding will emit any required flushes */ /* Unbinding will emit any required flushes */
list_for_each_entry_safe(obj_priv, tmp_obj_priv, while (!list_empty(&eviction_list)) {
&eviction_list, evict_list) { obj_priv = list_first_entry(&eviction_list,
#if WATCH_LRU struct drm_i915_gem_object,
DRM_INFO("%s: evicting %p\n", __func__, &obj_priv->base); evict_list);
#endif if (ret == 0)
ret = i915_gem_object_unbind(&obj_priv->base); ret = i915_gem_object_unbind(&obj_priv->base);
if (ret) list_del(&obj_priv->evict_list);
return ret;
drm_gem_object_unreference(&obj_priv->base); drm_gem_object_unreference(&obj_priv->base);
} }
/* The just created free hole should be on the top of the free stack return ret;
* 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;
} }
int int
......
...@@ -1013,8 +1013,8 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe) ...@@ -1013,8 +1013,8 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
DRM_DEBUG_KMS("vblank wait timed out\n"); 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 * @dev: drm device
* @pipe: pipe to wait for * @pipe: pipe to wait for
* *
...@@ -1022,25 +1022,39 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe) ...@@ -1022,25 +1022,39 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
* spinning on the vblank interrupt status bit, since we won't actually * spinning on the vblank interrupt status bit, since we won't actually
* see an interrupt when the pipe is disabled. * see an interrupt when the pipe is disabled.
* *
* So this function waits for the display line value to settle (it * On Gen4 and above:
* usually ends up stopping at the start of the next frame). * 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; struct drm_i915_private *dev_priv = dev->dev_private;
int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL);
unsigned long timeout = jiffies + msecs_to_jiffies(100); if (INTEL_INFO(dev)->gen >= 4) {
u32 last_line; int pipeconf_reg = (pipe == 0 ? PIPEACONF : PIPEBCONF);
/* Wait for the display line to settle */ /* Wait for the Pipe State to go off */
do { if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0,
last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK; 100, 0))
mdelay(5); DRM_DEBUG_KMS("pipe_off wait timed out\n");
} while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) && } else {
time_after(timeout, jiffies)); u32 last_line;
int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL);
if (time_after(jiffies, timeout)) unsigned long timeout = jiffies + msecs_to_jiffies(100);
DRM_DEBUG_KMS("vblank wait timed out\n");
/* Wait for the display line to settle */
do {
last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK;
mdelay(5);
} while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) &&
time_after(timeout, jiffies));
if (time_after(jiffies, timeout))
DRM_DEBUG_KMS("pipe_off wait timed out\n");
}
} }
/* Parameters have changed, update FBC info */ /* Parameters have changed, update FBC info */
...@@ -2328,13 +2342,13 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) ...@@ -2328,13 +2342,13 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
I915_READ(dspbase_reg); 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 */ /* Don't disable pipe A or pipe A PLLs if needed */
if (pipeconf_reg == PIPEACONF && 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; goto skip_pipe_off;
}
/* Next, disable display pipes */ /* Next, disable display pipes */
temp = I915_READ(pipeconf_reg); temp = I915_READ(pipeconf_reg);
...@@ -2343,8 +2357,8 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) ...@@ -2343,8 +2357,8 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
I915_READ(pipeconf_reg); I915_READ(pipeconf_reg);
} }
/* Wait for vblank for the disable to take effect. */ /* Wait for the pipe to turn off */
intel_wait_for_vblank_off(dev, pipe); intel_wait_for_pipe_off(dev, pipe);
temp = I915_READ(dpll_reg); temp = I915_READ(dpll_reg);
if ((temp & DPLL_VCO_ENABLE) != 0) { if ((temp & DPLL_VCO_ENABLE) != 0) {
......
...@@ -1138,18 +1138,14 @@ static bool ...@@ -1138,18 +1138,14 @@ static bool
intel_dp_set_link_train(struct intel_dp *intel_dp, intel_dp_set_link_train(struct intel_dp *intel_dp,
uint32_t dp_reg_value, uint32_t dp_reg_value,
uint8_t dp_train_pat, uint8_t dp_train_pat,
uint8_t train_set[4], uint8_t train_set[4])
bool first)
{ {
struct drm_device *dev = intel_dp->base.enc.dev; struct drm_device *dev = intel_dp->base.enc.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc);
int ret; int ret;
I915_WRITE(intel_dp->output_reg, dp_reg_value); I915_WRITE(intel_dp->output_reg, dp_reg_value);
POSTING_READ(intel_dp->output_reg); POSTING_READ(intel_dp->output_reg);
if (first)
intel_wait_for_vblank(dev, intel_crtc->pipe);
intel_dp_aux_native_write_1(intel_dp, intel_dp_aux_native_write_1(intel_dp,
DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_SET,
...@@ -1174,10 +1170,15 @@ intel_dp_link_train(struct intel_dp *intel_dp) ...@@ -1174,10 +1170,15 @@ intel_dp_link_train(struct intel_dp *intel_dp)
uint8_t voltage; uint8_t voltage;
bool clock_recovery = false; bool clock_recovery = false;
bool channel_eq = false; bool channel_eq = false;
bool first = true;
int tries; int tries;
u32 reg; u32 reg;
uint32_t DP = intel_dp->DP; 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 */ /* Write the link configuration data */
intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
...@@ -1210,9 +1211,8 @@ intel_dp_link_train(struct intel_dp *intel_dp) ...@@ -1210,9 +1211,8 @@ intel_dp_link_train(struct intel_dp *intel_dp)
reg = DP | DP_LINK_TRAIN_PAT_1; reg = DP | DP_LINK_TRAIN_PAT_1;
if (!intel_dp_set_link_train(intel_dp, reg, if (!intel_dp_set_link_train(intel_dp, reg,
DP_TRAINING_PATTERN_1, train_set, first)) DP_TRAINING_PATTERN_1, train_set))
break; break;
first = false;
/* Set training pattern 1 */ /* Set training pattern 1 */
udelay(100); udelay(100);
...@@ -1266,8 +1266,7 @@ intel_dp_link_train(struct intel_dp *intel_dp) ...@@ -1266,8 +1266,7 @@ intel_dp_link_train(struct intel_dp *intel_dp)
/* channel eq pattern */ /* channel eq pattern */
if (!intel_dp_set_link_train(intel_dp, reg, if (!intel_dp_set_link_train(intel_dp, reg,
DP_TRAINING_PATTERN_2, train_set, DP_TRAINING_PATTERN_2, train_set))
false))
break; break;
udelay(400); udelay(400);
......
...@@ -229,7 +229,6 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, ...@@ -229,7 +229,6 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
struct drm_crtc *crtc); struct drm_crtc *crtc);
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
extern void intel_wait_for_vblank_off(struct drm_device *dev, int pipe);
extern void intel_wait_for_vblank(struct drm_device *dev, int pipe); extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment