aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2014-01-20 05:17:36 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-01-22 04:34:40 -0500
commit5dce5b9387a06eb9301fa1cede07922a5a4d7a29 (patch)
treed09048bfeb1c2a6fe73f3822482eda4da2d620ae /drivers/gpu
parent2e82a7203182d0883d0f9450d40ad6e1c6578ad9 (diff)
drm/i915: Wait for completion of pending flips when starved of fences
On older generations (gen2, gen3) the GPU requires fences for many operations, such as blits. The display hardware also requires fences for scanouts and this leads to a situation where an arbitrary number of fences may be pinned by old scanouts following a pageflip but before we have executed the unpin workqueue. This is unpredictable by userspace and leads to random EDEADLK when submitting an otherwise benign execbuffer. However, we can detect when we have an outstanding flip and so cause userspace to wait upon their completion before finally declaring that the system is starved of fences. This is really no worse than forcing the GPU to stall waiting for older execbuffer to retire and release their fences before we can reallocate them for the next execbuffer. v2: move the test for a pending fb unpin to a common routine for later reuse during eviction Reported-and-tested-by: dimon@gmx.net Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=73696 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Jon Bloomfield <jon.bloomfield@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c13
-rw-r--r--drivers/gpu/drm/i915/intel_display.c24
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h1
3 files changed, 34 insertions, 4 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 4461336205ed..00c836154725 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3106,7 +3106,7 @@ i915_find_fence_reg(struct drm_device *dev)
3106 } 3106 }
3107 3107
3108 if (avail == NULL) 3108 if (avail == NULL)
3109 return NULL; 3109 goto deadlock;
3110 3110
3111 /* None available, try to steal one or wait for a user to finish */ 3111 /* None available, try to steal one or wait for a user to finish */
3112 list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) { 3112 list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) {
@@ -3116,7 +3116,12 @@ i915_find_fence_reg(struct drm_device *dev)
3116 return reg; 3116 return reg;
3117 } 3117 }
3118 3118
3119 return NULL; 3119deadlock:
3120 /* Wait for completion of pending flips which consume fences */
3121 if (intel_has_pending_fb_unpin(dev))
3122 return ERR_PTR(-EAGAIN);
3123
3124 return ERR_PTR(-EDEADLK);
3120} 3125}
3121 3126
3122/** 3127/**
@@ -3161,8 +3166,8 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
3161 } 3166 }
3162 } else if (enable) { 3167 } else if (enable) {
3163 reg = i915_find_fence_reg(dev); 3168 reg = i915_find_fence_reg(dev);
3164 if (reg == NULL) 3169 if (IS_ERR(reg))
3165 return -EDEADLK; 3170 return PTR_ERR(reg);
3166 3171
3167 if (reg->obj) { 3172 if (reg->obj) {
3168 struct drm_i915_gem_object *old = reg->obj; 3173 struct drm_i915_gem_object *old = reg->obj;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 14b024becb91..98371eeac77c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2982,6 +2982,30 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
2982 return pending; 2982 return pending;
2983} 2983}
2984 2984
2985bool intel_has_pending_fb_unpin(struct drm_device *dev)
2986{
2987 struct intel_crtc *crtc;
2988
2989 /* Note that we don't need to be called with mode_config.lock here
2990 * as our list of CRTC objects is static for the lifetime of the
2991 * device and so cannot disappear as we iterate. Similarly, we can
2992 * happily treat the predicates as racy, atomic checks as userspace
2993 * cannot claim and pin a new fb without at least acquring the
2994 * struct_mutex and so serialising with us.
2995 */
2996 list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
2997 if (atomic_read(&crtc->unpin_work_count) == 0)
2998 continue;
2999
3000 if (crtc->unpin_work)
3001 intel_wait_for_vblank(dev, crtc->pipe);
3002
3003 return true;
3004 }
3005
3006 return false;
3007}
3008
2985static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) 3009static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
2986{ 3010{
2987 struct drm_device *dev = crtc->dev; 3011 struct drm_device *dev = crtc->dev;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8754db9e3d52..fbfaaba5cc3b 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -626,6 +626,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
626 626
627/* intel_display.c */ 627/* intel_display.c */
628const char *intel_output_name(int output); 628const char *intel_output_name(int output);
629bool intel_has_pending_fb_unpin(struct drm_device *dev);
629int intel_pch_rawclk(struct drm_device *dev); 630int intel_pch_rawclk(struct drm_device *dev);
630void intel_mark_busy(struct drm_device *dev); 631void intel_mark_busy(struct drm_device *dev);
631void intel_mark_fb_busy(struct drm_i915_gem_object *obj, 632void intel_mark_fb_busy(struct drm_i915_gem_object *obj,