[PATCH] drm/i915: Fix the frame buffer fence starvation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Currently a tiled frame buffer to be scanned out is always installed
with a fence, leading to fence starvation on gen9lp virtualization
use case where graphics stacks of service and guest OSes compete for
fences.

By design, this fence is always needed by i965-(GEN4-) platforms.
For GEN4 and above, the fence is only required when the frame buffer
compression is enabled.

Changes are made to follow graphics hardware design principles.

Signed-off-by: Guang Bai <guang.bai@xxxxxxxxx>
---
 drivers/gpu/drm/i915/intel_display.c | 44 +++++++++++++++++++++++++++---------
 drivers/gpu/drm/i915/intel_drv.h     |  4 +++-
 drivers/gpu/drm/i915/intel_fbc.c     |  2 +-
 drivers/gpu/drm/i915/intel_fbdev.c   |  3 ++-
 4 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 3dbf5ed..59004f5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2068,7 +2068,8 @@ static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
 }
 
 struct i915_vma *
-intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
+intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation,
+			struct drm_plane *plane, enum pipe pipe)
 {
 	struct drm_device *dev = fb->dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
@@ -2076,6 +2077,8 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
 	struct i915_ggtt_view view;
 	struct i915_vma *vma;
 	u32 alignment;
+	bool needs_fence = false;
+	struct intel_plane *intel_plane;
 
 	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
@@ -2105,13 +2108,19 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
 	vma = i915_gem_object_pin_to_display_plane(obj, alignment, &view);
 	if (IS_ERR(vma))
 		goto err;
+	/*
+	 * Install the fence for pre-i965(GEN4-) tiled frame buffers all the
+	 * time but only do it for i965(GEN4) and beyond when the frame buffer
+	 * compression is enabled during boot up or runtime.
+	 */
+	intel_plane = to_intel_plane(plane);
+	if (INTEL_GEN(dev_priv) < 4 || (intel_fbc_can_enable(dev_priv) &&
+		(pipe == PIPE_A) && intel_plane &&
+		(intel_plane->id == PLANE_PRIMARY)))
+		needs_fence = true;
 
 	if (i915_vma_is_map_and_fenceable(vma)) {
-		/* Install a fence for tiled scan-out. Pre-i965 always needs a
-		 * fence, whereas 965+ only requires a fence if using
-		 * framebuffer compression.  For simplicity, we always, when
-		 * possible, install a fence as the cost is not that onerous.
-		 *
+		/*
 		 * If we fail to fence the tiled scanout, then either the
 		 * modeset will reject the change (which is highly unlikely as
 		 * the affected systems, all but one, do not have unmappable
@@ -2123,7 +2132,16 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
 		 * something and try to run the system in a "less than optimal"
 		 * mode that matches the user configuration.
 		 */
-		i915_vma_pin_fence(vma);
+		if (needs_fence)
+			i915_vma_pin_fence(vma);
+		else if (vma->fence)
+			/*
+			 * For a reused fence, increase its ref count even if
+			 * it's not pinned to maintain the count consistancy.
+			 * This is because the count is unconditionally 
+			 * decreased when the fence is unpinned.
+			 */
+			vma->fence->pin_count++;
 	}
 
 	i915_vma_get(vma);
@@ -2808,7 +2826,8 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
 valid_fb:
 	mutex_lock(&dev->struct_mutex);
 	intel_state->vma =
-		intel_pin_and_fence_fb_obj(fb, primary->state->rotation);
+		intel_pin_and_fence_fb_obj(fb, primary->state->rotation,
+					primary, intel_crtc->pipe);
 	mutex_unlock(&dev->struct_mutex);
 	if (IS_ERR(intel_state->vma)) {
 		DRM_ERROR("failed to pin boot fb on pipe %d: %li\n",
@@ -12711,8 +12730,9 @@ intel_prepare_plane_fb(struct drm_plane *plane,
 		ret = i915_gem_object_attach_phys(obj, align);
 	} else {
 		struct i915_vma *vma;
-
-		vma = intel_pin_and_fence_fb_obj(fb, new_state->rotation);
+		struct intel_crtc *temp_crtc = to_intel_crtc(new_state->crtc);
+		vma = intel_pin_and_fence_fb_obj(fb, new_state->rotation,
+						plane, temp_crtc->pipe);
 		if (!IS_ERR(vma))
 			to_intel_plane_state(new_state)->vma = vma;
 		else
@@ -13128,7 +13148,9 @@ intel_legacy_cursor_update(struct drm_plane *plane,
 			goto out_unlock;
 		}
 	} else {
-		vma = intel_pin_and_fence_fb_obj(fb, new_plane_state->rotation);
+		struct intel_crtc *temp_crtc = to_intel_crtc(crtc);
+		vma = intel_pin_and_fence_fb_obj(fb, new_plane_state->rotation,
+						plane, temp_crtc->pipe);
 		if (IS_ERR(vma)) {
 			DRM_DEBUG_KMS("failed to pin object\n");
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 898064e..7d98e069 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1503,7 +1503,8 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
 				    struct intel_load_detect_pipe *old,
 				    struct drm_modeset_acquire_ctx *ctx);
 struct i915_vma *
-intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation);
+intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation,
+			   struct drm_plane *plane, enum pipe pipe);
 void intel_unpin_fb_vma(struct i915_vma *vma);
 struct drm_framebuffer *
 intel_framebuffer_create(struct drm_i915_gem_object *obj,
@@ -1759,6 +1760,7 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv,
 		     unsigned int frontbuffer_bits, enum fb_op_origin origin);
 void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv);
 void intel_fbc_handle_fifo_underrun_irq(struct drm_i915_private *dev_priv);
+bool intel_fbc_can_enable(struct drm_i915_private *dev_priv);
 
 /* intel_hdmi.c */
 void intel_hdmi_init(struct drm_i915_private *dev_priv, i915_reg_t hdmi_reg,
diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
index d7d1ac7..6c9d704 100644
--- a/drivers/gpu/drm/i915/intel_fbc.c
+++ b/drivers/gpu/drm/i915/intel_fbc.c
@@ -862,7 +862,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
 	return true;
 }
 
-static bool intel_fbc_can_enable(struct drm_i915_private *dev_priv)
+bool intel_fbc_can_enable(struct drm_i915_private *dev_priv)
 {
 	struct intel_fbc *fbc = &dev_priv->fbc;
 
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index da48af1..ef04c7e 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -211,7 +211,8 @@ static int intelfb_create(struct drm_fb_helper *helper,
 	 * This also validates that any existing fb inherited from the
 	 * BIOS is suitable for own access.
 	 */
-	vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base, DRM_MODE_ROTATE_0);
+	vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base, DRM_MODE_ROTATE_0,
+					 NULL, INVALID_PIPE);
 	if (IS_ERR(vma)) {
 		ret = PTR_ERR(vma);
 		goto out_unlock;
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/intel-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux