From 21556350ade3cb5d7afecc8b3544e56431d21695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 14 Nov 2018 19:34:40 +0200 Subject: [PATCH 1/5] drm/i915: Disable LP3 watermarks on all SNB machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I have a Thinkpad X220 Tablet in my hands that is losing vblank interrupts whenever LP3 watermarks are used. If I nudge the latency value written to the WM3 register just by one in either direction the problem disappears. That to me suggests that the punit will not enter the corrsponding powersave mode (MPLL shutdown IIRC) unless the latency value in the register matches exactly what we read from SSKPD. Ie. it's not really a latency value but rather just a cookie by which the punit can identify the desired power saving state. On HSW/BDW this was changed such that we actually just write the WM level number into those bits, which makes much more sense given the observed behaviour. We could try to handle this by disallowing LP3 watermarks only when vblank interrupts are enabled but we'd first have to prove that only vblank interrupts are affected, which seems unlikely. Also we can't grab the wm mutex from the vblank enable/disable hooks because those are called with various spinlocks held. Thus we'd have to redesigne the watermark locking. So to play it safe and keep the code simple we simply disable LP3 watermarks on all SNB machines. To do that we simply zero out the latency values for watermark level 3, and we adjust the watermark computation to check for that. The behaviour now matches that of the g4x/vlv/skl wm code in the presence of a zeroed latency value. v2: s/USHRT_MAX/U32_MAX/ for consistency with the types (Chris) Cc: stable@vger.kernel.org Cc: Chris Wilson Acked-by: Chris Wilson Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101269 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103713 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20181114173440.6730-1-ville.syrjala@linux.intel.com (cherry picked from commit 03981c6ebec4fc7056b9b45f847393aeac90d060) Signed-off-by: Joonas Lahtinen --- drivers/gpu/drm/i915/intel_pm.c | 41 ++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 245f0022bcfd..3fe358db1276 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2493,6 +2493,9 @@ static uint32_t ilk_compute_pri_wm(const struct intel_crtc_state *cstate, uint32_t method1, method2; int cpp; + if (mem_value == 0) + return U32_MAX; + if (!intel_wm_plane_visible(cstate, pstate)) return 0; @@ -2522,6 +2525,9 @@ static uint32_t ilk_compute_spr_wm(const struct intel_crtc_state *cstate, uint32_t method1, method2; int cpp; + if (mem_value == 0) + return U32_MAX; + if (!intel_wm_plane_visible(cstate, pstate)) return 0; @@ -2545,6 +2551,9 @@ static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate, { int cpp; + if (mem_value == 0) + return U32_MAX; + if (!intel_wm_plane_visible(cstate, pstate)) return 0; @@ -3008,6 +3017,34 @@ static void snb_wm_latency_quirk(struct drm_i915_private *dev_priv) intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency); } +static void snb_wm_lp3_irq_quirk(struct drm_i915_private *dev_priv) +{ + /* + * On some SNB machines (Thinkpad X220 Tablet at least) + * LP3 usage can cause vblank interrupts to be lost. + * The DEIIR bit will go high but it looks like the CPU + * never gets interrupted. + * + * It's not clear whether other interrupt source could + * be affected or if this is somehow limited to vblank + * interrupts only. To play it safe we disable LP3 + * watermarks entirely. + */ + if (dev_priv->wm.pri_latency[3] == 0 && + dev_priv->wm.spr_latency[3] == 0 && + dev_priv->wm.cur_latency[3] == 0) + return; + + dev_priv->wm.pri_latency[3] = 0; + dev_priv->wm.spr_latency[3] = 0; + dev_priv->wm.cur_latency[3] = 0; + + DRM_DEBUG_KMS("LP3 watermarks disabled due to potential for lost interrupts\n"); + intel_print_wm_latency(dev_priv, "Primary", dev_priv->wm.pri_latency); + intel_print_wm_latency(dev_priv, "Sprite", dev_priv->wm.spr_latency); + intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency); +} + static void ilk_setup_wm_latency(struct drm_i915_private *dev_priv) { intel_read_wm_latency(dev_priv, dev_priv->wm.pri_latency); @@ -3024,8 +3061,10 @@ static void ilk_setup_wm_latency(struct drm_i915_private *dev_priv) intel_print_wm_latency(dev_priv, "Sprite", dev_priv->wm.spr_latency); intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency); - if (IS_GEN6(dev_priv)) + if (IS_GEN6(dev_priv)) { snb_wm_latency_quirk(dev_priv); + snb_wm_lp3_irq_quirk(dev_priv); + } } static void skl_setup_wm_latency(struct drm_i915_private *dev_priv) From 8830f26bcd3cf1ff07d9078cd310a534c03b6a10 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 2 Nov 2018 16:12:12 +0000 Subject: [PATCH 2/5] drm/i915: Prevent machine hang from Broxton's vtd w/a and error capture Since capturing the error state requires fiddling around with the GGTT to read arbitrary buffers and is itself run under stop_machine(), it deadlocks the machine (effectively a hard hang) when run in conjunction with Broxton's VTd workaround to serialize GGTT access. v2: Store the ERR_PTR in first_error so that the error can be reported to the user via sysfs. v3: Mention the quirk in dmesg (using info as per usual) Fixes: 0ef34ad6222a ("drm/i915: Serialize GTT/Aperture accesses on BXT") Signed-off-by: Chris Wilson Cc: Jon Bloomfield Cc: John Harrison Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Cc: Daniel Vetter Reviewed-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20181102161232.17742-5-chris@chris-wilson.co.uk (cherry picked from commit fb6f0b64e455b207a636346588e65bf9598d30eb) Signed-off-by: Joonas Lahtinen --- drivers/gpu/drm/i915/i915_gem_gtt.c | 5 +++++ drivers/gpu/drm/i915/i915_gpu_error.c | 15 ++++++++++++++- drivers/gpu/drm/i915/i915_gpu_error.h | 8 +++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 47c302543799..07999fe09ad2 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -3413,6 +3413,11 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) ggtt->vm.insert_page = bxt_vtd_ggtt_insert_page__BKL; if (ggtt->vm.clear_range != nop_clear_range) ggtt->vm.clear_range = bxt_vtd_ggtt_clear_range__BKL; + + /* Prevent recursively calling stop_machine() and deadlocks. */ + dev_info(dev_priv->drm.dev, + "Disabling error capture for VT-d workaround\n"); + i915_disable_error_state(dev_priv, -ENODEV); } ggtt->invalidate = gen6_ggtt_invalidate; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 8762d17b6659..3eb33e000d6f 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -648,6 +648,9 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, return 0; } + if (IS_ERR(error)) + return PTR_ERR(error); + if (*error->error_msg) err_printf(m, "%s\n", error->error_msg); err_printf(m, "Kernel: " UTS_RELEASE "\n"); @@ -1859,6 +1862,7 @@ void i915_capture_error_state(struct drm_i915_private *i915, error = i915_capture_gpu_state(i915); if (!error) { DRM_DEBUG_DRIVER("out of memory, not capturing error state\n"); + i915_disable_error_state(i915, -ENOMEM); return; } @@ -1914,5 +1918,14 @@ void i915_reset_error_state(struct drm_i915_private *i915) i915->gpu_error.first_error = NULL; spin_unlock_irq(&i915->gpu_error.lock); - i915_gpu_state_put(error); + if (!IS_ERR(error)) + i915_gpu_state_put(error); +} + +void i915_disable_error_state(struct drm_i915_private *i915, int err) +{ + spin_lock_irq(&i915->gpu_error.lock); + if (!i915->gpu_error.first_error) + i915->gpu_error.first_error = ERR_PTR(err); + spin_unlock_irq(&i915->gpu_error.lock); } diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index 8710fb18ed74..3ec89a504de5 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -343,6 +343,7 @@ static inline void i915_gpu_state_put(struct i915_gpu_state *gpu) struct i915_gpu_state *i915_first_error_state(struct drm_i915_private *i915); void i915_reset_error_state(struct drm_i915_private *i915); +void i915_disable_error_state(struct drm_i915_private *i915, int err); #else @@ -355,13 +356,18 @@ static inline void i915_capture_error_state(struct drm_i915_private *dev_priv, static inline struct i915_gpu_state * i915_first_error_state(struct drm_i915_private *i915) { - return NULL; + return ERR_PTR(-ENODEV); } static inline void i915_reset_error_state(struct drm_i915_private *i915) { } +static inline void i915_disable_error_state(struct drm_i915_private *i915, + int err) +{ +} + #endif /* IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) */ #endif /* _I915_GPU_ERROR_H_ */ From f8577fb3c273bcae821a5254c8fbcf82016d9a8d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 19 Nov 2018 15:41:53 +0000 Subject: [PATCH 3/5] drm/i915: Write GPU relocs harder with gen3 Under moderate amounts of GPU stress, we can observe on Bearlake and Pineview (later gen3 models) that we execute the following batch buffer before the write into the batch is coherent. Adding extra (tested with upto 32x) MI_FLUSH to either the invalidation, flush or both phases does not solve the incoherency issue with the relocations, but emitting the MI_STORE_DWORD_IMM twice does. So be it. Fixes: 7dd4f6729f92 ("drm/i915: Async GPU relocation processing") Testcase: igt/gem_tiled_fence_blits # blb/pnv Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20181119154153.15327-1-chris@chris-wilson.co.uk (cherry picked from commit 7fa28e146994da1e8a4124623d7da97b798ea520) Signed-off-by: Joonas Lahtinen --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 1aaccbe7e1de..d4fac09095f8 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1268,7 +1268,7 @@ relocate_entry(struct i915_vma *vma, else if (gen >= 4) len = 4; else - len = 3; + len = 6; batch = reloc_gpu(eb, vma, len); if (IS_ERR(batch)) @@ -1309,6 +1309,11 @@ relocate_entry(struct i915_vma *vma, *batch++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL; *batch++ = addr; *batch++ = target_offset; + + /* And again for good measure (blb/pnv) */ + *batch++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL; + *batch++ = addr; + *batch++ = target_offset; } goto out; From c773058dde9a4f919a8069f3828d9f4adb1fce1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 20 Nov 2018 15:54:49 +0200 Subject: [PATCH 4/5] drm/i915: Force a LUT update in intel_initial_commit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we force a plane update to fix up our half populated plane state we'll also force on the pipe gamma for the plane (since we always enable pipe gamma currently). If the BIOS hasn't programmed a sensible LUT into the hardware this will cause the image to become corrupted. Typical symptoms are a purple/yellow/etc. flash when the driver loads. To avoid this let's program something sensible into the LUT when we do the plane update. In the future I plan to add proper plane gamma enable readout so this is just a temporary measure. Cc: Hans de Goede Fixes: 516a49cc1946 ("drm/i915: Fix assert_plane() warning on bootup with external display") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20181120135450.3634-1-ville.syrjala@linux.intel.com Tested-by: Hans de Goede Reviewed-by: Rodrigo Vivi (cherry picked from commit fa6af5145b4e87a30a530be0d80734a9dd40da77) Signed-off-by: Joonas Lahtinen --- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a54843fdeb2f..fa6c1bad5ef7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15267,6 +15267,14 @@ retry: ret = drm_atomic_add_affected_planes(state, crtc); if (ret) goto out; + + /* + * FIXME hack to force a LUT update to avoid the + * plane update forcing the pipe gamma on without + * having a proper LUT loaded. Remove once we + * have readout for pipe gamma enable. + */ + crtc_state->color_mgmt_changed = true; } } From f559156c399cfb11d53a128d210118fbea36816e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 20 Nov 2018 15:54:50 +0200 Subject: [PATCH 5/5] drm/i915: Add rotation readout for plane initial config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we need to force a full plane update before userspace/fbdev have given us a proper plane state we should try to maintain the current plane state as much as possible (apart from the parts of the state we're trying to fix up with the plane update). To that end add basic readout for the plane rotation and maintain it during the initial fb takeover. Cc: Hans de Goede Fixes: 516a49cc1946 ("drm/i915: Fix assert_plane() warning on bootup with external display") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20181120135450.3634-2-ville.syrjala@linux.intel.com Tested-by: Hans de Goede Reviewed-by: Rodrigo Vivi Reviewed-by: Maarten Lankhorst (cherry picked from commit f43348a3db89305bb1935da9fe4499fdcdde9796) Signed-off-by: Joonas Lahtinen --- drivers/gpu/drm/i915/intel_display.c | 31 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 32 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fa6c1bad5ef7..c9878dd1f7cd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2890,6 +2890,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, return; valid_fb: + intel_state->base.rotation = plane_config->rotation; intel_fill_fb_ggtt_view(&intel_state->view, fb, intel_state->base.rotation); intel_state->color_plane[0].stride = @@ -7882,8 +7883,15 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc, plane_config->tiling = I915_TILING_X; fb->modifier = I915_FORMAT_MOD_X_TILED; } + + if (val & DISPPLANE_ROTATE_180) + plane_config->rotation = DRM_MODE_ROTATE_180; } + if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B && + val & DISPPLANE_MIRROR) + plane_config->rotation |= DRM_MODE_REFLECT_X; + pixel_format = val & DISPPLANE_PIXFORMAT_MASK; fourcc = i9xx_format_to_fourcc(pixel_format); fb->format = drm_format_info(fourcc); @@ -8952,6 +8960,29 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc, goto error; } + /* + * DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr + * while i915 HW rotation is clockwise, thats why this swapping. + */ + switch (val & PLANE_CTL_ROTATE_MASK) { + case PLANE_CTL_ROTATE_0: + plane_config->rotation = DRM_MODE_ROTATE_0; + break; + case PLANE_CTL_ROTATE_90: + plane_config->rotation = DRM_MODE_ROTATE_270; + break; + case PLANE_CTL_ROTATE_180: + plane_config->rotation = DRM_MODE_ROTATE_180; + break; + case PLANE_CTL_ROTATE_270: + plane_config->rotation = DRM_MODE_ROTATE_90; + break; + } + + if (INTEL_GEN(dev_priv) >= 10 && + val & PLANE_CTL_FLIP_HORIZONTAL) + plane_config->rotation |= DRM_MODE_REFLECT_X; + base = I915_READ(PLANE_SURF(pipe, plane_id)) & 0xfffff000; plane_config->base = base; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8b298e5f012d..db6fa1d0cbda 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -547,6 +547,7 @@ struct intel_initial_plane_config { unsigned int tiling; int size; u32 base; + u8 rotation; }; #define SKL_MIN_SRC_W 8