From 53421c2fe99ce16838639ad89d772d914a119a49 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Mon, 4 Dec 2017 15:22:10 -0800 Subject: [PATCH 001/158] drm/i915: Apply Display WA #1183 on skl, kbl, and cfl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display WA #1183 was recently added to workaround "Failures when enabling DPLL0 with eDP link rate 2.16 or 4.32 GHz and CD clock frequency 308.57 or 617.14 MHz (CDCLK_CTL CD Frequency Select 10b or 11b) used in this enabling or in previous enabling." This workaround was designed to minimize the impact only to save the bad case with that link rates. But HW engineers indicated that it should be safe to apply broadly, although they were expecting the DPLL0 link rate to be unchanged on runtime. We need to cover 2 cases: when we are in fact enabling DPLL0 and when we are just changing the frequency with small differences. This is based on previous patch by Rodrigo Vivi with suggestions from Ville Syrjälä. Cc: Arthur J Runyan Cc: Ville Syrjälä Cc: Rodrigo Vivi Cc: stable@vger.kernel.org Signed-off-by: Lucas De Marchi Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20171204232210.4958-1-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_cdclk.c | 35 ++++++++++++++++++------- drivers/gpu/drm/i915/intel_runtime_pm.c | 10 +++++++ 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 41285bec8fc0..966e4df9700e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7029,6 +7029,7 @@ enum { #define RESET_PCH_HANDSHAKE_ENABLE (1<<4) #define GEN8_CHICKEN_DCPR_1 _MMIO(0x46430) +#define SKL_SELECT_ALTERNATE_DC_EXIT (1<<30) #define MASK_WAKEMEM (1<<13) #define SKL_DFSM _MMIO(0x51000) @@ -8585,6 +8586,7 @@ enum skl_power_gate { #define BXT_CDCLK_CD2X_DIV_SEL_2 (2<<22) #define BXT_CDCLK_CD2X_DIV_SEL_4 (3<<22) #define BXT_CDCLK_CD2X_PIPE(pipe) ((pipe)<<20) +#define CDCLK_DIVMUX_CD_OVERRIDE (1<<19) #define BXT_CDCLK_CD2X_PIPE_NONE BXT_CDCLK_CD2X_PIPE(3) #define BXT_CDCLK_SSA_PRECHARGE_ENABLE (1<<16) #define CDCLK_FREQ_DECIMAL_MASK (0x7ff) diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index 9c5ceb98d48f..d77e2bec1e29 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -931,16 +931,10 @@ static void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv, static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) { - int min_cdclk = skl_calc_cdclk(0, vco); u32 val; WARN_ON(vco != 8100000 && vco != 8640000); - /* select the minimum CDCLK before enabling DPLL 0 */ - val = CDCLK_FREQ_337_308 | skl_cdclk_decimal(min_cdclk); - I915_WRITE(CDCLK_CTL, val); - POSTING_READ(CDCLK_CTL); - /* * We always enable DPLL0 with the lowest link rate possible, but still * taking into account the VCO required to operate the eDP panel at the @@ -994,7 +988,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, { int cdclk = cdclk_state->cdclk; int vco = cdclk_state->vco; - u32 freq_select; + u32 freq_select, cdclk_ctl; int ret; mutex_lock(&dev_priv->pcu_lock); @@ -1009,7 +1003,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, return; } - /* set CDCLK_CTL */ + /* Choose frequency for this cdclk */ switch (cdclk) { default: WARN_ON(cdclk != dev_priv->cdclk.hw.ref); @@ -1036,10 +1030,33 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, dev_priv->cdclk.hw.vco != vco) skl_dpll0_disable(dev_priv); + cdclk_ctl = I915_READ(CDCLK_CTL); + + if (dev_priv->cdclk.hw.vco != vco) { + /* Wa Display #1183: skl,kbl,cfl */ + cdclk_ctl &= ~(CDCLK_FREQ_SEL_MASK | CDCLK_FREQ_DECIMAL_MASK); + cdclk_ctl |= freq_select | skl_cdclk_decimal(cdclk); + I915_WRITE(CDCLK_CTL, cdclk_ctl); + } + + /* Wa Display #1183: skl,kbl,cfl */ + cdclk_ctl |= CDCLK_DIVMUX_CD_OVERRIDE; + I915_WRITE(CDCLK_CTL, cdclk_ctl); + POSTING_READ(CDCLK_CTL); + if (dev_priv->cdclk.hw.vco != vco) skl_dpll0_enable(dev_priv, vco); - I915_WRITE(CDCLK_CTL, freq_select | skl_cdclk_decimal(cdclk)); + /* Wa Display #1183: skl,kbl,cfl */ + cdclk_ctl &= ~(CDCLK_FREQ_SEL_MASK | CDCLK_FREQ_DECIMAL_MASK); + I915_WRITE(CDCLK_CTL, cdclk_ctl); + + cdclk_ctl |= freq_select | skl_cdclk_decimal(cdclk); + I915_WRITE(CDCLK_CTL, cdclk_ctl); + + /* Wa Display #1183: skl,kbl,cfl */ + cdclk_ctl &= ~CDCLK_DIVMUX_CD_OVERRIDE; + I915_WRITE(CDCLK_CTL, cdclk_ctl); POSTING_READ(CDCLK_CTL); /* inform PCU of the change */ diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index db9d57f39534..d758da6156a8 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -600,6 +600,11 @@ void gen9_enable_dc5(struct drm_i915_private *dev_priv) DRM_DEBUG_KMS("Enabling DC5\n"); + /* Wa Display #1183: skl,kbl,cfl */ + if (IS_GEN9_BC(dev_priv)) + I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) | + SKL_SELECT_ALTERNATE_DC_EXIT); + gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5); } @@ -627,6 +632,11 @@ void skl_disable_dc6(struct drm_i915_private *dev_priv) { DRM_DEBUG_KMS("Disabling DC6\n"); + /* Wa Display #1183: skl,kbl,cfl */ + if (IS_GEN9_BC(dev_priv)) + I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) | + SKL_SELECT_ALTERNATE_DC_EXIT); + gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); } From c8dae55a8ced625038d52d26e48273707fab2688 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 20 Dec 2017 11:50:17 +0100 Subject: [PATCH 002/158] drm/i915/vlv: Add cdclk workaround for DSI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At least on the Chuwi Vi8 (non pro/plus) the LCD panel will show an image shifted aprox. 20% to the left (with wraparound) and sometimes also wrong colors, showing that the panel controller is starting with sampling the datastream somewhere mid-line. This happens after the first blanking and re-init of the panel. After looking at drm.debug output I noticed that initially we inherit the cdclk of 333333 KHz set by the GOP, but after the re-init we picked 266667 KHz, which turns out to be the cause of this problem, a quick hack to hard code the cdclk to 333333 KHz makes the problem go away. I've tested this on various Bay Trail devices, to make sure this not does cause regressions on other devices and the higher cdclk does not cause any problems on the following devices: -GP-electronic T701 1024x600 333333 KHz cdclk after this patch -PEAQ C1010 1920x1200 333333 KHz cdclk after this patch -PoV mobii-wintab-800w 800x1280 333333 KHz cdclk after this patch -Asus Transformer-T100TA 1368x768 320000 KHz cdclk after this patch Also interesting wrt this is the comment in vlv_calc_cdclk about the existing workaround to avoid 200 Mhz as clock because that causes issues in some cases. This commit extends the "do not use 200 Mhz" workaround with an extra check to require atleast 320000 KHz (avoiding 266667 KHz) when a DSI panel is active. Changes in v2: -Change the commit message and the code comment to not treat the GOP as a reference, the GOP should not be treated as a reference Acked-by: Ville Syrjälä Signed-off-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20171220105017.11259-1-hdegoede@redhat.com --- drivers/gpu/drm/i915/intel_cdclk.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index d77e2bec1e29..ca36321eafac 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -1940,6 +1940,14 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state) if (crtc_state->has_audio && INTEL_GEN(dev_priv) >= 9) min_cdclk = max(2 * 96000, min_cdclk); + /* + * On Valleyview some DSI panels lose (v|h)sync when the clock is lower + * than 320000KHz. + */ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) && + IS_VALLEYVIEW(dev_priv)) + min_cdclk = max(320000, min_cdclk); + if (min_cdclk > dev_priv->max_cdclk_freq) { DRM_DEBUG_KMS("required cdclk (%d kHz) exceeds max (%d kHz)\n", min_cdclk, dev_priv->max_cdclk_freq); From 35954e88bc5091ef82134e8c99c5bcc3b4c6772a Mon Sep 17 00:00:00 2001 From: "C, Ramalingam" Date: Wed, 8 Nov 2017 00:08:23 +0530 Subject: [PATCH 003/158] drm/i915: Runtime disable for eDP DRRS Debugfs called i915_drrs_ctl is added to enable and disable the eDP DRRS. Writing 0 will disable the feature, whereas non-zero will enable the feature. Possibility of disabling the DRRS, enables the testing of the frontbuffer tracking based features (FBC, DRRS and PSR) as standalone or any combination of the set. [v2]: ctl interface is moved from module parameter to debugfs [Rodrigo] Signed-off-by: C, Ramalingam Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/1510079903-29441-1-git-send-email-ramalingam.c@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 43 ++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e968aeae1d84..ffa5f3f8222d 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4606,6 +4606,46 @@ static const struct file_operations i915_hpd_storm_ctl_fops = { .write = i915_hpd_storm_ctl_write }; +static int i915_drrs_ctl_set(void *data, u64 val) +{ + struct drm_i915_private *dev_priv = data; + struct drm_device *dev = &dev_priv->drm; + struct intel_crtc *intel_crtc; + struct intel_encoder *encoder; + struct intel_dp *intel_dp; + + if (INTEL_GEN(dev_priv) < 7) + return -ENODEV; + + drm_modeset_lock_all(dev); + for_each_intel_crtc(dev, intel_crtc) { + if (!intel_crtc->base.state->active || + !intel_crtc->config->has_drrs) + continue; + + for_each_encoder_on_crtc(dev, &intel_crtc->base, encoder) { + if (encoder->type != INTEL_OUTPUT_EDP) + continue; + + DRM_DEBUG_DRIVER("Manually %sabling DRRS. %llu\n", + val ? "en" : "dis", val); + + intel_dp = enc_to_intel_dp(&encoder->base); + if (val) + intel_edp_drrs_enable(intel_dp, + intel_crtc->config); + else + intel_edp_drrs_disable(intel_dp, + intel_crtc->config); + } + } + drm_modeset_unlock_all(dev); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(i915_drrs_ctl_fops, NULL, i915_drrs_ctl_set, "%llu\n"); + static const struct drm_info_list i915_debugfs_list[] = { {"i915_capabilities", i915_capabilities, 0}, {"i915_gem_objects", i915_gem_object_info, 0}, @@ -4683,7 +4723,8 @@ static const struct i915_debugfs_files { {"i915_dp_test_active", &i915_displayport_test_active_fops}, {"i915_guc_log_control", &i915_guc_log_control_fops}, {"i915_hpd_storm_ctl", &i915_hpd_storm_ctl_fops}, - {"i915_ipc_status", &i915_ipc_status_fops} + {"i915_ipc_status", &i915_ipc_status_fops}, + {"i915_drrs_ctl", &i915_drrs_ctl_fops} }; int i915_debugfs_register(struct drm_i915_private *dev_priv) From ce6e21370d5cacff3cd06c997af65316e7bba577 Mon Sep 17 00:00:00 2001 From: "C, Ramalingam" Date: Mon, 20 Nov 2017 09:53:47 +0530 Subject: [PATCH 004/158] i915/drrs/debugfs: psr status info addition Existing debugfs entry i915_drrs_status is updated with whether PSR is the cause for DRRS disabled state. [v2]: Dropped the module parameter details as ctl moved from module parameter to debugfs. [Rodrigo] [v3]: Crtc ID information is dropped as there is no immediate usecase. [Rodrigo]. Signed-off-by: C, Ramalingam Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/1511151827-6596-1-git-send-email-ramalingam.c@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index ffa5f3f8222d..d81cb2513069 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3363,7 +3363,10 @@ static void drrs_status_per_crtc(struct seq_file *m, /* disable_drrs() will make drrs->dp NULL */ if (!drrs->dp) { - seq_puts(m, "Idleness DRRS: Disabled"); + seq_puts(m, "Idleness DRRS: Disabled\n"); + if (dev_priv->psr.enabled) + seq_puts(m, + "\tAs PSR is enabled, DRRS is not enabled\n"); mutex_unlock(&drrs->mutex); return; } From 85a9c0bc0888be8b140de06ae6486208bc1424f9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 23 Dec 2017 11:04:06 +0000 Subject: [PATCH 005/158] drm/i915/selftests: Tweak igt_ggtt_page to speed it up Reduce the number of GGTT PTE operations to speed the test up, but we reduce the likelihood of spotting a coherency error in those operations. However, Broxton is sporadically timing on this test, presumably because its GGTT operations are all uncached. Signed-off-by: Chris Wilson Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20171223110407.21402-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index 4a28d713a7d8..bb7cf998fc65 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -1052,35 +1052,38 @@ static int igt_ggtt_page(void *arg) memset(&tmp, 0, sizeof(tmp)); err = drm_mm_insert_node_in_range(&ggtt->base.mm, &tmp, - 1024 * PAGE_SIZE, 0, + count * PAGE_SIZE, 0, I915_COLOR_UNEVICTABLE, 0, ggtt->mappable_end, DRM_MM_INSERT_LOW); if (err) goto out_unpin; + intel_runtime_pm_get(i915); + + for (n = 0; n < count; n++) { + u64 offset = tmp.start + n * PAGE_SIZE; + + ggtt->base.insert_page(&ggtt->base, + i915_gem_object_get_dma_address(obj, 0), + offset, I915_CACHE_NONE, 0); + } + order = i915_random_order(count, &prng); if (!order) { err = -ENOMEM; goto out_remove; } - intel_runtime_pm_get(i915); for (n = 0; n < count; n++) { u64 offset = tmp.start + order[n] * PAGE_SIZE; u32 __iomem *vaddr; - ggtt->base.insert_page(&ggtt->base, - i915_gem_object_get_dma_address(obj, 0), - offset, I915_CACHE_NONE, 0); - vaddr = io_mapping_map_atomic_wc(&ggtt->iomap, offset); iowrite32(n, vaddr + n); io_mapping_unmap_atomic(vaddr); - - wmb(); - ggtt->base.clear_range(&ggtt->base, offset, PAGE_SIZE); } + i915_gem_flush_ggtt_writes(i915); i915_random_reorder(order, count, &prng); for (n = 0; n < count; n++) { @@ -1088,16 +1091,10 @@ static int igt_ggtt_page(void *arg) u32 __iomem *vaddr; u32 val; - ggtt->base.insert_page(&ggtt->base, - i915_gem_object_get_dma_address(obj, 0), - offset, I915_CACHE_NONE, 0); - vaddr = io_mapping_map_atomic_wc(&ggtt->iomap, offset); val = ioread32(vaddr + n); io_mapping_unmap_atomic(vaddr); - ggtt->base.clear_range(&ggtt->base, offset, PAGE_SIZE); - if (val != n) { pr_err("insert page failed: found %d, expected %d\n", val, n); @@ -1105,10 +1102,11 @@ static int igt_ggtt_page(void *arg) break; } } - intel_runtime_pm_put(i915); kfree(order); out_remove: + ggtt->base.clear_range(&ggtt->base, tmp.start, tmp.size); + intel_runtime_pm_put(i915); drm_mm_remove_node(&tmp); out_unpin: i915_gem_object_unpin_pages(obj); From 9861b6682804a9db82600e0adf592bfa6deec377 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 23 Dec 2017 11:04:07 +0000 Subject: [PATCH 006/158] drm/i915/selftests: Allow random array allocation to fail In the selftests, we don't want to force an oom and would rather ENOMEM be reported. In this case, we would rather the allocation for the random array to fail. Signed-off-by: Chris Wilson Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20171223110407.21402-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_random.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_random.c b/drivers/gpu/drm/i915/selftests/i915_random.c index 2088ae57aa89..1f415ce47018 100644 --- a/drivers/gpu/drm/i915/selftests/i915_random.c +++ b/drivers/gpu/drm/i915/selftests/i915_random.c @@ -57,7 +57,8 @@ unsigned int *i915_random_order(unsigned int count, struct rnd_state *state) { unsigned int *order, i; - order = kmalloc_array(count, sizeof(*order), GFP_KERNEL | __GFP_NOWARN); + order = kmalloc_array(count, sizeof(*order), + GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN); if (!order) return order; From 27ec1843169973fbdf224d831e2a40f441407ab0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 2 Jan 2018 15:12:17 +0000 Subject: [PATCH 007/158] drm/i915: Delete defunct i915_gem_request_assign() i915_gem_request_assign() is not used since commit 77f0d0e925e8 ("drm/i915/execlists: Pack the count into the low bits of the port.request"), so remove the defunct code References: 77f0d0e925e8 ("drm/i915/execlists: Pack the count into the low bits of the port.request") Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180102151235.3949-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_request.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_request.h b/drivers/gpu/drm/i915/i915_gem_request.h index 0d6d39f19506..04ee289d6cab 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.h +++ b/drivers/gpu/drm/i915/i915_gem_request.h @@ -245,18 +245,6 @@ i915_gem_request_put(struct drm_i915_gem_request *req) dma_fence_put(&req->fence); } -static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst, - struct drm_i915_gem_request *src) -{ - if (src) - i915_gem_request_get(src); - - if (*pdst) - i915_gem_request_put(*pdst); - - *pdst = src; -} - /** * i915_gem_request_global_seqno - report the current global seqno * @request - the request From 42232213614ddbef854ef368092e39c4e8347877 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 2 Jan 2018 15:12:32 +0000 Subject: [PATCH 008/158] drm/i915/execlists: Clear context-switch interrupt earlier in the reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the clearing of the CS-interrupt into the engine reset phase, before the current init-hw phase. This helps clarify that we clear the pending interrupts prior to any restarting of the execlists. Signed-off-by: Chris Wilson Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20180102151235.3949-16-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 33 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 739c33b07c59..8f699a1c9ed5 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1493,18 +1493,6 @@ static int gen8_init_common_ring(struct intel_engine_cs *engine) GEM_BUG_ON(engine->id >= ARRAY_SIZE(gtiir)); - /* - * Clear any pending interrupt state. - * - * We do it twice out of paranoia that some of the IIR are double - * buffered, and if we only reset it once there may still be - * an interrupt pending. - */ - I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]), - GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift); - I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]), - GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift); - clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); execlists->csb_head = -1; execlists->active = 0; @@ -1551,6 +1539,24 @@ static int gen9_init_render_ring(struct intel_engine_cs *engine) return init_workarounds_ring(engine); } +static void reset_irq(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + + /* + * Clear any pending interrupt state. + * + * We do it twice out of paranoia that some of the IIR are double + * buffered, and if we only reset it once there may still be + * an interrupt pending. + */ + I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]), + GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift); + I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]), + GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift); + clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); +} + static void reset_common_ring(struct intel_engine_cs *engine, struct drm_i915_gem_request *request) { @@ -1560,6 +1566,9 @@ static void reset_common_ring(struct intel_engine_cs *engine, GEM_TRACE("%s seqno=%x\n", engine->name, request ? request->global_seqno : 0); + + reset_irq(engine); + spin_lock_irqsave(&engine->timeline->lock, flags); /* From 693cfbf0589040536c673d6ed3d262ea3ecf9aea Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 2 Jan 2018 15:12:33 +0000 Subject: [PATCH 009/158] drm/i915/execlists: Record elsp offset during engine setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, we record the elsp register offset inside init-hw but we only need to do it once during engine setup (after we know the mmio iomapping). Signed-off-by: Chris Wilson Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20180102151235.3949-17-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8f699a1c9ed5..c23ffde36355 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1496,9 +1496,6 @@ static int gen8_init_common_ring(struct intel_engine_cs *engine) execlists->csb_head = -1; execlists->active = 0; - execlists->elsp = - dev_priv->regs + i915_mmio_reg_offset(RING_ELSP(engine)); - /* After a GPU reset, we may have requests to replay */ if (execlists->first) tasklet_schedule(&execlists->tasklet); @@ -2007,6 +2004,9 @@ static int logical_ring_init(struct intel_engine_cs *engine) if (ret) goto error; + engine->execlists.elsp = + engine->i915->regs + i915_mmio_reg_offset(RING_ELSP(engine)); + return 0; error: From f3c9d4075771b4fbaa0d793d2c875c61e2e1cb12 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 2 Jan 2018 15:12:34 +0000 Subject: [PATCH 010/158] drm/i915/execlists: Tidy enabling execlists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the register settings for enabling execlists into its own function for clarity. Signed-off-by: Chris Wilson Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20180102151235.3949-18-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index c23ffde36355..e114776b8836 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1469,9 +1469,20 @@ static u8 gtiir[] = { [VECS] = 3, }; -static int gen8_init_common_ring(struct intel_engine_cs *engine) +static void enable_execlists(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; + + I915_WRITE(RING_HWSTAM(engine->mmio_base), 0xffffffff); + I915_WRITE(RING_MODE_GEN7(engine), + _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); + I915_WRITE(RING_HWS_PGA(engine->mmio_base), + engine->status_page.ggtt_offset); + POSTING_READ(RING_HWS_PGA(engine->mmio_base)); +} + +static int gen8_init_common_ring(struct intel_engine_cs *engine) +{ struct intel_engine_execlists * const execlists = &engine->execlists; int ret; @@ -1482,13 +1493,7 @@ static int gen8_init_common_ring(struct intel_engine_cs *engine) intel_engine_reset_breadcrumbs(engine); intel_engine_init_hangcheck(engine); - I915_WRITE(RING_HWSTAM(engine->mmio_base), 0xffffffff); - I915_WRITE(RING_MODE_GEN7(engine), - _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); - I915_WRITE(RING_HWS_PGA(engine->mmio_base), - engine->status_page.ggtt_offset); - POSTING_READ(RING_HWS_PGA(engine->mmio_base)); - + enable_execlists(engine); DRM_DEBUG_DRIVER("Execlists enabled for %s\n", engine->name); GEM_BUG_ON(engine->id >= ARRAY_SIZE(gtiir)); @@ -1915,6 +1920,7 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *engine) intel_engine_cleanup_common(engine); lrc_destroy_wa_ctx(engine); + engine->i915 = NULL; dev_priv->engine[engine->id] = NULL; kfree(engine); From 65c475c6dd607226159a774d7c3d7ff4b6e00255 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 2 Jan 2018 15:12:31 +0000 Subject: [PATCH 011/158] drm/i915: Hold rpm wakeref for modifying the global seqno MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To modify the global seqno may require rewriting a few registers, which requires us to hold the rpm wakeref. We must therefore take it around the call to i915_gem_set_global_seqno() in debugfs, on behalf of the user. Signed-off-by: Chris Wilson Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20180102151235.3949-15-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_debugfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d81cb2513069..2bb63073d73f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -988,7 +988,10 @@ i915_next_seqno_set(void *data, u64 val) if (ret) return ret; + intel_runtime_pm_get(dev_priv); ret = i915_gem_set_global_seqno(dev, val); + intel_runtime_pm_put(dev_priv); + mutex_unlock(&dev->struct_mutex); return ret; From 83cc84c5a848748d4bb190bc179a7620491a925f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 2 Jan 2018 15:12:25 +0000 Subject: [PATCH 012/158] drm/i915: Assert all signalers we depended on did indeed signal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Back up our comment that all signalers should have been signaled before we ourselves were retired with an assert to that effect. Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20180102151235.3949-9-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_request.c | 9 ++++++++- drivers/gpu/drm/i915/i915_gem_request.h | 8 ++++++++ drivers/gpu/drm/i915/intel_lrc.c | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c index d575109f7a7f..72bdc203716f 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.c +++ b/drivers/gpu/drm/i915/i915_gem_request.c @@ -161,12 +161,16 @@ i915_priotree_fini(struct drm_i915_private *i915, struct i915_priotree *pt) GEM_BUG_ON(!list_empty(&pt->link)); - /* Everyone we depended upon (the fences we wait to be signaled) + /* + * Everyone we depended upon (the fences we wait to be signaled) * should retire before us and remove themselves from our list. * However, retirement is run independently on each timeline and * so we may be called out-of-order. */ list_for_each_entry_safe(dep, next, &pt->signalers_list, signal_link) { + GEM_BUG_ON(!i915_priotree_signaled(dep->signaler)); + GEM_BUG_ON(!list_empty(&dep->dfs_link)); + list_del(&dep->wait_link); if (dep->flags & I915_DEPENDENCY_ALLOC) i915_dependency_free(i915, dep); @@ -174,6 +178,9 @@ i915_priotree_fini(struct drm_i915_private *i915, struct i915_priotree *pt) /* Remove ourselves from everyone who depends upon us */ list_for_each_entry_safe(dep, next, &pt->waiters_list, wait_link) { + GEM_BUG_ON(dep->signaler != pt); + GEM_BUG_ON(!list_empty(&dep->dfs_link)); + list_del(&dep->signal_link); if (dep->flags & I915_DEPENDENCY_ALLOC) i915_dependency_free(i915, dep); diff --git a/drivers/gpu/drm/i915/i915_gem_request.h b/drivers/gpu/drm/i915/i915_gem_request.h index 04ee289d6cab..6c607f8dbf92 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.h +++ b/drivers/gpu/drm/i915/i915_gem_request.h @@ -329,6 +329,14 @@ i915_gem_request_completed(const struct drm_i915_gem_request *req) return __i915_gem_request_completed(req, seqno); } +static inline bool i915_priotree_signaled(const struct i915_priotree *pt) +{ + const struct drm_i915_gem_request *rq = + container_of(pt, const struct drm_i915_gem_request, priotree); + + return i915_gem_request_completed(rq); +} + /* We treat requests as fences. This is not be to confused with our * "fence registers" but pipeline synchronisation objects ala GL_ARB_sync. * We use the fences to synchronize access from the CPU with activity on the diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index e114776b8836..04c35e4dd7c6 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1037,7 +1037,7 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio) * engines. */ list_for_each_entry(p, &pt->signalers_list, signal_link) { - if (i915_gem_request_completed(pt_to_request(p->signaler))) + if (i915_priotree_signaled(p->signaler)) continue; GEM_BUG_ON(p->signaler->priority < pt->priority); From ce01b173773a09e2b5d3007c26d11cbd7737c3fe Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 2 Jan 2018 15:12:26 +0000 Subject: [PATCH 013/158] drm/i915/execlists: Assert there are no simple cycles in the dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dependency chain must be an acyclic graph. This is checked by the swfence, but for sanity, also do a simple check that we do not corrupt our list iteration in execlists_schedule() by a shallow dependency cycle. Signed-off-by: Chris Wilson Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20180102151235.3949-10-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 04c35e4dd7c6..7d1ce21fa051 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1011,7 +1011,8 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio) stack.signaler = &request->priotree; list_add(&stack.dfs_link, &dfs); - /* Recursively bump all dependent priorities to match the new request. + /* + * Recursively bump all dependent priorities to match the new request. * * A naive approach would be to use recursion: * static void update_priorities(struct i915_priotree *pt, prio) { @@ -1031,12 +1032,15 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio) list_for_each_entry_safe(dep, p, &dfs, dfs_link) { struct i915_priotree *pt = dep->signaler; - /* Within an engine, there can be no cycle, but we may + /* + * Within an engine, there can be no cycle, but we may * refer to the same dependency chain multiple times * (redundant dependencies are not eliminated) and across * engines. */ list_for_each_entry(p, &pt->signalers_list, signal_link) { + GEM_BUG_ON(p == dep); /* no cycles! */ + if (i915_priotree_signaled(p->signaler)) continue; @@ -1048,7 +1052,8 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio) list_safe_reset_next(dep, p, dfs_link); } - /* If we didn't need to bump any existing priorities, and we haven't + /* + * If we didn't need to bump any existing priorities, and we haven't * yet submitted this request (i.e. there is no potential race with * execlists_submit_request()), we can set our own priority and skip * acquiring the engine locks. From 2221c5b7ddfae1ed1ca8b21a9092d0878281293a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 2 Jan 2018 15:12:27 +0000 Subject: [PATCH 014/158] drm/i915/execlists: Reduce list_for_each_safe+list_safe_reset_next MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After staring at the list_for_each_safe macros for a bit, our current invocation of list_safe_reset_next in execlists_schedule() simply reduces to list_for_each. Signed-off-by: Chris Wilson Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20180102151235.3949-11-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7d1ce21fa051..4e150b095a11 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1029,7 +1029,7 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio) * end result is a topological list of requests in reverse order, the * last element in the list is the request we must execute first. */ - list_for_each_entry_safe(dep, p, &dfs, dfs_link) { + list_for_each_entry(dep, &dfs, dfs_link) { struct i915_priotree *pt = dep->signaler; /* @@ -1048,8 +1048,6 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio) if (prio > READ_ONCE(p->signaler->priority)) list_move_tail(&p->dfs_link, &dfs); } - - list_safe_reset_next(dep, p, dfs_link); } /* From c24f0c1de481c1c0f914e937f409bac2c90b90b3 Mon Sep 17 00:00:00 2001 From: Sujaritha Sundaresan Date: Tue, 2 Jan 2018 13:20:24 -0800 Subject: [PATCH 015/158] drm/i915/guc : Decoupling ADS and logs from submission The Additional Data Struct (ADS) contains objects that are required by GuC post FW load and are not necessarily submission-only. Even with submission disabled we may require something inside the ADS, so it makes more sense for them to be always created. Similarly, we need to access GuC logs and even if GuC submission is disabled, to debug issues with GuC loading or with whatever we're using GuC for. v2: re-wording commit message (Sagar) Signed-off-by: Sujaritha Sundaresan Cc: Chris Wilson Cc: Michal Wajdeczko Cc: Sagar Arun Kamble Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/1514928025-29659-1-git-send-email-sujaritha.sundaresan@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/intel_guc.c | 18 +++ drivers/gpu/drm/i915/intel_guc_ads.c | 151 ++++++++++++++++++++ drivers/gpu/drm/i915/intel_guc_ads.h | 33 +++++ drivers/gpu/drm/i915/intel_guc_submission.c | 134 ----------------- 5 files changed, 203 insertions(+), 134 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_guc_ads.c create mode 100644 drivers/gpu/drm/i915/intel_guc_ads.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 091aef281963..4d9e2f855e9d 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -83,6 +83,7 @@ i915-y += i915_cmd_parser.o \ i915-y += intel_uc.o \ intel_uc_fw.o \ intel_guc.o \ + intel_guc_ads.o \ intel_guc_ct.o \ intel_guc_fw.o \ intel_guc_log.o \ diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 3c6bf5a34c3c..50b472576980 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -23,6 +23,7 @@ */ #include "intel_guc.h" +#include "intel_guc_ads.h" #include "intel_guc_submission.h" #include "i915_drv.h" @@ -163,10 +164,25 @@ int intel_guc_init(struct intel_guc *guc) return ret; GEM_BUG_ON(!guc->shared_data); + ret = intel_guc_log_create(guc); + if (ret) + goto err_shared; + + ret = intel_guc_ads_create(guc); + if (ret) + goto err_log; + GEM_BUG_ON(!guc->ads_vma); + /* We need to notify the guc whenever we change the GGTT */ i915_ggtt_enable_guc(dev_priv); return 0; + +err_log: + intel_guc_log_destroy(guc); +err_shared: + guc_shared_data_destroy(guc); + return ret; } void intel_guc_fini(struct intel_guc *guc) @@ -174,6 +190,8 @@ void intel_guc_fini(struct intel_guc *guc) struct drm_i915_private *dev_priv = guc_to_i915(guc); i915_ggtt_disable_guc(dev_priv); + intel_guc_ads_destroy(guc); + intel_guc_log_destroy(guc); guc_shared_data_destroy(guc); } diff --git a/drivers/gpu/drm/i915/intel_guc_ads.c b/drivers/gpu/drm/i915/intel_guc_ads.c new file mode 100644 index 000000000000..ac627534667d --- /dev/null +++ b/drivers/gpu/drm/i915/intel_guc_ads.c @@ -0,0 +1,151 @@ +/* + * Copyright © 2014-2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#include "intel_guc_ads.h" +#include "intel_uc.h" +#include "i915_drv.h" + +/* + * The Additional Data Struct (ADS) has pointers for different buffers used by + * the GuC. One single gem object contains the ADS struct itself (guc_ads), the + * scheduling policies (guc_policies), a structure describing a collection of + * register sets (guc_mmio_reg_state) and some extra pages for the GuC to save + * its internal state for sleep. + */ + +static void guc_policy_init(struct guc_policy *policy) +{ + policy->execution_quantum = POLICY_DEFAULT_EXECUTION_QUANTUM_US; + policy->preemption_time = POLICY_DEFAULT_PREEMPTION_TIME_US; + policy->fault_time = POLICY_DEFAULT_FAULT_TIME_US; + policy->policy_flags = 0; +} + +static void guc_policies_init(struct guc_policies *policies) +{ + struct guc_policy *policy; + u32 p, i; + + policies->dpc_promote_time = POLICY_DEFAULT_DPC_PROMOTE_TIME_US; + policies->max_num_work_items = POLICY_MAX_NUM_WI; + + for (p = 0; p < GUC_CLIENT_PRIORITY_NUM; p++) { + for (i = GUC_RENDER_ENGINE; i < GUC_MAX_ENGINES_NUM; i++) { + policy = &policies->policy[p][i]; + + guc_policy_init(policy); + } + } + + policies->is_valid = 1; +} + +/* + * The first 80 dwords of the register state context, containing the + * execlists and ppgtt registers. + */ +#define LR_HW_CONTEXT_SIZE (80 * sizeof(u32)) + +/** + * intel_guc_ads_create() - creates GuC ADS + * @guc: intel_guc struct + * + */ +int intel_guc_ads_create(struct intel_guc *guc) +{ + struct drm_i915_private *dev_priv = guc_to_i915(guc); + struct i915_vma *vma; + struct page *page; + /* The ads obj includes the struct itself and buffers passed to GuC */ + struct { + struct guc_ads ads; + struct guc_policies policies; + struct guc_mmio_reg_state reg_state; + u8 reg_state_buffer[GUC_S3_SAVE_SPACE_PAGES * PAGE_SIZE]; + } __packed *blob; + struct intel_engine_cs *engine; + enum intel_engine_id id; + const u32 skipped_offset = LRC_HEADER_PAGES * PAGE_SIZE; + const u32 skipped_size = LRC_PPHWSP_SZ * PAGE_SIZE + LR_HW_CONTEXT_SIZE; + u32 base; + + GEM_BUG_ON(guc->ads_vma); + + vma = intel_guc_allocate_vma(guc, PAGE_ALIGN(sizeof(*blob))); + if (IS_ERR(vma)) + return PTR_ERR(vma); + + guc->ads_vma = vma; + + page = i915_vma_first_page(vma); + blob = kmap(page); + + /* GuC scheduling policies */ + guc_policies_init(&blob->policies); + + /* MMIO reg state */ + for_each_engine(engine, dev_priv, id) { + blob->reg_state.white_list[engine->guc_id].mmio_start = + engine->mmio_base + GUC_MMIO_WHITE_LIST_START; + + /* Nothing to be saved or restored for now. */ + blob->reg_state.white_list[engine->guc_id].count = 0; + } + + /* + * The GuC requires a "Golden Context" when it reinitialises + * engines after a reset. Here we use the Render ring default + * context, which must already exist and be pinned in the GGTT, + * so its address won't change after we've told the GuC where + * to find it. Note that we have to skip our header (1 page), + * because our GuC shared data is there. + */ + blob->ads.golden_context_lrca = + guc_ggtt_offset(dev_priv->kernel_context->engine[RCS].state) + + skipped_offset; + + /* + * The GuC expects us to exclude the portion of the context image that + * it skips from the size it is to read. It starts reading from after + * the execlist context (so skipping the first page [PPHWSP] and 80 + * dwords). Weird guc is weird. + */ + for_each_engine(engine, dev_priv, id) + blob->ads.eng_state_size[engine->guc_id] = + engine->context_size - skipped_size; + + base = guc_ggtt_offset(vma); + blob->ads.scheduler_policies = base + ptr_offset(blob, policies); + blob->ads.reg_state_buffer = base + ptr_offset(blob, reg_state_buffer); + blob->ads.reg_state_addr = base + ptr_offset(blob, reg_state); + + kunmap(page); + + return 0; +} + +void intel_guc_ads_destroy(struct intel_guc *guc) +{ + i915_vma_unpin_and_release(&guc->ads_vma); +} diff --git a/drivers/gpu/drm/i915/intel_guc_ads.h b/drivers/gpu/drm/i915/intel_guc_ads.h new file mode 100644 index 000000000000..c4735742c564 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_guc_ads.h @@ -0,0 +1,33 @@ +/* + * Copyright © 2014-2017 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#ifndef _INTEL_GUC_ADS_H_ +#define _INTEL_GUC_ADS_H_ + +struct intel_guc; + +int intel_guc_ads_create(struct intel_guc *guc); +void intel_guc_ads_destroy(struct intel_guc *guc); + +#endif diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 4d2409466a3a..1f3a8786bbdc 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -73,13 +73,6 @@ * ELSP context descriptor dword into Work Item. * See guc_add_request() * - * ADS: - * The Additional Data Struct (ADS) has pointers for different buffers used by - * the GuC. One single gem object contains the ADS struct itself (guc_ads), the - * scheduling policies (guc_policies), a structure describing a collection of - * register sets (guc_mmio_reg_state) and some extra pages for the GuC to save - * its internal state for sleep. - * */ static inline bool is_high_priority(struct intel_guc_client *client) @@ -1012,117 +1005,6 @@ static void guc_clients_destroy(struct intel_guc *guc) guc_client_free(client); } -static void guc_policy_init(struct guc_policy *policy) -{ - policy->execution_quantum = POLICY_DEFAULT_EXECUTION_QUANTUM_US; - policy->preemption_time = POLICY_DEFAULT_PREEMPTION_TIME_US; - policy->fault_time = POLICY_DEFAULT_FAULT_TIME_US; - policy->policy_flags = 0; -} - -static void guc_policies_init(struct guc_policies *policies) -{ - struct guc_policy *policy; - u32 p, i; - - policies->dpc_promote_time = POLICY_DEFAULT_DPC_PROMOTE_TIME_US; - policies->max_num_work_items = POLICY_MAX_NUM_WI; - - for (p = 0; p < GUC_CLIENT_PRIORITY_NUM; p++) { - for (i = GUC_RENDER_ENGINE; i < GUC_MAX_ENGINES_NUM; i++) { - policy = &policies->policy[p][i]; - - guc_policy_init(policy); - } - } - - policies->is_valid = 1; -} - -/* - * The first 80 dwords of the register state context, containing the - * execlists and ppgtt registers. - */ -#define LR_HW_CONTEXT_SIZE (80 * sizeof(u32)) - -static int guc_ads_create(struct intel_guc *guc) -{ - struct drm_i915_private *dev_priv = guc_to_i915(guc); - struct i915_vma *vma; - struct page *page; - /* The ads obj includes the struct itself and buffers passed to GuC */ - struct { - struct guc_ads ads; - struct guc_policies policies; - struct guc_mmio_reg_state reg_state; - u8 reg_state_buffer[GUC_S3_SAVE_SPACE_PAGES * PAGE_SIZE]; - } __packed *blob; - struct intel_engine_cs *engine; - enum intel_engine_id id; - const u32 skipped_offset = LRC_HEADER_PAGES * PAGE_SIZE; - const u32 skipped_size = LRC_PPHWSP_SZ * PAGE_SIZE + LR_HW_CONTEXT_SIZE; - u32 base; - - GEM_BUG_ON(guc->ads_vma); - - vma = intel_guc_allocate_vma(guc, PAGE_ALIGN(sizeof(*blob))); - if (IS_ERR(vma)) - return PTR_ERR(vma); - - guc->ads_vma = vma; - - page = i915_vma_first_page(vma); - blob = kmap(page); - - /* GuC scheduling policies */ - guc_policies_init(&blob->policies); - - /* MMIO reg state */ - for_each_engine(engine, dev_priv, id) { - blob->reg_state.white_list[engine->guc_id].mmio_start = - engine->mmio_base + GUC_MMIO_WHITE_LIST_START; - - /* Nothing to be saved or restored for now. */ - blob->reg_state.white_list[engine->guc_id].count = 0; - } - - /* - * The GuC requires a "Golden Context" when it reinitialises - * engines after a reset. Here we use the Render ring default - * context, which must already exist and be pinned in the GGTT, - * so its address won't change after we've told the GuC where - * to find it. Note that we have to skip our header (1 page), - * because our GuC shared data is there. - */ - blob->ads.golden_context_lrca = - guc_ggtt_offset(dev_priv->kernel_context->engine[RCS].state) + - skipped_offset; - - /* - * The GuC expects us to exclude the portion of the context image that - * it skips from the size it is to read. It starts reading from after - * the execlist context (so skipping the first page [PPHWSP] and 80 - * dwords). Weird guc is weird. - */ - for_each_engine(engine, dev_priv, id) - blob->ads.eng_state_size[engine->guc_id] = - engine->context_size - skipped_size; - - base = guc_ggtt_offset(vma); - blob->ads.scheduler_policies = base + ptr_offset(blob, policies); - blob->ads.reg_state_buffer = base + ptr_offset(blob, reg_state_buffer); - blob->ads.reg_state_addr = base + ptr_offset(blob, reg_state); - - kunmap(page); - - return 0; -} - -static void guc_ads_destroy(struct intel_guc *guc) -{ - i915_vma_unpin_and_release(&guc->ads_vma); -} - /* * Set up the memory resources to be shared with the GuC (via the GGTT) * at firmware loading time. @@ -1146,15 +1028,6 @@ int intel_guc_submission_init(struct intel_guc *guc) */ GEM_BUG_ON(!guc->stage_desc_pool); - ret = intel_guc_log_create(guc); - if (ret < 0) - goto err_stage_desc_pool; - - ret = guc_ads_create(guc); - if (ret < 0) - goto err_log; - GEM_BUG_ON(!guc->ads_vma); - WARN_ON(!guc_verify_doorbells(guc)); ret = guc_clients_create(guc); if (ret) @@ -1167,11 +1040,6 @@ int intel_guc_submission_init(struct intel_guc *guc) return 0; -err_log: - intel_guc_log_destroy(guc); -err_stage_desc_pool: - guc_stage_desc_pool_destroy(guc); - return ret; } void intel_guc_submission_fini(struct intel_guc *guc) @@ -1186,8 +1054,6 @@ void intel_guc_submission_fini(struct intel_guc *guc) guc_clients_destroy(guc); WARN_ON(!guc_verify_doorbells(guc)); - guc_ads_destroy(guc); - intel_guc_log_destroy(guc); guc_stage_desc_pool_destroy(guc); } From 6f25d0be180f5b4713c6fb5a6619fe11dd1dacd9 Mon Sep 17 00:00:00 2001 From: Sujaritha Sundaresan Date: Tue, 2 Jan 2018 13:20:25 -0800 Subject: [PATCH 016/158] drm/i915/guc : GEM_BUG_ON on invoking GuC reset function Instead of returning -EINVAL, GEM_BUG_ON when GuC reset is invoked for platforms not supporting as we don't expect to invoke it. v2: re-wording commit message and subject (Sagar) Signed-off-by: Sujaritha Sundaresan Cc: Chris Wilson Cc: Michal Wajdeczko Cc: Sagar Arun Kamble Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/1514928025-29659-2-git-send-email-sujaritha.sundaresan@intel.com --- drivers/gpu/drm/i915/intel_uncore.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 89547b614aa6..94e1fb3a2936 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1936,8 +1936,7 @@ int intel_reset_guc(struct drm_i915_private *dev_priv) { int ret; - if (!HAS_GUC(dev_priv)) - return -EINVAL; + GEM_BUG_ON(!HAS_GUC(dev_priv)); intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); ret = gen6_hw_domain_reset(dev_priv, GEN9_GRDOM_GUC); From c68ce69910e3b292afc138e12725399d3b0fb347 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 2 Jan 2018 19:25:00 +0000 Subject: [PATCH 017/158] drm/i915: Assert we do not try to wait on an invalid seqno MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We should never insert the invalid seqno into the wait tree, so assert we do not. Signed-off-by: Chris Wilson Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20180102192500.20364-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_breadcrumbs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c index 58c624f982d9..86acac010bb8 100644 --- a/drivers/gpu/drm/i915/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c @@ -396,6 +396,8 @@ static bool __intel_engine_add_wait(struct intel_engine_cs *engine, bool first, armed; u32 seqno; + GEM_BUG_ON(!wait->seqno); + /* Insert the request into the retirement ordered list * of waiters by walking the rbtree. If we are the oldest * seqno in the tree (the first to be retired), then From 82e07602d22ab45cd90e31b62a87f0fa37ca428f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 4 Jan 2018 16:38:42 +0000 Subject: [PATCH 018/158] drm/i915: Pass DMA_ATTR_NO_WARN to dma_map_sg() In some iommu, e.g. swiotlb, the available space can be quite limited. So we employ a trial-and-error approach to seeing if our large contiguous chunks can fit, and if that fails we try again with smaller chunks after trying to free our own lazily allocated blobs. As we use a trial-and-error approach, we do not want dma_map_sg() to emit a WARN of its own accord, we want to gracefully report the error back to the caller instead. Note that our noisy culprit, swiotlb, doesn't honour the flag, yet. Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Cc: Matthew Auld Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20180104163842.11635-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index c5f393870532..f2a0f556da21 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2335,9 +2335,10 @@ int i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj, struct sg_table *pages) { do { - if (dma_map_sg(&obj->base.dev->pdev->dev, - pages->sgl, pages->nents, - PCI_DMA_BIDIRECTIONAL)) + if (dma_map_sg_attrs(&obj->base.dev->pdev->dev, + pages->sgl, pages->nents, + PCI_DMA_BIDIRECTIONAL, + DMA_ATTR_NO_WARN)) return 0; /* If the DMA remap fails, one cause can be that we have From a76050a4837860fcadb6ca11d69d41e08f4090d8 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Wed, 3 Jan 2018 11:03:45 -0800 Subject: [PATCH 019/158] drm/i915/glk: Disable Guc and HuC on GLK Since the firmwares are not yet released to public repo, disable them on Geminilake. v2: Remove the firmware versions (Michal) v3: Remove unwanted defines (Rodrigo) Correct commit message (Michal) Cc: Michal Wajdeczko Cc: Rodrigo Vivi Cc: Signed-off-by: Anusha Srivatsa Fixes: 90f192c8241e ("drm/i915/GuC/GLK: Load GuC on GLK") Fixes: db5ba0d8931e ("drm/i915/GLK/HuC: Load HuC on GLK") Reviewed-by: Michal Wajdeczko Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/1515006225-13003-1-git-send-email-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/intel_guc_fw.c | 9 --------- drivers/gpu/drm/i915/intel_huc.c | 11 ----------- 2 files changed, 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc_fw.c b/drivers/gpu/drm/i915/intel_guc_fw.c index cbc51c960425..3b0932942857 100644 --- a/drivers/gpu/drm/i915/intel_guc_fw.c +++ b/drivers/gpu/drm/i915/intel_guc_fw.c @@ -39,9 +39,6 @@ #define KBL_FW_MAJOR 9 #define KBL_FW_MINOR 39 -#define GLK_FW_MAJOR 10 -#define GLK_FW_MINOR 56 - #define GUC_FW_PATH(platform, major, minor) \ "i915/" __stringify(platform) "_guc_ver" __stringify(major) "_" __stringify(minor) ".bin" @@ -54,8 +51,6 @@ MODULE_FIRMWARE(I915_BXT_GUC_UCODE); #define I915_KBL_GUC_UCODE GUC_FW_PATH(kbl, KBL_FW_MAJOR, KBL_FW_MINOR) MODULE_FIRMWARE(I915_KBL_GUC_UCODE); -#define I915_GLK_GUC_UCODE GUC_FW_PATH(glk, GLK_FW_MAJOR, GLK_FW_MINOR) - static void guc_fw_select(struct intel_uc_fw *guc_fw) { struct intel_guc *guc = container_of(guc_fw, struct intel_guc, fw); @@ -82,10 +77,6 @@ static void guc_fw_select(struct intel_uc_fw *guc_fw) guc_fw->path = I915_KBL_GUC_UCODE; guc_fw->major_ver_wanted = KBL_FW_MAJOR; guc_fw->minor_ver_wanted = KBL_FW_MINOR; - } else if (IS_GEMINILAKE(dev_priv)) { - guc_fw->path = I915_GLK_GUC_UCODE; - guc_fw->major_ver_wanted = GLK_FW_MAJOR; - guc_fw->minor_ver_wanted = GLK_FW_MINOR; } else { DRM_WARN("%s: No firmware known for this platform!\n", intel_uc_fw_type_repr(guc_fw->type)); diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c index 974be3defa70..8ed05182f944 100644 --- a/drivers/gpu/drm/i915/intel_huc.c +++ b/drivers/gpu/drm/i915/intel_huc.c @@ -54,10 +54,6 @@ #define KBL_HUC_FW_MINOR 00 #define KBL_BLD_NUM 1810 -#define GLK_HUC_FW_MAJOR 02 -#define GLK_HUC_FW_MINOR 00 -#define GLK_BLD_NUM 1748 - #define HUC_FW_PATH(platform, major, minor, bld_num) \ "i915/" __stringify(platform) "_huc_ver" __stringify(major) "_" \ __stringify(minor) "_" __stringify(bld_num) ".bin" @@ -74,9 +70,6 @@ MODULE_FIRMWARE(I915_BXT_HUC_UCODE); KBL_HUC_FW_MINOR, KBL_BLD_NUM) MODULE_FIRMWARE(I915_KBL_HUC_UCODE); -#define I915_GLK_HUC_UCODE HUC_FW_PATH(glk, GLK_HUC_FW_MAJOR, \ - GLK_HUC_FW_MINOR, GLK_BLD_NUM) - static void huc_fw_select(struct intel_uc_fw *huc_fw) { struct intel_huc *huc = container_of(huc_fw, struct intel_huc, fw); @@ -103,10 +96,6 @@ static void huc_fw_select(struct intel_uc_fw *huc_fw) huc_fw->path = I915_KBL_HUC_UCODE; huc_fw->major_ver_wanted = KBL_HUC_FW_MAJOR; huc_fw->minor_ver_wanted = KBL_HUC_FW_MINOR; - } else if (IS_GEMINILAKE(dev_priv)) { - huc_fw->path = I915_GLK_HUC_UCODE; - huc_fw->major_ver_wanted = GLK_HUC_FW_MAJOR; - huc_fw->minor_ver_wanted = GLK_HUC_FW_MINOR; } else { DRM_WARN("%s: No firmware known for this platform!\n", intel_uc_fw_type_repr(huc_fw->type)); From fe9a9da61c3ec33c7d3ad305c2c535edbcae1ddb Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Thu, 4 Jan 2018 15:51:42 -0800 Subject: [PATCH 020/158] drm/i915/dmc: DMC 1.07 for Cannonlake There is a new version of DMC available for CNL. The release notes mentions: 1. Fix for the issue where DC_STATE was getting enabled even when disabled by driver causing data corruption v2: Since the firmware is merged to linux-firmware.git, add MODULE_FIRMWARE. v3: rebased. Correct commit message(Jani) Cc: Jani Saarinen Cc: Rodrigo Vivi Signed-off-by: Anusha Srivatsa Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/1515109902-14076-1-git-send-email-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/intel_csr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index 7fe4aac0facc..41e6c75a7f3c 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -37,8 +37,9 @@ #define I915_CSR_GLK "i915/glk_dmc_ver1_04.bin" #define GLK_CSR_VERSION_REQUIRED CSR_VERSION(1, 4) -#define I915_CSR_CNL "i915/cnl_dmc_ver1_06.bin" -#define CNL_CSR_VERSION_REQUIRED CSR_VERSION(1, 6) +#define I915_CSR_CNL "i915/cnl_dmc_ver1_07.bin" +MODULE_FIRMWARE(I915_CSR_CNL); +#define CNL_CSR_VERSION_REQUIRED CSR_VERSION(1, 7) #define I915_CSR_KBL "i915/kbl_dmc_ver1_04.bin" MODULE_FIRMWARE(I915_CSR_KBL); From ab062639edb0412daf6de540725276b9a5d217f9 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Fri, 5 Jan 2018 00:59:05 -0800 Subject: [PATCH 021/158] drm/i915: Whitelist SLICE_COMMON_ECO_CHICKEN1 on Geminilake. Geminilake requires the 3D driver to select whether barriers are intended for compute shaders, or tessellation control shaders, by whacking a "Barrier Mode" bit in SLICE_COMMON_ECO_CHICKEN1 when switching pipelines. Failure to do this properly can result in GPU hangs. Unfortunately, this means it needs to switch mid-batch, so only userspace can properly set it. To facilitate this, the kernel needs to whitelist the register. The workarounds page currently tags this as applying to Broxton only, but that doesn't make sense. The documentation for the register it references says the bit userspace is supposed to toggle only exists on Geminilake. Empirically, the Mesa patch to toggle this bit appears to fix intermittent GPU hangs in tessellation control shader barrier tests on Geminilake; we haven't seen those hangs on Broxton. v2: Mention WA #0862 in the comment (it doesn't have a name). Signed-off-by: Kenneth Graunke Acked-by: Rodrigo Vivi Cc: stable@vger.kernel.org Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180105085905.9298-1-kenneth@whitecape.org --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_engine_cs.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 966e4df9700e..505c605eff98 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7079,6 +7079,8 @@ enum { #define GEN9_SLICE_COMMON_ECO_CHICKEN0 _MMIO(0x7308) #define DISABLE_PIXEL_MASK_CAMMING (1<<14) +#define GEN9_SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c) + #define GEN7_L3SQCREG1 _MMIO(0xB010) #define VLV_B0_WA_L3SQCREG1_VALUE 0x00D30000 diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index ebdcbcbacb3c..6bb51a502b8b 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1338,6 +1338,11 @@ static int glk_init_workarounds(struct intel_engine_cs *engine) if (ret) return ret; + /* WA #0862: Userspace has to set "Barrier Mode" to avoid hangs. */ + ret = wa_ring_whitelist_reg(engine, GEN9_SLICE_COMMON_ECO_CHICKEN1); + if (ret) + return ret; + /* WaToEnableHwFixForPushConstHWBug:glk */ WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); From c218ee03b9315073ce43992792554dafa0626eb8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 6 Jan 2018 10:56:18 +0000 Subject: [PATCH 022/158] drm/i915: Don't adjust priority on an already signaled fence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we retire a signaled fence, we free the dependency tree. However, we skip clearing the list so that if we then try to adjust the priority of the signaled fence, we may walk the list of freed dependencies. [ 3083.156757] ================================================================== [ 3083.156806] BUG: KASAN: use-after-free in execlists_schedule+0x199/0x660 [i915] [ 3083.156810] Read of size 8 at addr ffff8806bf20f400 by task Xorg/831 [ 3083.156815] CPU: 0 PID: 831 Comm: Xorg Not tainted 4.15.0-rc6-no-psn+ #1 [ 3083.156817] Hardware name: Notebook N24_25BU/N24_25BU, BIOS 5.12 02/17/2017 [ 3083.156818] Call Trace: [ 3083.156823] dump_stack+0x5c/0x7a [ 3083.156827] print_address_description+0x6b/0x290 [ 3083.156830] kasan_report+0x28f/0x380 [ 3083.156872] ? execlists_schedule+0x199/0x660 [i915] [ 3083.156914] execlists_schedule+0x199/0x660 [i915] [ 3083.156956] ? intel_crtc_atomic_check+0x146/0x4e0 [i915] [ 3083.156997] ? execlists_submit_request+0xe0/0xe0 [i915] [ 3083.157038] ? i915_vma_misplaced.part.4+0x25/0xb0 [i915] [ 3083.157079] ? __i915_vma_do_pin+0x7c8/0xc80 [i915] [ 3083.157121] ? intel_atomic_state_alloc+0x44/0x60 [i915] [ 3083.157130] ? drm_atomic_helper_page_flip+0x3e/0xb0 [drm_kms_helper] [ 3083.157145] ? drm_mode_page_flip_ioctl+0x7d2/0x850 [drm] [ 3083.157159] ? drm_ioctl_kernel+0xa7/0xf0 [drm] [ 3083.157172] ? drm_ioctl+0x45b/0x560 [drm] [ 3083.157211] i915_gem_object_wait_priority+0x14c/0x2c0 [i915] [ 3083.157251] ? i915_gem_get_aperture_ioctl+0x150/0x150 [i915] [ 3083.157290] ? i915_vma_pin_fence+0x1d8/0x320 [i915] [ 3083.157331] ? intel_pin_and_fence_fb_obj+0x175/0x250 [i915] [ 3083.157372] ? intel_rotation_info_size+0x60/0x60 [i915] [ 3083.157413] ? intel_link_compute_m_n+0x80/0x80 [i915] [ 3083.157428] ? drm_dev_printk+0x1b0/0x1b0 [drm] [ 3083.157443] ? drm_dev_printk+0x1b0/0x1b0 [drm] [ 3083.157485] intel_prepare_plane_fb+0x2f8/0x5a0 [i915] [ 3083.157527] ? intel_crtc_get_vblank_counter+0x80/0x80 [i915] [ 3083.157536] drm_atomic_helper_prepare_planes+0xa0/0x1c0 [drm_kms_helper] [ 3083.157587] intel_atomic_commit+0x12e/0x4e0 [i915] [ 3083.157605] drm_atomic_helper_page_flip+0xa2/0xb0 [drm_kms_helper] [ 3083.157621] drm_mode_page_flip_ioctl+0x7d2/0x850 [drm] [ 3083.157638] ? drm_mode_cursor2_ioctl+0x10/0x10 [drm] [ 3083.157652] ? drm_lease_owner+0x1a/0x30 [drm] [ 3083.157668] ? drm_mode_cursor2_ioctl+0x10/0x10 [drm] [ 3083.157681] drm_ioctl_kernel+0xa7/0xf0 [drm] [ 3083.157696] drm_ioctl+0x45b/0x560 [drm] [ 3083.157711] ? drm_mode_cursor2_ioctl+0x10/0x10 [drm] [ 3083.157725] ? drm_getstats+0x20/0x20 [drm] [ 3083.157729] ? timerqueue_del+0x49/0x80 [ 3083.157732] ? __remove_hrtimer+0x62/0xb0 [ 3083.157735] ? hrtimer_try_to_cancel+0x173/0x210 [ 3083.157738] do_vfs_ioctl+0x13b/0x880 [ 3083.157741] ? ioctl_preallocate+0x140/0x140 [ 3083.157744] ? _raw_spin_unlock_irq+0xe/0x30 [ 3083.157746] ? do_setitimer+0x234/0x370 [ 3083.157750] ? SyS_setitimer+0x19e/0x1b0 [ 3083.157752] ? SyS_alarm+0x140/0x140 [ 3083.157755] ? __rcu_read_unlock+0x66/0x80 [ 3083.157757] ? __fget+0xc4/0x100 [ 3083.157760] SyS_ioctl+0x74/0x80 [ 3083.157763] entry_SYSCALL_64_fastpath+0x1a/0x7d [ 3083.157765] RIP: 0033:0x7f6135d0c6a7 [ 3083.157767] RSP: 002b:00007fff01451888 EFLAGS: 00003246 ORIG_RAX: 0000000000000010 [ 3083.157769] RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007f6135d0c6a7 [ 3083.157771] RDX: 00007fff01451950 RSI: 00000000c01864b0 RDI: 000000000000000c [ 3083.157772] RBP: 00007f613076f600 R08: 0000000000000001 R09: 0000000000000000 [ 3083.157773] R10: 0000000000000060 R11: 0000000000003246 R12: 0000000000000000 [ 3083.157774] R13: 0000000000000060 R14: 000000000000001b R15: 0000000000000060 [ 3083.157779] Allocated by task 831: [ 3083.157783] kmem_cache_alloc+0xc0/0x200 [ 3083.157822] i915_gem_request_await_dma_fence+0x2c4/0x5d0 [i915] [ 3083.157861] i915_gem_request_await_object+0x321/0x370 [i915] [ 3083.157900] i915_gem_do_execbuffer+0x1165/0x19c0 [i915] [ 3083.157937] i915_gem_execbuffer2+0x1ad/0x550 [i915] [ 3083.157950] drm_ioctl_kernel+0xa7/0xf0 [drm] [ 3083.157962] drm_ioctl+0x45b/0x560 [drm] [ 3083.157964] do_vfs_ioctl+0x13b/0x880 [ 3083.157966] SyS_ioctl+0x74/0x80 [ 3083.157968] entry_SYSCALL_64_fastpath+0x1a/0x7d [ 3083.157971] Freed by task 831: [ 3083.157973] kmem_cache_free+0x77/0x220 [ 3083.158012] i915_gem_request_retire+0x72c/0xa70 [i915] [ 3083.158051] i915_gem_request_alloc+0x1e9/0x8b0 [i915] [ 3083.158089] i915_gem_do_execbuffer+0xa96/0x19c0 [i915] [ 3083.158127] i915_gem_execbuffer2+0x1ad/0x550 [i915] [ 3083.158140] drm_ioctl_kernel+0xa7/0xf0 [drm] [ 3083.158153] drm_ioctl+0x45b/0x560 [drm] [ 3083.158155] do_vfs_ioctl+0x13b/0x880 [ 3083.158156] SyS_ioctl+0x74/0x80 [ 3083.158158] entry_SYSCALL_64_fastpath+0x1a/0x7d [ 3083.158162] The buggy address belongs to the object at ffff8806bf20f400 which belongs to the cache i915_dependency of size 64 [ 3083.158166] The buggy address is located 0 bytes inside of 64-byte region [ffff8806bf20f400, ffff8806bf20f440) [ 3083.158168] The buggy address belongs to the page: [ 3083.158171] page:00000000d43decc4 count:1 mapcount:0 mapping: (null) index:0x0 [ 3083.158174] flags: 0x17ffe0000000100(slab) [ 3083.158179] raw: 017ffe0000000100 0000000000000000 0000000000000000 0000000180200020 [ 3083.158182] raw: ffffea001afc16c0 0000000500000005 ffff880731b881c0 0000000000000000 [ 3083.158184] page dumped because: kasan: bad access detected [ 3083.158187] Memory state around the buggy address: [ 3083.158190] ffff8806bf20f300: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc [ 3083.158192] ffff8806bf20f380: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc [ 3083.158195] >ffff8806bf20f400: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc [ 3083.158196] ^ [ 3083.158199] ffff8806bf20f480: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc [ 3083.158201] ffff8806bf20f500: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc [ 3083.158203] ================================================================== Reported-by: Alexandru Chirvasitu Reported-by: Mike Keehan Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104436 Fixes: 1f181225f8ec ("drm/i915/execlists: Keep request->priority for its lifetime") Signed-off-by: Chris Wilson Cc: Alexandru Chirvasitu Cc: Michał Winiarski Cc: Joonas Lahtinen Cc: Tvrtko Ursulin Tested-by: Alexandru Chirvasitu Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20180106105618.13532-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ba9f67c256f4..8bc3283484be 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -467,7 +467,7 @@ static void __fence_set_priority(struct dma_fence *fence, int prio) struct drm_i915_gem_request *rq; struct intel_engine_cs *engine; - if (!dma_fence_is_i915(fence)) + if (dma_fence_is_signaled(fence) || !dma_fence_is_i915(fence)) return; rq = to_request(fence); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 4e150b095a11..ff25f209d0a5 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1002,6 +1002,9 @@ static void execlists_schedule(struct drm_i915_gem_request *request, int prio) GEM_BUG_ON(prio == I915_PRIORITY_INVALID); + if (i915_gem_request_completed(request)) + return; + if (prio <= READ_ONCE(request->priotree.priority)) return; From cfb926e148e99acc02351d72e8b85e32b5f786ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sun, 31 Dec 2017 23:34:54 +0100 Subject: [PATCH 023/158] drm/i915: Try EDID bitbanging on HDMI after failed read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ACK/NACK implementation as found in e.g. the G965 has the falling clock edge and the release of the data line after the ACK for the received byte happen at the same time. This is conformant with the I2C specification, which allows a zero hold time, see footnote [3]: "A device must internally provide a hold time of at least 300 ns for the SDA signal (with respect to the V IH(min) of the SCL signal) to bridge the undefined region of the falling edge of SCL." Some HDMI-to-VGA converters apparently fail to adhere to this requirement and latch SDA at the falling clock edge, so instead of an ACK sometimes a NACK is read and the slave (i.e. the EDID ROM) ends the transfer. The bitbanging releases the data line for the ACK only 1/4 bit time after the falling clock edge, so a slave will see the correct value no matter if it samples at the rising or the falling clock edge or in the center. Fallback to bitbanging is already done for the CRT connector. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92685 Signed-off-by: Stefan Brüns Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/a39f080b-81a5-4c93-b3f7-7cb0a58daca3@rwthex-w2-a.rwth-ad.de --- drivers/gpu/drm/i915/intel_hdmi.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index bced7b954d93..179d0ad3889d 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1595,12 +1595,20 @@ intel_hdmi_set_edid(struct drm_connector *connector) struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); struct edid *edid; bool connected = false; + struct i2c_adapter *i2c; intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); - edid = drm_get_edid(connector, - intel_gmbus_get_adapter(dev_priv, - intel_hdmi->ddc_bus)); + i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); + + edid = drm_get_edid(connector, i2c); + + if (!edid && !intel_gmbus_is_forced_bit(i2c)) { + DRM_DEBUG_KMS("HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n"); + intel_gmbus_force_bit(i2c, true); + edid = drm_get_edid(connector, i2c); + intel_gmbus_force_bit(i2c, false); + } intel_hdmi_dp_dual_mode_detect(connector, edid != NULL); From 17bd6e66d8f677b1b250d098097fbed6e70175ef Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 9 Jan 2018 14:20:40 +0200 Subject: [PATCH 024/158] drm/i915: Fix using BIT_ULL() vs. BIT() for power domain masks The power domain masks are 64 bit wide, so we need BIT_ULL() when setting bits in them, these ones were missed during converting from 32 to 64 bit masks. All 3 enums are <32 atm, so this didn't cause a real problem. Fixes: d8fc70b7367b ("drm/i915: Make power domain masks 64 bit long") Cc: Joonas Lahtinen Reported-by: Fengguang Wu Signed-off-by: Imre Deak Reviewed-by: Chris Wilson Reviewed-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20180109122040.19425-1-imre.deak@intel.com --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0cd355978ab4..f288bcc7be22 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5661,8 +5661,8 @@ static u64 get_crtc_power_domains(struct drm_crtc *crtc, if (!crtc_state->base.active) return 0; - mask = BIT(POWER_DOMAIN_PIPE(pipe)); - mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder)); + mask = BIT_ULL(POWER_DOMAIN_PIPE(pipe)); + mask |= BIT_ULL(POWER_DOMAIN_TRANSCODER(transcoder)); if (crtc_state->pch_pfit.enabled || crtc_state->pch_pfit.force_thru) mask |= BIT_ULL(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe)); @@ -5674,7 +5674,7 @@ static u64 get_crtc_power_domains(struct drm_crtc *crtc, } if (HAS_DDI(dev_priv) && crtc_state->has_audio) - mask |= BIT(POWER_DOMAIN_AUDIO); + mask |= BIT_ULL(POWER_DOMAIN_AUDIO); if (crtc_state->shared_dpll) mask |= BIT_ULL(POWER_DOMAIN_PLLS); From da943b5ab071584fcb9cfa896dc8c643d376f362 Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Wed, 10 Jan 2018 18:24:16 +0530 Subject: [PATCH 025/158] drm/i915/guc: Add uc_fini_wq in gem_init unwind path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While moving code around for solving lockdep issue for GuC log relay, spotted that uc_fini_wq is not being called in failure path in gem_init. Missed in the below commit. Add it. v2: Removed GEM_BUG_ON(!HAS_GUC()) from intel_uc_fini_wq as init happens only based on enable_guc module parameter and does not consider has_guc capability. (Michal) Signed-off-by: Sagar Arun Kamble Fixes: 3176ff49bc3e ("drm/i915/guc: Move GuC workqueue allocations outside of the mutex") Cc: Michał Winiarski Cc: Chris Wilson Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/1515588857-10283-1-git-send-email-sagar.a.kamble@intel.com Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 2 ++ drivers/gpu/drm/i915/intel_uc.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8bc3283484be..1135a77b383a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5283,6 +5283,8 @@ err_unlock: intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); mutex_unlock(&dev_priv->drm.struct_mutex); + intel_uc_fini_wq(dev_priv); + if (ret != -EIO) i915_gem_cleanup_userptr(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 907deac6e3fa..d82ca0f438f5 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -209,8 +209,6 @@ void intel_uc_fini_wq(struct drm_i915_private *dev_priv) if (!USES_GUC(dev_priv)) return; - GEM_BUG_ON(!HAS_GUC(dev_priv)); - intel_guc_fini_wq(&dev_priv->guc); } From 5a3f58dfd1420347be838546e00a4a9e847bda30 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Fri, 22 Dec 2017 14:38:49 -0800 Subject: [PATCH 026/158] drm/i915: Stop getting the fault address from RING_FAULT_REG This register does not contain it. Instead, we have to look into FAULT_TLB_DATA0 & 1 (where, by the way, we can also get the address space). v2: Right formatting v3: - Use 12 (as per the register format) instead of PAGE_SIZE (Chris) - s/BITS_44_TO_47/HIGHBITS (Chris) - Right formatting, this time for real Fixes: b03ec3d67ab8 ("drm/i915: There is only one fault register from GEN8 onwards") Signed-off-by: Oscar Mateo Cc: Michel Thierry Cc: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/1513982329-32191-1-git-send-email-oscar.mateo@intel.com Reviewed-by: Michel Thierry Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_gtt.c | 15 +++++++++++++-- drivers/gpu/drm/i915/i915_reg.h | 2 ++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index f2a0f556da21..26dee5e61e99 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2287,12 +2287,23 @@ static void gen8_check_and_clear_faults(struct drm_i915_private *dev_priv) u32 fault = I915_READ(GEN8_RING_FAULT_REG); if (fault & RING_FAULT_VALID) { + u32 fault_data0, fault_data1; + u64 fault_addr; + + fault_data0 = I915_READ(GEN8_FAULT_TLB_DATA0); + fault_data1 = I915_READ(GEN8_FAULT_TLB_DATA1); + fault_addr = ((u64)(fault_data1 & FAULT_VA_HIGH_BITS) << 44) | + ((u64)fault_data0 << 12); + DRM_DEBUG_DRIVER("Unexpected fault\n" - "\tAddr: 0x%08lx\n" + "\tAddr: 0x%08x_%08x\n" + "\tAddress space: %s\n" "\tEngine ID: %d\n" "\tSource ID: %d\n" "\tType: %d\n", - fault & PAGE_MASK, + upper_32_bits(fault_addr), + lower_32_bits(fault_addr), + fault_data1 & FAULT_GTT_SEL ? "GGTT" : "PPGTT", GEN8_RING_FAULT_ENGINE_ID(fault), RING_FAULT_SRCID(fault), RING_FAULT_FAULT_TYPE(fault)); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 505c605eff98..a2108e35c599 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2489,6 +2489,8 @@ enum i915_power_well_id { #define GEN8_FAULT_TLB_DATA0 _MMIO(0x4b10) #define GEN8_FAULT_TLB_DATA1 _MMIO(0x4b14) +#define FAULT_VA_HIGH_BITS (0xf << 0) +#define FAULT_GTT_SEL (1 << 4) #define FPGA_DBG _MMIO(0x42300) #define FPGA_DBG_RM_NOCLAIM (1<<31) From 6e7a3f5244356ce079457cb3cfbc58ca01c00a2e Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 11 Jan 2018 08:24:17 +0000 Subject: [PATCH 027/158] drm/i915: Apply headless DMC workaround for CNL With firmware 1.07 having fixed the state corruption issue, we can enable the headless GT performance workaround for CNL as well. (Equivalent to b68763741aa2 ("drm/i915: Restore GT performance in headless mode with DMC loaded") on other affected platforms.) Signed-off-by: Tvrtko Ursulin Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=100572 Testcase: igt/gem_exec_nop/headless Cc: Imre Deak Cc: Chris Wilson Cc: Dmitry Rogozhkin Reviewed-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20180111082417.795-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/intel_runtime_pm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index d758da6156a8..4996c4ea8a80 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -1848,6 +1848,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, BIT_ULL(POWER_DOMAIN_INIT)) #define CNL_DISPLAY_DC_OFF_POWER_DOMAINS ( \ CNL_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ + BIT_ULL(POWER_DOMAIN_GT_IRQ) | \ BIT_ULL(POWER_DOMAIN_MODESET) | \ BIT_ULL(POWER_DOMAIN_AUX_A) | \ BIT_ULL(POWER_DOMAIN_INIT)) From 109ec558370f78143509d9ebb6c26e19de1f1fb9 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 11 Jan 2018 08:35:25 +0000 Subject: [PATCH 028/158] drm/i915/pmu: Only enumerate available counters in sysfs Switch over to dynamically creating device attributes, which are in turn used by the perf core to expose available counters in sysfs. This way we do not expose counters which are not avaiable on the current platform, and are so more consistent between what we reply to open attempts via the perf_event_open(2), and what is discoverable in sysfs. v2: * Simplify attribute pointer freeing loop. * Changed attr init from macro to function. * More common error unwind. (Chris Wilson) * Rename some locals. (Chris Wilson) v3: * Fixed double semi-colon. (Chris Wilson) Signed-off-by: Tvrtko Ursulin Cc: Chris Wilson Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180111083525.32394-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 323 ++++++++++++++++++++++++-------- drivers/gpu/drm/i915/i915_pmu.h | 8 + 2 files changed, 252 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 55a8a1e29424..9139bc8df82b 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -290,21 +290,16 @@ static void i915_pmu_event_destroy(struct perf_event *event) WARN_ON(event->parent); } -static int engine_event_init(struct perf_event *event) +static int +engine_event_status(struct intel_engine_cs *engine, + enum drm_i915_pmu_engine_sample sample) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); - - if (!intel_engine_lookup_user(i915, engine_event_class(event), - engine_event_instance(event))) - return -ENODEV; - - switch (engine_event_sample(event)) { + switch (sample) { case I915_SAMPLE_BUSY: case I915_SAMPLE_WAIT: break; case I915_SAMPLE_SEMA: - if (INTEL_GEN(i915) < 6) + if (INTEL_GEN(engine->i915) < 6) return -ENODEV; break; default: @@ -314,6 +309,46 @@ static int engine_event_init(struct perf_event *event) return 0; } +static int +config_status(struct drm_i915_private *i915, u64 config) +{ + switch (config) { + case I915_PMU_ACTUAL_FREQUENCY: + if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) + /* Requires a mutex for sampling! */ + return -ENODEV; + /* Fall-through. */ + case I915_PMU_REQUESTED_FREQUENCY: + if (INTEL_GEN(i915) < 6) + return -ENODEV; + break; + case I915_PMU_INTERRUPTS: + break; + case I915_PMU_RC6_RESIDENCY: + if (!HAS_RC6(i915)) + return -ENODEV; + break; + default: + return -ENOENT; + } + + return 0; +} + +static int engine_event_init(struct perf_event *event) +{ + struct drm_i915_private *i915 = + container_of(event->pmu, typeof(*i915), pmu.base); + struct intel_engine_cs *engine; + + engine = intel_engine_lookup_user(i915, engine_event_class(event), + engine_event_instance(event)); + if (!engine) + return -ENODEV; + + return engine_event_status(engine, engine_event_sample(event)); +} + static int i915_pmu_event_init(struct perf_event *event) { struct drm_i915_private *i915 = @@ -337,30 +372,10 @@ static int i915_pmu_event_init(struct perf_event *event) if (!cpumask_test_cpu(event->cpu, &i915_pmu_cpumask)) return -EINVAL; - if (is_engine_event(event)) { + if (is_engine_event(event)) ret = engine_event_init(event); - } else { - ret = 0; - switch (event->attr.config) { - case I915_PMU_ACTUAL_FREQUENCY: - if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) - /* Requires a mutex for sampling! */ - ret = -ENODEV; - case I915_PMU_REQUESTED_FREQUENCY: - if (INTEL_GEN(i915) < 6) - ret = -ENODEV; - break; - case I915_PMU_INTERRUPTS: - break; - case I915_PMU_RC6_RESIDENCY: - if (!HAS_RC6(i915)) - ret = -ENODEV; - break; - default: - ret = -ENOENT; - break; - } - } + else + ret = config_status(i915, event->attr.config); if (ret) return ret; @@ -657,52 +672,9 @@ static ssize_t i915_pmu_event_show(struct device *dev, return sprintf(buf, "config=0x%lx\n", eattr->val); } -#define I915_EVENT_ATTR(_name, _config) \ - (&((struct i915_ext_attribute[]) { \ - { .attr = __ATTR(_name, 0444, i915_pmu_event_show, NULL), \ - .val = _config, } \ - })[0].attr.attr) - -#define I915_EVENT_STR(_name, _str) \ - (&((struct perf_pmu_events_attr[]) { \ - { .attr = __ATTR(_name, 0444, perf_event_sysfs_show, NULL), \ - .id = 0, \ - .event_str = _str, } \ - })[0].attr.attr) - -#define I915_EVENT(_name, _config, _unit) \ - I915_EVENT_ATTR(_name, _config), \ - I915_EVENT_STR(_name.unit, _unit) - -#define I915_ENGINE_EVENT(_name, _class, _instance, _sample) \ - I915_EVENT_ATTR(_name, __I915_PMU_ENGINE(_class, _instance, _sample)), \ - I915_EVENT_STR(_name.unit, "ns") - -#define I915_ENGINE_EVENTS(_name, _class, _instance) \ - I915_ENGINE_EVENT(_name##_instance-busy, _class, _instance, I915_SAMPLE_BUSY), \ - I915_ENGINE_EVENT(_name##_instance-sema, _class, _instance, I915_SAMPLE_SEMA), \ - I915_ENGINE_EVENT(_name##_instance-wait, _class, _instance, I915_SAMPLE_WAIT) - -static struct attribute *i915_pmu_events_attrs[] = { - I915_ENGINE_EVENTS(rcs, I915_ENGINE_CLASS_RENDER, 0), - I915_ENGINE_EVENTS(bcs, I915_ENGINE_CLASS_COPY, 0), - I915_ENGINE_EVENTS(vcs, I915_ENGINE_CLASS_VIDEO, 0), - I915_ENGINE_EVENTS(vcs, I915_ENGINE_CLASS_VIDEO, 1), - I915_ENGINE_EVENTS(vecs, I915_ENGINE_CLASS_VIDEO_ENHANCE, 0), - - I915_EVENT(actual-frequency, I915_PMU_ACTUAL_FREQUENCY, "MHz"), - I915_EVENT(requested-frequency, I915_PMU_REQUESTED_FREQUENCY, "MHz"), - - I915_EVENT_ATTR(interrupts, I915_PMU_INTERRUPTS), - - I915_EVENT(rc6-residency, I915_PMU_RC6_RESIDENCY, "ns"), - - NULL, -}; - -static const struct attribute_group i915_pmu_events_attr_group = { +static struct attribute_group i915_pmu_events_attr_group = { .name = "events", - .attrs = i915_pmu_events_attrs, + /* Patch in attrs at runtime. */ }; static ssize_t @@ -720,7 +692,7 @@ static struct attribute *i915_cpumask_attrs[] = { NULL, }; -static struct attribute_group i915_pmu_cpumask_attr_group = { +static const struct attribute_group i915_pmu_cpumask_attr_group = { .attrs = i915_cpumask_attrs, }; @@ -731,6 +703,191 @@ static const struct attribute_group *i915_pmu_attr_groups[] = { NULL }; +#define __event(__config, __name, __unit) \ +{ \ + .config = (__config), \ + .name = (__name), \ + .unit = (__unit), \ +} + +#define __engine_event(__sample, __name) \ +{ \ + .sample = (__sample), \ + .name = (__name), \ +} + +static struct i915_ext_attribute * +add_i915_attr(struct i915_ext_attribute *attr, const char *name, u64 config) +{ + attr->attr.attr.name = name; + attr->attr.attr.mode = 0444; + attr->attr.show = i915_pmu_event_show; + attr->val = config; + + return ++attr; +} + +static struct perf_pmu_events_attr * +add_pmu_attr(struct perf_pmu_events_attr *attr, const char *name, + const char *str) +{ + attr->attr.attr.name = name; + attr->attr.attr.mode = 0444; + attr->attr.show = perf_event_sysfs_show; + attr->event_str = str; + + return ++attr; +} + +static struct attribute ** +create_event_attributes(struct drm_i915_private *i915) +{ + static const struct { + u64 config; + const char *name; + const char *unit; + } events[] = { + __event(I915_PMU_ACTUAL_FREQUENCY, "actual-frequency", "MHz"), + __event(I915_PMU_REQUESTED_FREQUENCY, "requested-frequency", "MHz"), + __event(I915_PMU_INTERRUPTS, "interrupts", NULL), + __event(I915_PMU_RC6_RESIDENCY, "rc6-residency", "ns"), + }; + static const struct { + enum drm_i915_pmu_engine_sample sample; + char *name; + } engine_events[] = { + __engine_event(I915_SAMPLE_BUSY, "busy"), + __engine_event(I915_SAMPLE_SEMA, "sema"), + __engine_event(I915_SAMPLE_WAIT, "wait"), + }; + unsigned int count = 0; + struct perf_pmu_events_attr *pmu_attr = NULL, *pmu_iter; + struct i915_ext_attribute *i915_attr = NULL, *i915_iter; + struct attribute **attr = NULL, **attr_iter; + struct intel_engine_cs *engine; + enum intel_engine_id id; + unsigned int i; + + /* Count how many counters we will be exposing. */ + for (i = 0; i < ARRAY_SIZE(events); i++) { + if (!config_status(i915, events[i].config)) + count++; + } + + for_each_engine(engine, i915, id) { + for (i = 0; i < ARRAY_SIZE(engine_events); i++) { + if (!engine_event_status(engine, + engine_events[i].sample)) + count++; + } + } + + /* Allocate attribute objects and table. */ + i915_attr = kzalloc(count * sizeof(*i915_attr), GFP_KERNEL); + if (!i915_attr) + goto err_alloc; + + pmu_attr = kzalloc(count * sizeof(*pmu_attr), GFP_KERNEL); + if (!pmu_attr) + goto err_alloc; + + /* Max one pointer of each attribute type plus a termination entry. */ + attr = kzalloc((count * 2 + 1) * sizeof(attr), GFP_KERNEL); + if (!attr) + goto err_alloc; + + i915_iter = i915_attr; + pmu_iter = pmu_attr; + attr_iter = attr; + + /* Initialize supported non-engine counters. */ + for (i = 0; i < ARRAY_SIZE(events); i++) { + char *str; + + if (config_status(i915, events[i].config)) + continue; + + str = kstrdup(events[i].name, GFP_KERNEL); + if (!str) + goto err; + + *attr_iter++ = &i915_iter->attr.attr; + i915_iter = add_i915_attr(i915_iter, str, events[i].config); + + if (events[i].unit) { + str = kasprintf(GFP_KERNEL, "%s.unit", events[i].name); + if (!str) + goto err; + + *attr_iter++ = &pmu_iter->attr.attr; + pmu_iter = add_pmu_attr(pmu_iter, str, events[i].unit); + } + } + + /* Initialize supported engine counters. */ + for_each_engine(engine, i915, id) { + for (i = 0; i < ARRAY_SIZE(engine_events); i++) { + char *str; + + if (engine_event_status(engine, + engine_events[i].sample)) + continue; + + str = kasprintf(GFP_KERNEL, "%s-%s", + engine->name, engine_events[i].name); + if (!str) + goto err; + + *attr_iter++ = &i915_iter->attr.attr; + i915_iter = + add_i915_attr(i915_iter, str, + __I915_PMU_ENGINE(engine->class, + engine->instance, + engine_events[i].sample)); + + str = kasprintf(GFP_KERNEL, "%s-%s.unit", + engine->name, engine_events[i].name); + if (!str) + goto err; + + *attr_iter++ = &pmu_iter->attr.attr; + pmu_iter = add_pmu_attr(pmu_iter, str, "ns"); + } + } + + i915->pmu.i915_attr = i915_attr; + i915->pmu.pmu_attr = pmu_attr; + + return attr; + +err:; + for (attr_iter = attr; *attr_iter; attr_iter++) + kfree((*attr_iter)->name); + +err_alloc: + kfree(attr); + kfree(i915_attr); + kfree(pmu_attr); + + return NULL; +} + +static void free_event_attributes(struct drm_i915_private *i915) +{ + struct attribute **attr_iter = i915_pmu_events_attr_group.attrs; + + for (; *attr_iter; attr_iter++) + kfree((*attr_iter)->name); + + kfree(i915_pmu_events_attr_group.attrs); + kfree(i915->pmu.i915_attr); + kfree(i915->pmu.pmu_attr); + + i915_pmu_events_attr_group.attrs = NULL; + i915->pmu.i915_attr = NULL; + i915->pmu.pmu_attr = NULL; +} + static int i915_pmu_cpu_online(unsigned int cpu, struct hlist_node *node) { struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), node); @@ -806,6 +963,12 @@ void i915_pmu_register(struct drm_i915_private *i915) return; } + i915_pmu_events_attr_group.attrs = create_event_attributes(i915); + if (!i915_pmu_events_attr_group.attrs) { + ret = -ENOMEM; + goto err; + } + i915->pmu.base.attr_groups = i915_pmu_attr_groups; i915->pmu.base.task_ctx_nr = perf_invalid_context; i915->pmu.base.event_init = i915_pmu_event_init; @@ -838,6 +1001,7 @@ err_unreg: perf_pmu_unregister(&i915->pmu.base); err: i915->pmu.base.event_init = NULL; + free_event_attributes(i915); DRM_NOTE("Failed to register PMU! (err=%d)\n", ret); } @@ -862,4 +1026,5 @@ void i915_pmu_unregister(struct drm_i915_private *i915) perf_pmu_unregister(&i915->pmu.base); i915->pmu.base.event_init = NULL; + free_event_attributes(i915); } diff --git a/drivers/gpu/drm/i915/i915_pmu.h b/drivers/gpu/drm/i915/i915_pmu.h index 40c154d13565..5a2e013a56bb 100644 --- a/drivers/gpu/drm/i915/i915_pmu.h +++ b/drivers/gpu/drm/i915/i915_pmu.h @@ -94,6 +94,14 @@ struct i915_pmu { * struct intel_engine_cs. */ struct i915_pmu_sample sample[__I915_NUM_PMU_SAMPLERS]; + /** + * @i915_attr: Memory block holding device attributes. + */ + void *i915_attr; + /** + * @pmu_attr: Memory block holding device attributes. + */ + void *pmu_attr; }; #ifdef CONFIG_PERF_EVENTS From 2bbba4e94eb987701abcacae241929fd13a196b2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 11 Jan 2018 14:04:02 +0000 Subject: [PATCH 029/158] drm/i915/pmu: Initialise our dynamic sysfs attributes for use with lockdep As we kmalloc our dynamic sysfs attributes, we have to give them an external static lock_class_key for them to use with lockdep. Fixes: 109ec558370f ("drm/i915/pmu: Only enumerate available counters in sysfs") Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180111140402.3984-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_pmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 9139bc8df82b..95ab5e28f5be 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -719,6 +719,7 @@ static const struct attribute_group *i915_pmu_attr_groups[] = { static struct i915_ext_attribute * add_i915_attr(struct i915_ext_attribute *attr, const char *name, u64 config) { + sysfs_attr_init(&attr->attr.attr); attr->attr.attr.name = name; attr->attr.attr.mode = 0444; attr->attr.show = i915_pmu_event_show; @@ -731,6 +732,7 @@ static struct perf_pmu_events_attr * add_pmu_attr(struct perf_pmu_events_attr *attr, const char *name, const char *str) { + sysfs_attr_init(&attr->attr.attr); attr->attr.attr.name = name; attr->attr.attr.mode = 0444; attr->attr.show = perf_event_sysfs_show; From 4900727d35bb20028f9bd83146ec4bf78afffe30 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 11 Jan 2018 07:30:31 +0000 Subject: [PATCH 030/158] drm/i915/pmu: Reconstruct active state on starting busy-stats We have a hole in our busy-stat accounting if the pmu is enabled during a long running batch, the pmu will not start accumulating busy-time until the next context switch. This then fails tests that are only sampling a single batch. v2: Count each active port just once (context in/out events are only on the first and last assignment to a port). v3: Avoid hardcoding knowledge of 2 submission ports Fixes: 30e17b7847f5 ("drm/i915: Engine busy time tracking") Testcase: igt/perf_pmu/busy-start Testcase: igt/perf_pmu/busy-double-start Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180111073031.14614-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 6bb51a502b8b..d790bdc227ff 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1951,8 +1951,22 @@ int intel_enable_engine_stats(struct intel_engine_cs *engine) spin_lock_irqsave(&engine->stats.lock, flags); if (engine->stats.enabled == ~0) goto busy; - if (engine->stats.enabled++ == 0) + if (engine->stats.enabled++ == 0) { + struct intel_engine_execlists *execlists = &engine->execlists; + const struct execlist_port *port = execlists->port; + unsigned int num_ports = execlists_num_ports(execlists); + engine->stats.enabled_at = ktime_get(); + + /* XXX submission method oblivious? */ + while (num_ports-- && port_isset(port)) { + engine->stats.active++; + port++; + } + + if (engine->stats.active) + engine->stats.start = engine->stats.enabled_at; + } spin_unlock_irqrestore(&engine->stats.lock, flags); return 0; From 4c501230846b99ad78435637500471caa77a65c8 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Fri, 12 Jan 2018 17:03:39 +0000 Subject: [PATCH 031/158] drm/i915/pmu: fix noderef.cocci warnings drivers/gpu/drm/i915/i915_pmu.c:795:34-40: ERROR: application of sizeof to pointer sizeof when applied to a pointer typed expression gives the size of the pointer Generated by: scripts/coccinelle/misc/noderef.cocci Fixes: 109ec558370f ("drm/i915/pmu: Only enumerate available counters in sysfs") Signed-off-by: Fengguang Wu Reviewed-by: Tvrtko Ursulin Signed-off-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180112170340.5387-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 95ab5e28f5be..9be4f5201e41 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -794,7 +794,7 @@ create_event_attributes(struct drm_i915_private *i915) goto err_alloc; /* Max one pointer of each attribute type plus a termination entry. */ - attr = kzalloc((count * 2 + 1) * sizeof(attr), GFP_KERNEL); + attr = kzalloc((count * 2 + 1) * sizeof(*attr), GFP_KERNEL); if (!attr) goto err_alloc; From dd5fec87efdd54db6870b5d24c1fd3cda94f4510 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 12 Jan 2018 17:03:40 +0000 Subject: [PATCH 032/158] drm/i915/pmu: Use kcalloc instead of kzalloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kcalloc is preffered for allocating arrays. Signed-off-by: Tvrtko Ursulin Suggested-by: Ville Syrjälä Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180112170340.5387-2-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 9be4f5201e41..065a28c713c4 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -785,16 +785,16 @@ create_event_attributes(struct drm_i915_private *i915) } /* Allocate attribute objects and table. */ - i915_attr = kzalloc(count * sizeof(*i915_attr), GFP_KERNEL); + i915_attr = kcalloc(count, sizeof(*i915_attr), GFP_KERNEL); if (!i915_attr) goto err_alloc; - pmu_attr = kzalloc(count * sizeof(*pmu_attr), GFP_KERNEL); + pmu_attr = kcalloc(count, sizeof(*pmu_attr), GFP_KERNEL); if (!pmu_attr) goto err_alloc; /* Max one pointer of each attribute type plus a termination entry. */ - attr = kzalloc((count * 2 + 1) * sizeof(*attr), GFP_KERNEL); + attr = kcalloc(count * 2 + 1, sizeof(*attr), GFP_KERNEL); if (!attr) goto err_alloc; From 457f1e5f47024793c7b4095e6647ce48ea0bf697 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Wed, 3 Jan 2018 13:38:22 -0800 Subject: [PATCH 033/158] drm/i915/psr: Kill psr.source_ok flag. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This flag has become redundant since commit 4d90f2d507ab ("drm/i915: Start tracking PSR state in crtc state") It is set at the same place as psr.enabled, which is also exposed via debugfs. Cc: Rodrigo Vivi Cc: Ville Syrjälä Signed-off-by: Dhinakaran Pandiyan Acked-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180103213824.1405-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 1 - drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_psr.c | 2 -- 3 files changed, 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 2bb63073d73f..6890340387b7 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2529,7 +2529,6 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) mutex_lock(&dev_priv->psr.lock); seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support)); - seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok)); seq_printf(m, "Enabled: %s\n", yesno((bool)dev_priv->psr.enabled)); seq_printf(m, "Active: %s\n", yesno(dev_priv->psr.active)); seq_printf(m, "Busy frontbuffer bits: 0x%03x\n", diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index caebd5825279..cb1b69e7f439 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -754,7 +754,6 @@ struct i915_drrs { struct i915_psr { struct mutex lock; bool sink_support; - bool source_ok; struct intel_dp *enabled; bool active; struct delayed_work work; diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 2e32615eeada..17636dce1cb0 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -522,8 +522,6 @@ void intel_psr_enable(struct intel_dp *intel_dp, } dev_priv->psr.psr2_support = crtc_state->has_psr2; - dev_priv->psr.source_ok = true; - dev_priv->psr.busy_frontbuffer_bits = 0; dev_priv->psr.setup_vsc(intel_dp, crtc_state); From 4371d89601c301fdbbdb9616c887ae77b38f6404 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Wed, 3 Jan 2018 13:38:23 -0800 Subject: [PATCH 034/158] drm/i915/psr: CAN_PSR() macro to check for PSR source and sink support. The global variable dev_priv->psr.sink_support is set if an eDP sink supports PSR. Use this instead of redoing the check with is_edp_psr(). Combine source and sink support checks into a macro that can be used to return early from psr_{invalidate, single_frame_update, flush}. Cc: Rodrigo Vivi Signed-off-by: Dhinakaran Pandiyan Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180103213824.1405-2-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_psr.c | 19 ++++--------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 30f791f89d64..48676e99316e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1760,6 +1760,7 @@ static inline void intel_backlight_device_unregister(struct intel_connector *con /* intel_psr.c */ +#define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support) void intel_psr_enable(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state); void intel_psr_disable(struct intel_dp *intel_dp, diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 17636dce1cb0..df9b1d7baefb 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -56,14 +56,6 @@ #include "intel_drv.h" #include "i915_drv.h" -static bool is_edp_psr(struct intel_dp *intel_dp) -{ - if (!intel_dp_is_edp(intel_dp)) - return false; - - return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED; -} - static bool vlv_is_psr_active_on_pipe(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = to_i915(dev); @@ -358,10 +350,7 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, &crtc_state->base.adjusted_mode; int psr_setup_time; - if (!HAS_PSR(dev_priv)) - return; - - if (!is_edp_psr(intel_dp)) + if (!CAN_PSR(dev_priv)) return; if (!i915_modparams.enable_psr) { @@ -794,7 +783,7 @@ void intel_psr_single_frame_update(struct drm_i915_private *dev_priv, enum pipe pipe; u32 val; - if (!HAS_PSR(dev_priv)) + if (!CAN_PSR(dev_priv)) return; /* @@ -843,7 +832,7 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv, struct drm_crtc *crtc; enum pipe pipe; - if (!HAS_PSR(dev_priv)) + if (!CAN_PSR(dev_priv)) return; mutex_lock(&dev_priv->psr.lock); @@ -883,7 +872,7 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, struct drm_crtc *crtc; enum pipe pipe; - if (!HAS_PSR(dev_priv)) + if (!CAN_PSR(dev_priv)) return; mutex_lock(&dev_priv->psr.lock); From c9ef291a7e79ebc9fb1723090c12fae626e74c46 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Wed, 3 Jan 2018 13:38:24 -0800 Subject: [PATCH 035/158] drm/i915/psr: Avoid initializing PSR if there is no sink support. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DPCD read for the eDP is complete by the time intel_psr_init() is called, which means we can avoid initializing PSR structures and state if there is no sink support. Cc: Rodrigo Vivi Cc: Ville Syrjälä Signed-off-by: Dhinakaran Pandiyan Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180103213824.1405-3-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 7 ++++++- drivers/gpu/drm/i915/intel_psr.c | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 6890340387b7..cc659b4b2a45 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2521,14 +2521,19 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) u32 stat[3]; enum pipe pipe; bool enabled = false; + bool sink_support; if (!HAS_PSR(dev_priv)) return -ENODEV; + sink_support = dev_priv->psr.sink_support; + seq_printf(m, "Sink_Support: %s\n", yesno(sink_support)); + if (!sink_support) + return 0; + intel_runtime_pm_get(dev_priv); mutex_lock(&dev_priv->psr.lock); - seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support)); seq_printf(m, "Enabled: %s\n", yesno((bool)dev_priv->psr.enabled)); seq_printf(m, "Active: %s\n", yesno(dev_priv->psr.active)); seq_printf(m, "Busy frontbuffer bits: 0x%03x\n", diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index df9b1d7baefb..863650366425 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -503,6 +503,9 @@ void intel_psr_enable(struct intel_dp *intel_dp, if (!crtc_state->has_psr) return; + if (WARN_ON(!CAN_PSR(dev_priv))) + return; + WARN_ON(dev_priv->drrs.dp); mutex_lock(&dev_priv->psr.lock); if (dev_priv->psr.enabled) { @@ -633,6 +636,9 @@ void intel_psr_disable(struct intel_dp *intel_dp, if (!old_crtc_state->has_psr) return; + if (WARN_ON(!CAN_PSR(dev_priv))) + return; + mutex_lock(&dev_priv->psr.lock); if (!dev_priv->psr.enabled) { mutex_unlock(&dev_priv->psr.lock); @@ -913,6 +919,9 @@ void intel_psr_init(struct drm_i915_private *dev_priv) dev_priv->psr_mmio_base = IS_HASWELL(dev_priv) ? HSW_EDP_PSR_BASE : BDW_EDP_PSR_BASE; + if (!dev_priv->psr.sink_support) + return; + /* Per platform default: all disabled. */ if (i915_modparams.enable_psr == -1) i915_modparams.enable_psr = 0; From c32164b1f6a2eafa0658bbf33d02b2da41c72e5a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2018 09:06:42 +0000 Subject: [PATCH 036/158] drm/i915: Only defer freeing of fence callback when also using the timer Without an accompanying timer (for internal fences), we can free the fence callback immediately as we do not need to employ the RCU barrier to serialise with the timer. By avoiding the RCU delay, we can avoid the extra mempressure under heavy inter-engine request utilisation. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180115090643.26696-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_sw_fence.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c index 3669f5eeb91e..13021326d777 100644 --- a/drivers/gpu/drm/i915/i915_sw_fence.c +++ b/drivers/gpu/drm/i915/i915_sw_fence.c @@ -398,7 +398,12 @@ static void dma_i915_sw_fence_wake(struct dma_fence *dma, if (fence) i915_sw_fence_complete(fence); - irq_work_queue(&cb->work); + if (cb->dma) { + irq_work_queue(&cb->work); + return; + } + + kfree(cb); } static void irq_i915_sw_fence_work(struct irq_work *wrk) @@ -437,10 +442,12 @@ int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence, i915_sw_fence_await(fence); cb->dma = NULL; - timer_setup(&cb->timer, timer_i915_sw_fence_wake, TIMER_IRQSAFE); - init_irq_work(&cb->work, irq_i915_sw_fence_work); if (timeout) { cb->dma = dma_fence_get(dma); + init_irq_work(&cb->work, irq_i915_sw_fence_work); + + timer_setup(&cb->timer, + timer_i915_sw_fence_wake, TIMER_IRQSAFE); mod_timer(&cb->timer, round_jiffies_up(jiffies + timeout)); } From f255c1e91e333ba0bd177120748f4caf294b812b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2018 09:06:43 +0000 Subject: [PATCH 037/158] drm/i915/fence: Separate timeout mechanism for awaiting on dma-fences As the timeout mechanism has grown more and more complicated, using multiple deferred tasks and more than doubling the size of our struct, split the two implementations to streamline the simpler no-timeout callback variant. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180115090643.26696-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_sw_fence.c | 61 ++++++++++++++++++---------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c index 13021326d777..1de5173e53a2 100644 --- a/drivers/gpu/drm/i915/i915_sw_fence.c +++ b/drivers/gpu/drm/i915/i915_sw_fence.c @@ -365,18 +365,31 @@ int i915_sw_fence_await_sw_fence_gfp(struct i915_sw_fence *fence, struct i915_sw_dma_fence_cb { struct dma_fence_cb base; struct i915_sw_fence *fence; +}; + +struct i915_sw_dma_fence_cb_timer { + struct i915_sw_dma_fence_cb base; struct dma_fence *dma; struct timer_list timer; struct irq_work work; struct rcu_head rcu; }; +static void dma_i915_sw_fence_wake(struct dma_fence *dma, + struct dma_fence_cb *data) +{ + struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base); + + i915_sw_fence_complete(cb->fence); + kfree(cb); +} + static void timer_i915_sw_fence_wake(struct timer_list *t) { - struct i915_sw_dma_fence_cb *cb = from_timer(cb, t, timer); + struct i915_sw_dma_fence_cb_timer *cb = from_timer(cb, t, timer); struct i915_sw_fence *fence; - fence = xchg(&cb->fence, NULL); + fence = xchg(&cb->base.fence, NULL); if (!fence) return; @@ -388,27 +401,24 @@ static void timer_i915_sw_fence_wake(struct timer_list *t) i915_sw_fence_complete(fence); } -static void dma_i915_sw_fence_wake(struct dma_fence *dma, - struct dma_fence_cb *data) +static void dma_i915_sw_fence_wake_timer(struct dma_fence *dma, + struct dma_fence_cb *data) { - struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base); + struct i915_sw_dma_fence_cb_timer *cb = + container_of(data, typeof(*cb), base.base); struct i915_sw_fence *fence; - fence = xchg(&cb->fence, NULL); + fence = xchg(&cb->base.fence, NULL); if (fence) i915_sw_fence_complete(fence); - if (cb->dma) { - irq_work_queue(&cb->work); - return; - } - - kfree(cb); + irq_work_queue(&cb->work); } static void irq_i915_sw_fence_work(struct irq_work *wrk) { - struct i915_sw_dma_fence_cb *cb = container_of(wrk, typeof(*cb), work); + struct i915_sw_dma_fence_cb_timer *cb = + container_of(wrk, typeof(*cb), work); del_timer_sync(&cb->timer); dma_fence_put(cb->dma); @@ -422,6 +432,7 @@ int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence, gfp_t gfp) { struct i915_sw_dma_fence_cb *cb; + dma_fence_func_t func; int ret; debug_fence_assert(fence); @@ -430,7 +441,10 @@ int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence, if (dma_fence_is_signaled(dma)) return 0; - cb = kmalloc(sizeof(*cb), gfp); + cb = kmalloc(timeout ? + sizeof(struct i915_sw_dma_fence_cb_timer) : + sizeof(struct i915_sw_dma_fence_cb), + gfp); if (!cb) { if (!gfpflags_allow_blocking(gfp)) return -ENOMEM; @@ -441,21 +455,26 @@ int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence, cb->fence = fence; i915_sw_fence_await(fence); - cb->dma = NULL; + func = dma_i915_sw_fence_wake; if (timeout) { - cb->dma = dma_fence_get(dma); - init_irq_work(&cb->work, irq_i915_sw_fence_work); + struct i915_sw_dma_fence_cb_timer *timer = + container_of(cb, typeof(*timer), base); - timer_setup(&cb->timer, + timer->dma = dma_fence_get(dma); + init_irq_work(&timer->work, irq_i915_sw_fence_work); + + timer_setup(&timer->timer, timer_i915_sw_fence_wake, TIMER_IRQSAFE); - mod_timer(&cb->timer, round_jiffies_up(jiffies + timeout)); + mod_timer(&timer->timer, round_jiffies_up(jiffies + timeout)); + + func = dma_i915_sw_fence_wake_timer; } - ret = dma_fence_add_callback(dma, &cb->base, dma_i915_sw_fence_wake); + ret = dma_fence_add_callback(dma, &cb->base, func); if (ret == 0) { ret = 1; } else { - dma_i915_sw_fence_wake(dma, &cb->base); + func(dma, &cb->base); if (ret == -ENOENT) /* fence already signaled */ ret = 0; } From 99e48bf98dd036090b480a12c39e8b971731247e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2018 09:20:41 +0000 Subject: [PATCH 038/158] drm/i915: Lock out execlist tasklet while peeking inside for busy-stats In order to prevent a race condition where we may end up overaccounting the active state and leaving the busy-stats believing the GPU is 100% busy, lock out the tasklet while we reconstruct the busy state. There is no direct spinlock guard for the execlists->port[], so we need to utilise tasklet_disable() as a synchronous barrier to prevent it, the only writer to execlists->port[], from running at the same time as the enable. Fixes: 4900727d35bb ("drm/i915/pmu: Reconstruct active state on starting busy-stats") Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180115092041.13509-1-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/intel_engine_cs.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index d790bdc227ff..b221610f2365 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1943,16 +1943,22 @@ intel_engine_lookup_user(struct drm_i915_private *i915, u8 class, u8 instance) */ int intel_enable_engine_stats(struct intel_engine_cs *engine) { + struct intel_engine_execlists *execlists = &engine->execlists; unsigned long flags; + int err = 0; if (!intel_engine_supports_stats(engine)) return -ENODEV; + tasklet_disable(&execlists->tasklet); spin_lock_irqsave(&engine->stats.lock, flags); - if (engine->stats.enabled == ~0) - goto busy; + + if (unlikely(engine->stats.enabled == ~0)) { + err = -EBUSY; + goto unlock; + } + if (engine->stats.enabled++ == 0) { - struct intel_engine_execlists *execlists = &engine->execlists; const struct execlist_port *port = execlists->port; unsigned int num_ports = execlists_num_ports(execlists); @@ -1967,14 +1973,12 @@ int intel_enable_engine_stats(struct intel_engine_cs *engine) if (engine->stats.active) engine->stats.start = engine->stats.enabled_at; } + +unlock: spin_unlock_irqrestore(&engine->stats.lock, flags); + tasklet_enable(&execlists->tasklet); - return 0; - -busy: - spin_unlock_irqrestore(&engine->stats.lock, flags); - - return -EBUSY; + return err; } static ktime_t __intel_engine_get_busy_time(struct intel_engine_cs *engine) From beacbd16158a583dc22104d59ea9ac0a808be73f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2018 12:28:45 +0000 Subject: [PATCH 039/158] drm/i915: Use our singlethreaded wq for freeing objects As freeing the objects require serialisation on struct_mutex, we should prefer to use our singlethreaded driver wq that is dedicated to work requiring struct_mutex (hence serialised).The benefit should be less clutter on the system wq, allowing it to make progress even when the driver/struct_mutex is heavily contended. Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180115122846.15193-1-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1135a77b383a..87937c4f9dff 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4732,7 +4732,7 @@ static void __i915_gem_free_object_rcu(struct rcu_head *head) * detour through a worker. */ if (llist_add(&obj->freed, &i915->mm.free_list)) - schedule_work(&i915->mm.free_work); + queue_work(i915->wq, &i915->mm.free_work); } void i915_gem_free_object(struct drm_gem_object *gem_obj) From 2aa472c8279a0eea4649283fd1266cb629b8a5d3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2018 20:43:48 +0000 Subject: [PATCH 040/158] drm/i915/selftests: Test i915_sw_fence/dma_fence interop Check that we can successfully wait upon a dma_fence using the i915_sw_fence, including the optional timeout mechanism. v2: Account for the rounding up of the timeout to the next second. Unfortunately, the minimum delay is then 1 second. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180115204348.8480-1-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin --- .../gpu/drm/i915/selftests/i915_sw_fence.c | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c index ea01d0fe3ace..4fb51deb81a1 100644 --- a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c +++ b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c @@ -606,6 +606,141 @@ err: return -EINVAL; } +static const char *mock_name(struct dma_fence *fence) +{ + return "mock"; +} + +static bool mock_enable_signaling(struct dma_fence *fence) +{ + return true; +} + +static const struct dma_fence_ops mock_fence_ops = { + .get_driver_name = mock_name, + .get_timeline_name = mock_name, + .enable_signaling = mock_enable_signaling, + .wait = dma_fence_default_wait, + .release = dma_fence_free, +}; + +static DEFINE_SPINLOCK(mock_fence_lock); + +static struct dma_fence *alloc_dma_fence(void) +{ + struct dma_fence *dma; + + dma = kmalloc(sizeof(*dma), GFP_KERNEL); + if (dma) + dma_fence_init(dma, &mock_fence_ops, &mock_fence_lock, 0, 0); + + return dma; +} + +static struct i915_sw_fence * +wrap_dma_fence(struct dma_fence *dma, unsigned long delay) +{ + struct i915_sw_fence *fence; + int err; + + fence = alloc_fence(); + if (!fence) + return ERR_PTR(-ENOMEM); + + err = i915_sw_fence_await_dma_fence(fence, dma, delay, GFP_NOWAIT); + i915_sw_fence_commit(fence); + if (err < 0) { + free_fence(fence); + return ERR_PTR(err); + } + + return fence; +} + +static int test_dma_fence(void *arg) +{ + struct i915_sw_fence *timeout = NULL, *not = NULL; + unsigned long delay = i915_selftest.timeout_jiffies; + unsigned long end, sleep; + struct dma_fence *dma; + int err; + + dma = alloc_dma_fence(); + if (!dma) + return -ENOMEM; + + timeout = wrap_dma_fence(dma, delay); + if (IS_ERR(timeout)) { + err = PTR_ERR(timeout); + goto err; + } + + not = wrap_dma_fence(dma, 0); + if (IS_ERR(not)) { + err = PTR_ERR(not); + goto err; + } + + err = -EINVAL; + if (i915_sw_fence_done(timeout) || i915_sw_fence_done(not)) { + pr_err("Fences immediately signaled\n"); + goto err; + } + + /* We round the timeout for the fence up to the next second */ + end = round_jiffies_up(jiffies + delay); + + sleep = jiffies_to_usecs(delay) / 3; + usleep_range(sleep, 2 * sleep); + if (time_after(jiffies, end)) { + pr_debug("Slept too long, delay=%lu, skipping!\n", delay); + goto skip; + } + + if (i915_sw_fence_done(timeout) || i915_sw_fence_done(not)) { + pr_err("Fences signaled too early\n"); + goto err; + } + + do { + sleep = jiffies_to_usecs(end - jiffies + 1); + usleep_range(sleep, 2 * sleep); + } while (!time_after(jiffies, end)); + + if (i915_sw_fence_done(not)) { + pr_err("No timeout fence signaled!\n"); + goto err; + } + + if (!i915_sw_fence_done(timeout)) { + pr_err("Timeout fence unsignaled!\n"); + goto err; + } + +skip: + dma_fence_signal(dma); + + if (!i915_sw_fence_done(timeout) || !i915_sw_fence_done(not)) { + pr_err("Fences unsignaled\n"); + goto err; + } + + free_fence(not); + free_fence(timeout); + dma_fence_put(dma); + + return 0; + +err: + dma_fence_signal(dma); + if (!IS_ERR_OR_NULL(timeout)) + free_fence(timeout); + if (!IS_ERR_OR_NULL(not)) + free_fence(not); + dma_fence_put(dma); + return err; +} + int i915_sw_fence_mock_selftests(void) { static const struct i915_subtest tests[] = { @@ -618,6 +753,7 @@ int i915_sw_fence_mock_selftests(void) SUBTEST(test_chain), SUBTEST(test_ipc), SUBTEST(test_timer), + SUBTEST(test_dma_fence), }; return i915_subtests(tests, NULL); From 2ef1e729c7f0fbad9706848f5fe5cff84f5b6d24 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2018 20:57:59 +0000 Subject: [PATCH 041/158] drm/i915: Rewrite some comments around RCU-deferred object free Tvrtko noticed that the comments describing the interaction of RCU and the deferred worker for freeing drm_i915_gem_object were a little confusing, so attempt to bring some sense to them. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180115205759.13884-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 87937c4f9dff..b2ba685cb144 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4699,7 +4699,8 @@ static void __i915_gem_free_work(struct work_struct *work) container_of(work, struct drm_i915_private, mm.free_work); struct llist_node *freed; - /* All file-owned VMA should have been released by this point through + /* + * All file-owned VMA should have been released by this point through * i915_gem_close_object(), or earlier by i915_gem_context_close(). * However, the object may also be bound into the global GTT (e.g. * older GPUs without per-process support, or for direct access through @@ -4726,10 +4727,15 @@ static void __i915_gem_free_object_rcu(struct rcu_head *head) container_of(head, typeof(*obj), rcu); struct drm_i915_private *i915 = to_i915(obj->base.dev); - /* We can't simply use call_rcu() from i915_gem_free_object() - * as we need to block whilst unbinding, and the call_rcu - * task may be called from softirq context. So we take a - * detour through a worker. + /* + * Since we require blocking on struct_mutex to unbind the freed + * object from the GPU before releasing resources back to the + * system, we can not do that directly from the RCU callback (which may + * be a softirq context), but must instead then defer that work onto a + * kthread. We use the RCU callback rather than move the freed object + * directly onto the work queue so that we can mix between using the + * worker and performing frees directly from subsequent allocations for + * crude but effective memory throttling. */ if (llist_add(&obj->freed, &i915->mm.free_list)) queue_work(i915->wq, &i915->mm.free_work); @@ -4745,7 +4751,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) if (discard_backing_storage(obj)) obj->mm.madv = I915_MADV_DONTNEED; - /* Before we free the object, make sure any pure RCU-only + /* + * Before we free the object, make sure any pure RCU-only * read-side critical sections are complete, e.g. * i915_gem_busy_ioctl(). For the corresponding synchronized * lookup see i915_gem_object_lookup_rcu(). From ac25dfed15d470d7f23dd817e965b54aa3f94a1e Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 16 Jan 2018 16:53:24 +0100 Subject: [PATCH 042/158] drm/i915: Always call to intel_display_set_init_power() in resume_early. intel_power_domains_init_hw() calls set_init_power, but when using runtime power management this call is skipped. This prevents hw readout from taking place. Signed-off-by: Maarten Lankhorst Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104172 Link: https://patchwork.freedesktop.org/patch/msgid/20180116155324.75120-1-maarten.lankhorst@linux.intel.com Fixes: bc87229f323e ("drm/i915/skl: enable PC9/10 power states during suspend-to-idle") Cc: Nivedita Swaminathan Cc: Imre Deak Cc: Patrik Jakobsson Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: # v4.5+ Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 6c8da9d20c33..173d0095e3b2 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1842,6 +1842,8 @@ static int i915_drm_resume_early(struct drm_device *dev) if (IS_GEN9_LP(dev_priv) || !(dev_priv->suspended_to_idle && dev_priv->csr.dmc_payload)) intel_power_domains_init_hw(dev_priv, true); + else + intel_display_set_init_power(dev_priv, true); i915_gem_sanitize(dev_priv); From 3f5b933e60506452ea4f83d8a436607cb1c8fa24 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 16 Jan 2018 16:53:31 +0100 Subject: [PATCH 043/158] drm/i915: Do not WARN_ON with small framebuffers. It's perfectly legal to create a fb with stride < 512, and one of the kms_plane_scaling subtests creates a very small fb. Downgrade the WARN_ON to a simple check check, and because this function is potentially called on every atomic update/pageflip, downgrade the other WARN_ON to a WARN_ON_ONCE, and do the right thing here. Cc: Paulo Zanoni Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20180116155331.75175-1-maarten.lankhorst@linux.intel.com Reviewed-by: Rodrigo Vivi --- drivers/gpu/drm/i915/intel_fbc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index f88c1b5dae4c..9dc2b8b5f2db 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -668,11 +668,13 @@ void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv) static bool stride_is_valid(struct drm_i915_private *dev_priv, unsigned int stride) { - /* These should have been caught earlier. */ - WARN_ON(stride < 512); - WARN_ON((stride & (64 - 1)) != 0); + /* This should have been caught earlier. */ + if (WARN_ON_ONCE((stride & (64 - 1)) != 0)) + return false; /* Below are the additional FBC restrictions. */ + if (stride < 512) + return false; if (IS_GEN2(dev_priv) || IS_GEN3(dev_priv)) return stride == 4096 || stride == 8192; From ba02f4c26b37102ab030aa81d42d8021c81a43ab Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 17 Jan 2018 13:57:13 +0000 Subject: [PATCH 044/158] drm/i915/selftests: Wait for the dma-fence timeout When testing that the timeout fired, we need to be sure we have waited just long enough for the timeout to have occurred and for the softirq (on another cpu) to have completed. Sleeping for an arbitrary amount is prone to error, so wait for the timeout instead and complain if it was too late. v2: Use wait_event_timeout to provide an upper bound v3: Fix inverted check for wait_event_timeout timing out v4: Restore the check that the fences aren't signalled too early, by inspecting them before the expected timeout. References: https://bugs.freedesktop.org/show_bug.cgi?id=104670 Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180117135713.2324-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_sw_fence.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c index 4fb51deb81a1..570e325af93e 100644 --- a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c +++ b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c @@ -693,7 +693,8 @@ static int test_dma_fence(void *arg) sleep = jiffies_to_usecs(delay) / 3; usleep_range(sleep, 2 * sleep); if (time_after(jiffies, end)) { - pr_debug("Slept too long, delay=%lu, skipping!\n", delay); + pr_debug("Slept too long, delay=%lu, (target=%lu, now=%lu) skipping\n", + delay, end, jiffies); goto skip; } @@ -702,18 +703,15 @@ static int test_dma_fence(void *arg) goto err; } - do { - sleep = jiffies_to_usecs(end - jiffies + 1); - usleep_range(sleep, 2 * sleep); - } while (!time_after(jiffies, end)); - - if (i915_sw_fence_done(not)) { - pr_err("No timeout fence signaled!\n"); + if (!wait_event_timeout(timeout->wait, + i915_sw_fence_done(timeout), + 2 * (end - jiffies) + 1)) { + pr_err("Timeout fence unsignaled!\n"); goto err; } - if (!i915_sw_fence_done(timeout)) { - pr_err("Timeout fence unsignaled!\n"); + if (i915_sw_fence_done(not)) { + pr_err("No timeout fence signaled!\n"); goto err; } From c6270dbce9b01b465875ee4200623887f9399a21 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 Jan 2018 16:48:53 +0100 Subject: [PATCH 045/158] drm: i915: remove timeval users struct timeval is deprecated because it cannot represent times past 2038. In this driver, the only use of this structure is to capture debug information. This is easily changed to ktime_t, which we then format as needed when printing it later. Reviewed-by: Chris Wilson Signed-off-by: Arnd Bergmann Link: https://patchwork.freedesktop.org/patch/msgid/20180117154916.219273-1-arnd@arndb.de Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 6 +++--- drivers/gpu/drm/i915/i915_gpu_error.c | 25 ++++++++++++++----------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cb1b69e7f439..67f6f9ad4446 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -453,9 +453,9 @@ struct intel_display_error_state; struct i915_gpu_state { struct kref ref; - struct timeval time; - struct timeval boottime; - struct timeval uptime; + ktime_t time; + ktime_t boottime; + ktime_t uptime; struct drm_i915_private *i915; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 944059322daa..06577574296b 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -610,6 +610,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, { struct drm_i915_private *dev_priv = m->i915; struct drm_i915_error_object *obj; + struct timespec64 ts; int i, j; if (!error) { @@ -620,12 +621,15 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, if (*error->error_msg) err_printf(m, "%s\n", error->error_msg); err_printf(m, "Kernel: " UTS_RELEASE "\n"); - err_printf(m, "Time: %ld s %ld us\n", - error->time.tv_sec, error->time.tv_usec); - err_printf(m, "Boottime: %ld s %ld us\n", - error->boottime.tv_sec, error->boottime.tv_usec); - err_printf(m, "Uptime: %ld s %ld us\n", - error->uptime.tv_sec, error->uptime.tv_usec); + ts = ktime_to_timespec64(error->time); + err_printf(m, "Time: %lld s %ld us\n", + (s64)ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC); + ts = ktime_to_timespec64(error->boottime); + err_printf(m, "Boottime: %lld s %ld us\n", + (s64)ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC); + ts = ktime_to_timespec64(error->uptime); + err_printf(m, "Uptime: %lld s %ld us\n", + (s64)ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC); for (i = 0; i < ARRAY_SIZE(error->engine); i++) { if (error->engine[i].hangcheck_stalled && @@ -1737,11 +1741,10 @@ static int capture(void *data) { struct i915_gpu_state *error = data; - do_gettimeofday(&error->time); - error->boottime = ktime_to_timeval(ktime_get_boottime()); - error->uptime = - ktime_to_timeval(ktime_sub(ktime_get(), - error->i915->gt.last_init_time)); + error->time = ktime_get_real(); + error->boottime = ktime_get_boottime(); + error->uptime = ktime_sub(ktime_get(), + error->i915->gt.last_init_time); capture_params(error); capture_uc_state(error); From 29d384e34c55d696cf37bd4159e05f4b14d45da0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2018 21:24:46 +0000 Subject: [PATCH 046/158] drm/i915: Only attempt to scan the requested number of shrinker slabs Since commit 4e773c3a8a69 ("drm/i915: Wire up shrinkctl->nr_scanned"), we track the number of objects we scan and do not wish to exceed that as it will overly penalise our own slabs under mempressure. Given that we now know the target number of objects to scan, use that as our guide for deciding to shrink as opposed to the number of objects we manage to shrink (which doesn't correspond to the numbers we report to shrinkctl). Fixes: 4e773c3a8a69 ("drm/i915: Wire up shrinkctl->nr_scanned") Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20180115212455.24046-2-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/i915_gem_shrinker.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index 9029ed04879c..0e158f9287c4 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -363,13 +363,13 @@ i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) I915_SHRINK_BOUND | I915_SHRINK_UNBOUND | I915_SHRINK_PURGEABLE); - if (freed < sc->nr_to_scan) + if (sc->nr_scanned < sc->nr_to_scan) freed += i915_gem_shrink(i915, sc->nr_to_scan - sc->nr_scanned, &sc->nr_scanned, I915_SHRINK_BOUND | I915_SHRINK_UNBOUND); - if (freed < sc->nr_to_scan && current_is_kswapd()) { + if (sc->nr_scanned < sc->nr_to_scan && current_is_kswapd()) { intel_runtime_pm_get(i915); freed += i915_gem_shrink(i915, sc->nr_to_scan - sc->nr_scanned, From b6c51c3e2872b2d133293dd94245b5f39126aaf7 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 17 Jan 2018 19:25:08 +0200 Subject: [PATCH 047/158] drm/i915: Add tracking for CDCLK bypass frequency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CDCLK bypass frequency can vary on upcoming platforms, so prepare for that now by tracking its value in the CDCLK state. Currently on BDW+ the bypass frequency is always the reference clock and I didn't bother with earlier platforms since it's not all that clear what's the bypass clock on those. I also didn't bother adding support for changing this frequency, since atm I don't see any need for it. Suggested-by: Ville Syrjälä Cc: Ville Syrjälä Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180117172508.15993-1-imre.deak@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_cdclk.c | 35 +++++++++++++++--------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 67f6f9ad4446..905d1e32ef6a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1791,7 +1791,7 @@ struct i915_oa_ops { }; struct intel_cdclk_state { - unsigned int cdclk, vco, ref; + unsigned int cdclk, vco, ref, bypass; u8 voltage_level; }; diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index ca36321eafac..f46a61d423a1 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -858,7 +858,7 @@ static void skl_get_cdclk(struct drm_i915_private *dev_priv, skl_dpll0_update(dev_priv, cdclk_state); - cdclk_state->cdclk = cdclk_state->ref; + cdclk_state->cdclk = cdclk_state->bypass = cdclk_state->ref; if (cdclk_state->vco == 0) goto out; @@ -1006,7 +1006,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, /* Choose frequency for this cdclk */ switch (cdclk) { default: - WARN_ON(cdclk != dev_priv->cdclk.hw.ref); + WARN_ON(cdclk != dev_priv->cdclk.hw.bypass); WARN_ON(vco != 0); /* fall through */ case 308571: @@ -1085,7 +1085,7 @@ static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv) /* Is PLL enabled and locked ? */ if (dev_priv->cdclk.hw.vco == 0 || - dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.ref) + dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.bypass) goto sanitize; /* DPLL okay; verify the cdclock @@ -1159,7 +1159,7 @@ void skl_uninit_cdclk(struct drm_i915_private *dev_priv) { struct intel_cdclk_state cdclk_state = dev_priv->cdclk.hw; - cdclk_state.cdclk = cdclk_state.ref; + cdclk_state.cdclk = cdclk_state.bypass; cdclk_state.vco = 0; cdclk_state.voltage_level = skl_calc_voltage_level(cdclk_state.cdclk); @@ -1199,7 +1199,7 @@ static int bxt_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk) { int ratio; - if (cdclk == dev_priv->cdclk.hw.ref) + if (cdclk == dev_priv->cdclk.hw.bypass) return 0; switch (cdclk) { @@ -1224,7 +1224,7 @@ static int glk_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk) { int ratio; - if (cdclk == dev_priv->cdclk.hw.ref) + if (cdclk == dev_priv->cdclk.hw.bypass) return 0; switch (cdclk) { @@ -1268,7 +1268,7 @@ static void bxt_get_cdclk(struct drm_i915_private *dev_priv, bxt_de_pll_update(dev_priv, cdclk_state); - cdclk_state->cdclk = cdclk_state->ref; + cdclk_state->cdclk = cdclk_state->bypass = cdclk_state->ref; if (cdclk_state->vco == 0) goto out; @@ -1352,7 +1352,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, /* cdclk = vco / 2 / div{1,1.5,2,4} */ switch (DIV_ROUND_CLOSEST(vco, cdclk)) { default: - WARN_ON(cdclk != dev_priv->cdclk.hw.ref); + WARN_ON(cdclk != dev_priv->cdclk.hw.bypass); WARN_ON(vco != 0); /* fall through */ case 2: @@ -1425,7 +1425,7 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) intel_dump_cdclk_state(&dev_priv->cdclk.hw, "Current CDCLK"); if (dev_priv->cdclk.hw.vco == 0 || - dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.ref) + dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.bypass) goto sanitize; /* DPLL okay; verify the cdclock @@ -1514,7 +1514,7 @@ void bxt_uninit_cdclk(struct drm_i915_private *dev_priv) { struct intel_cdclk_state cdclk_state = dev_priv->cdclk.hw; - cdclk_state.cdclk = cdclk_state.ref; + cdclk_state.cdclk = cdclk_state.bypass; cdclk_state.vco = 0; cdclk_state.voltage_level = bxt_calc_voltage_level(cdclk_state.cdclk); @@ -1574,7 +1574,7 @@ static void cnl_get_cdclk(struct drm_i915_private *dev_priv, cnl_cdclk_pll_update(dev_priv, cdclk_state); - cdclk_state->cdclk = cdclk_state->ref; + cdclk_state->cdclk = cdclk_state->bypass = cdclk_state->ref; if (cdclk_state->vco == 0) goto out; @@ -1660,7 +1660,7 @@ static void cnl_set_cdclk(struct drm_i915_private *dev_priv, /* cdclk = vco / 2 / div{1,2} */ switch (DIV_ROUND_CLOSEST(vco, cdclk)) { default: - WARN_ON(cdclk != dev_priv->cdclk.hw.ref); + WARN_ON(cdclk != dev_priv->cdclk.hw.bypass); WARN_ON(vco != 0); /* fall through */ case 2: @@ -1705,7 +1705,7 @@ static int cnl_cdclk_pll_vco(struct drm_i915_private *dev_priv, int cdclk) { int ratio; - if (cdclk == dev_priv->cdclk.hw.ref) + if (cdclk == dev_priv->cdclk.hw.bypass) return 0; switch (cdclk) { @@ -1732,7 +1732,7 @@ static void cnl_sanitize_cdclk(struct drm_i915_private *dev_priv) intel_dump_cdclk_state(&dev_priv->cdclk.hw, "Current CDCLK"); if (dev_priv->cdclk.hw.vco == 0 || - dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.ref) + dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.bypass) goto sanitize; /* DPLL okay; verify the cdclock @@ -1805,7 +1805,7 @@ void cnl_uninit_cdclk(struct drm_i915_private *dev_priv) { struct intel_cdclk_state cdclk_state = dev_priv->cdclk.hw; - cdclk_state.cdclk = cdclk_state.ref; + cdclk_state.cdclk = cdclk_state.bypass; cdclk_state.vco = 0; cdclk_state.voltage_level = cnl_calc_voltage_level(cdclk_state.cdclk); @@ -1846,9 +1846,10 @@ bool intel_cdclk_changed(const struct intel_cdclk_state *a, void intel_dump_cdclk_state(const struct intel_cdclk_state *cdclk_state, const char *context) { - DRM_DEBUG_DRIVER("%s %d kHz, VCO %d kHz, ref %d kHz, voltage level %d\n", + DRM_DEBUG_DRIVER("%s %d kHz, VCO %d kHz, ref %d kHz, bypass %d kHz, voltage level %d\n", context, cdclk_state->cdclk, cdclk_state->vco, - cdclk_state->ref, cdclk_state->voltage_level); + cdclk_state->ref, cdclk_state->bypass, + cdclk_state->voltage_level); } /** From e9af4ea2b9e7e5d3caa6354be14de06b678ed0fa Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 18 Jan 2018 13:16:09 +0000 Subject: [PATCH 048/158] drm/i915: Avoid waitboosting on the active request Watching a light workload on Baytrail (running glxgears and a 1080p decode), instead of the system remaining at low frequency, the glxgears would regularly trigger waitboosting after which it would have to spend a few seconds throttling back down. In this case, the waitboosting is counter productive as the minimal wait for glxgears doesn't prevent it from functioning correctly and delivering frames on time. In this case, glxgears happens to almost always be waiting on the current request, which we already expect to complete quickly (see i915_spin_request) and so avoiding the waitboost on the active request and spinning instead provides the best latency without overcommitting to upclocking. However, if the system falls behind we still force the waitboost. Similarly, we will also trigger upclocking if we detect the system is not delivering frames on time - again using a mechanism that tries to detect a miss and not preemptively upclock. v2: Also skip boosting for after missed vblank if the desired request is already active. Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Cc: Tvrtko Ursulin Cc: Radoslaw Szwichtenberg Reviewed-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20180118131609.16574-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 7 +++---- drivers/gpu/drm/i915/i915_gem_request.h | 13 +++++++++++++ drivers/gpu/drm/i915/intel_display.c | 8 +++++++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b2ba685cb144..7f0684ccc724 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -369,7 +369,8 @@ i915_gem_object_wait_fence(struct dma_fence *fence, if (i915_gem_request_completed(rq)) goto out; - /* This client is about to stall waiting for the GPU. In many cases + /* + * This client is about to stall waiting for the GPU. In many cases * this is undesirable and limits the throughput of the system, as * many clients cannot continue processing user input/output whilst * blocked. RPS autotuning may take tens of milliseconds to respond @@ -384,11 +385,9 @@ i915_gem_object_wait_fence(struct dma_fence *fence, * forcing the clocks too high for the whole system, we only allow * each client to waitboost once in a busy period. */ - if (rps_client) { + if (rps_client && !i915_gem_request_started(rq)) { if (INTEL_GEN(rq->i915) >= 6) gen6_rps_boost(rq, rps_client); - else - rps_client = NULL; } timeout = i915_wait_request(rq, flags, timeout); diff --git a/drivers/gpu/drm/i915/i915_gem_request.h b/drivers/gpu/drm/i915/i915_gem_request.h index 6c607f8dbf92..2236e9188c5c 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.h +++ b/drivers/gpu/drm/i915/i915_gem_request.h @@ -329,6 +329,19 @@ i915_gem_request_completed(const struct drm_i915_gem_request *req) return __i915_gem_request_completed(req, seqno); } +static inline bool +i915_gem_request_started(const struct drm_i915_gem_request *req) +{ + u32 seqno; + + seqno = i915_gem_request_global_seqno(req); + if (!seqno) + return false; + + return i915_seqno_passed(intel_engine_get_seqno(req->engine), + seqno - 1); +} + static inline bool i915_priotree_signaled(const struct i915_priotree *pt) { const struct drm_i915_gem_request *rq = diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f288bcc7be22..cbec1d3efa22 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12519,7 +12519,13 @@ static int do_rps_boost(struct wait_queue_entry *_wait, struct wait_rps_boost *wait = container_of(_wait, typeof(*wait), wait); struct drm_i915_gem_request *rq = wait->request; - gen6_rps_boost(rq, NULL); + /* + * If we missed the vblank, but the request is already running it + * is reasonable to assume that it will complete before the next + * vblank without our intervention, so leave RPS alone. + */ + if (!i915_gem_request_started(rq)) + gen6_rps_boost(rq, NULL); i915_gem_request_put(rq); drm_crtc_vblank_put(wait->crtc); From 0ed8795353265259b3c891d0626fed5f257dc527 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 11 Jan 2018 15:24:40 +0000 Subject: [PATCH 049/158] drm/i915/guc: Redefine guc_log_level modparam values We used value -1 to indicate "disabled" and values 0..3 to indicate "enabled", but most of our other modparams are using -1 for "auto" mode and 0 for "disable". For consistency let's change our log level values to: -1: auto (depends on platform and Kconfig.debug settings) 0: disabled 1: enabled (severity level 0 = min) 2: enabled (severity level 1) 3: enabled (severity level 2) 4: enabled (severity level 3 = max) v2: fix commit message (Sagar) display sanitized modparam value (Sagar) unify sanitize messages (Sagar/Michal) Signed-off-by: Michal Wajdeczko Cc: Sagar Arun Kamble Cc: Daniele Ceraolo Spurio Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Cc: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180111152441.21676-1-michal.wajdeczko@intel.com Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_params.c | 3 +- drivers/gpu/drm/i915/intel_guc.c | 22 ++++++---- drivers/gpu/drm/i915/intel_guc_log.c | 47 ++++++++++------------ drivers/gpu/drm/i915/intel_uc.c | 60 +++++++++++++++++++++++++--- 4 files changed, 93 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index b5f3eb4fa8a3..0b553a8e48fb 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -155,7 +155,8 @@ i915_param_named_unsafe(enable_guc, int, 0400, "(-1=auto, 0=disable [default], 1=GuC submission, 2=HuC load)"); i915_param_named(guc_log_level, int, 0400, - "GuC firmware logging level (-1:disabled (default), 0-3:enabled)"); + "GuC firmware logging level. Requires GuC to be loaded. " + "(-1=auto [default], 0=disable, 1..4=enable with verbosity min..max)"); i915_param_named_unsafe(guc_firmware_path, charp, 0400, "GuC firmware path to use instead of the default one"); diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 50b472576980..ea30e7c34a04 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -215,6 +215,19 @@ static u32 get_core_family(struct drm_i915_private *dev_priv) } } +static u32 get_log_verbosity_flags(void) +{ + if (i915_modparams.guc_log_level > 0) { + u32 verbosity = i915_modparams.guc_log_level - 1; + + GEM_BUG_ON(verbosity > GUC_LOG_VERBOSITY_MAX); + return verbosity << GUC_LOG_VERBOSITY_SHIFT; + } + + GEM_BUG_ON(i915_modparams.enable_guc < 0); + return GUC_LOG_DISABLED; +} + /* * Initialise the GuC parameter block before starting the firmware * transfer. These parameters are read by the firmware on startup @@ -247,12 +260,7 @@ void intel_guc_init_params(struct intel_guc *guc) params[GUC_CTL_LOG_PARAMS] = guc->log.flags; - if (i915_modparams.guc_log_level >= 0) { - params[GUC_CTL_DEBUG] = - i915_modparams.guc_log_level << GUC_LOG_VERBOSITY_SHIFT; - } else { - params[GUC_CTL_DEBUG] = GUC_LOG_DISABLED; - } + params[GUC_CTL_DEBUG] = get_log_verbosity_flags(); /* If GuC submission is enabled, set up additional parameters here */ if (USES_GUC_SUBMISSION(dev_priv)) { @@ -445,7 +453,7 @@ int intel_guc_resume(struct drm_i915_private *dev_priv) if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS) return 0; - if (i915_modparams.guc_log_level >= 0) + if (i915_modparams.guc_log_level) gen9_enable_guc_interrupts(dev_priv); data[0] = INTEL_GUC_ACTION_EXIT_S_STATE; diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index eaedd63e3819..e6d59bf9dae1 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -33,11 +33,10 @@ static void guc_log_capture_logs(struct intel_guc *guc); /** * DOC: GuC firmware log * - * Firmware log is enabled by setting i915.guc_log_level to non-negative level. + * Firmware log is enabled by setting i915.guc_log_level to the positive level. * Log data is printed out via reading debugfs i915_guc_log_dump. Reading from * i915_guc_load_status will print out firmware loading status and scratch * registers value. - * */ static int guc_log_flush_complete(struct intel_guc *guc) @@ -147,7 +146,7 @@ static int guc_log_relay_file_create(struct intel_guc *guc) struct dentry *log_dir; int ret; - if (i915_modparams.guc_log_level < 0) + if (!i915_modparams.guc_log_level) return 0; /* For now create the log file in /sys/kernel/debug/dri/0 dir */ @@ -423,8 +422,8 @@ static void guc_log_runtime_destroy(struct intel_guc *guc) { /* * It's possible that the runtime stuff was never allocated because - * guc_log_level was < 0 at the time - **/ + * GuC log was disabled at the boot time. + */ if (!guc_log_has_runtime(guc)) return; @@ -441,9 +440,10 @@ static int guc_log_late_setup(struct intel_guc *guc) lockdep_assert_held(&dev_priv->drm.struct_mutex); if (!guc_log_has_runtime(guc)) { - /* If log_level was set as -1 at boot time, then setup needed to - * handle log buffer flush interrupts would not have been done yet, - * so do that now. + /* + * If log was disabled at boot time, then setup needed to handle + * log buffer flush interrupts would not have been done yet, so + * do that now. */ ret = guc_log_runtime_create(guc); if (ret) @@ -460,7 +460,7 @@ err_runtime: guc_log_runtime_destroy(guc); err: /* logging will remain off */ - i915_modparams.guc_log_level = -1; + i915_modparams.guc_log_level = 0; return ret; } @@ -482,8 +482,7 @@ static void guc_flush_logs(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); - if (!USES_GUC_SUBMISSION(dev_priv) || - (i915_modparams.guc_log_level < 0)) + if (!USES_GUC_SUBMISSION(dev_priv) || !i915_modparams.guc_log_level) return; /* First disable the interrupts, will be renabled afterwards */ @@ -511,9 +510,6 @@ int intel_guc_log_create(struct intel_guc *guc) GEM_BUG_ON(guc->log.vma); - if (i915_modparams.guc_log_level > GUC_LOG_VERBOSITY_MAX) - i915_modparams.guc_log_level = GUC_LOG_VERBOSITY_MAX; - /* The first page is to save log buffer state. Allocate one * extra page for others in case for overlap */ size = (1 + GUC_LOG_DPC_PAGES + 1 + @@ -537,7 +533,7 @@ int intel_guc_log_create(struct intel_guc *guc) guc->log.vma = vma; - if (i915_modparams.guc_log_level >= 0) { + if (i915_modparams.guc_log_level) { ret = guc_log_runtime_create(guc); if (ret < 0) goto err_vma; @@ -558,7 +554,7 @@ err_vma: i915_vma_unpin_and_release(&guc->log.vma); err: /* logging will be off */ - i915_modparams.guc_log_level = -1; + i915_modparams.guc_log_level = 0; return ret; } @@ -582,7 +578,7 @@ int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val) return -EINVAL; /* This combination doesn't make sense & won't have any effect */ - if (!log_param.logging_enabled && (i915_modparams.guc_log_level < 0)) + if (!log_param.logging_enabled && !i915_modparams.guc_log_level) return 0; ret = guc_log_control(guc, log_param.value); @@ -592,11 +588,12 @@ int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val) } if (log_param.logging_enabled) { - i915_modparams.guc_log_level = log_param.verbosity; + i915_modparams.guc_log_level = 1 + log_param.verbosity; - /* If log_level was set as -1 at boot time, then the relay channel file - * wouldn't have been created by now and interrupts also would not have - * been enabled. Try again now, just in case. + /* + * If log was disabled at boot time, then the relay channel file + * wouldn't have been created by now and interrupts also would + * not have been enabled. Try again now, just in case. */ ret = guc_log_late_setup(guc); if (ret < 0) { @@ -607,7 +604,8 @@ int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val) /* GuC logging is currently the only user of Guc2Host interrupts */ gen9_enable_guc_interrupts(dev_priv); } else { - /* Once logging is disabled, GuC won't generate logs & send an + /* + * Once logging is disabled, GuC won't generate logs & send an * interrupt. But there could be some data in the log buffer * which is yet to be captured. So request GuC to update the log * buffer state and then collect the left over logs. @@ -615,7 +613,7 @@ int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val) guc_flush_logs(guc); /* As logging is disabled, update log level to reflect that */ - i915_modparams.guc_log_level = -1; + i915_modparams.guc_log_level = 0; } return ret; @@ -623,8 +621,7 @@ int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val) void i915_guc_log_register(struct drm_i915_private *dev_priv) { - if (!USES_GUC_SUBMISSION(dev_priv) || - (i915_modparams.guc_log_level < 0)) + if (!USES_GUC_SUBMISSION(dev_priv) || !i915_modparams.guc_log_level) return; mutex_lock(&dev_priv->drm.struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index d82ca0f438f5..f78a17b24798 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -65,6 +65,21 @@ static int __get_platform_enable_guc(struct drm_i915_private *dev_priv) return enable_guc; } +static int __get_default_guc_log_level(struct drm_i915_private *dev_priv) +{ + int guc_log_level = 0; /* disabled */ + + /* Enable if we're running on platform with GuC and debug config */ + if (HAS_GUC(dev_priv) && intel_uc_is_using_guc() && + (IS_ENABLED(CONFIG_DRM_I915_DEBUG) || + IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))) + guc_log_level = 1 + GUC_LOG_VERBOSITY_MAX; + + /* Any platform specific fine-tuning can be done here */ + + return guc_log_level; +} + /** * intel_uc_sanitize_options - sanitize uC related modparam options * @dev_priv: device private @@ -74,6 +89,13 @@ static int __get_platform_enable_guc(struct drm_i915_private *dev_priv) * modparam varies between platforms and it is hardcoded in driver code. * Any other modparam value is only monitored against availability of the * related hardware or firmware definitions. + * + * In case of "guc_log_level" option this function will attempt to modify + * it only if it was initially set to "auto(-1)" or if initial value was + * "enable(1..4)" on platforms without the GuC. Default value for this + * modparam varies between platforms and is usually set to "disable(0)" + * unless GuC is enabled on given platform and the driver is compiled with + * debug config when this modparam will default to "enable(1..4)". */ void intel_uc_sanitize_options(struct drm_i915_private *dev_priv) { @@ -91,22 +113,48 @@ void intel_uc_sanitize_options(struct drm_i915_private *dev_priv) /* Verify GuC firmware availability */ if (intel_uc_is_using_guc() && !intel_uc_fw_is_selected(guc_fw)) { - DRM_WARN("Incompatible option detected: enable_guc=%d, %s!\n", - i915_modparams.enable_guc, + DRM_WARN("Incompatible option detected: %s=%d, %s!\n", + "enable_guc", i915_modparams.enable_guc, !HAS_GUC(dev_priv) ? "no GuC hardware" : "no GuC firmware"); } /* Verify HuC firmware availability */ if (intel_uc_is_using_huc() && !intel_uc_fw_is_selected(huc_fw)) { - DRM_WARN("Incompatible option detected: enable_guc=%d, %s!\n", - i915_modparams.enable_guc, + DRM_WARN("Incompatible option detected: %s=%d, %s!\n", + "enable_guc", i915_modparams.enable_guc, !HAS_HUC(dev_priv) ? "no HuC hardware" : "no HuC firmware"); } + /* A negative value means "use platform/config default" */ + if (i915_modparams.guc_log_level < 0) + i915_modparams.guc_log_level = + __get_default_guc_log_level(dev_priv); + + if (i915_modparams.guc_log_level > 0 && !intel_uc_is_using_guc()) { + DRM_WARN("Incompatible option detected: %s=%d, %s!\n", + "guc_log_level", i915_modparams.guc_log_level, + !HAS_GUC(dev_priv) ? "no GuC hardware" : + "GuC not enabled"); + i915_modparams.guc_log_level = 0; + } + + if (i915_modparams.guc_log_level > 1 + GUC_LOG_VERBOSITY_MAX) { + DRM_WARN("Incompatible option detected: %s=%d, %s!\n", + "guc_log_level", i915_modparams.guc_log_level, + "verbosity too high"); + i915_modparams.guc_log_level = 1 + GUC_LOG_VERBOSITY_MAX; + } + + DRM_DEBUG_DRIVER("guc_log_level=%d (enabled:%s verbosity:%d)\n", + i915_modparams.guc_log_level, + yesno(i915_modparams.guc_log_level), + i915_modparams.guc_log_level - 1); + /* Make sure that sanitization was done */ GEM_BUG_ON(i915_modparams.enable_guc < 0); + GEM_BUG_ON(i915_modparams.guc_log_level < 0); } void intel_uc_init_early(struct drm_i915_private *dev_priv) @@ -152,7 +200,7 @@ void intel_uc_init_mmio(struct drm_i915_private *dev_priv) static void guc_capture_load_err_log(struct intel_guc *guc) { - if (!guc->log.vma || i915_modparams.guc_log_level < 0) + if (!guc->log.vma || !i915_modparams.guc_log_level) return; if (!guc->load_err_log) @@ -322,7 +370,7 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) } if (USES_GUC_SUBMISSION(dev_priv)) { - if (i915_modparams.guc_log_level >= 0) + if (i915_modparams.guc_log_level) gen9_enable_guc_interrupts(dev_priv); ret = intel_guc_submission_enable(guc); From 35fe703c3161ac9e723c845d425814a02cfda140 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 11 Jan 2018 15:24:41 +0000 Subject: [PATCH 050/158] drm/i915/guc: Change values for i915_guc_log_control Today we have format mismatch between read/write operations of i915_guc_log_control entry. For read we return (0, 1..4) that represents disable/verbosity levels, but for write we force user to follow internal structure format (0,1,9,11,13). Let's hide internals from the user and accept same values as we support for read and related guc_log_level modparam. Signed-off-by: Michal Wajdeczko Cc: Sagar Arun Kamble Cc: Daniele Ceraolo Spurio Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Cc: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180111152441.21676-2-michal.wajdeczko@intel.com Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_guc_log.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index e6d59bf9dae1..2ffc966aa196 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -58,11 +58,15 @@ static int guc_log_flush(struct intel_guc *guc) return intel_guc_send(guc, action, ARRAY_SIZE(action)); } -static int guc_log_control(struct intel_guc *guc, u32 control_val) +static int guc_log_control(struct intel_guc *guc, bool enable, u32 verbosity) { + union guc_log_control control_val = { + .logging_enabled = enable, + .verbosity = verbosity, + }; u32 action[] = { INTEL_GUC_ACTION_UK_LOG_ENABLE_LOGGING, - control_val + control_val.value }; return intel_guc_send(guc, action, ARRAY_SIZE(action)); @@ -567,28 +571,27 @@ void intel_guc_log_destroy(struct intel_guc *guc) int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val) { struct intel_guc *guc = &dev_priv->guc; - - union guc_log_control log_param; + bool enable_logging = control_val > 0; + u32 verbosity; int ret; - log_param.value = control_val; - - if (log_param.verbosity < GUC_LOG_VERBOSITY_MIN || - log_param.verbosity > GUC_LOG_VERBOSITY_MAX) + BUILD_BUG_ON(GUC_LOG_VERBOSITY_MIN); + if (control_val > 1 + GUC_LOG_VERBOSITY_MAX) return -EINVAL; /* This combination doesn't make sense & won't have any effect */ - if (!log_param.logging_enabled && !i915_modparams.guc_log_level) + if (!enable_logging && !i915_modparams.guc_log_level) return 0; - ret = guc_log_control(guc, log_param.value); + verbosity = enable_logging ? control_val - 1 : 0; + ret = guc_log_control(guc, enable_logging, verbosity); if (ret < 0) { DRM_DEBUG_DRIVER("guc_logging_control action failed %d\n", ret); return ret; } - if (log_param.logging_enabled) { - i915_modparams.guc_log_level = 1 + log_param.verbosity; + if (enable_logging) { + i915_modparams.guc_log_level = 1 + verbosity; /* * If log was disabled at boot time, then the relay channel file From 1edf6958c195146973fd78c82fadea8330becfd0 Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Thu, 18 Jan 2018 17:52:28 +0000 Subject: [PATCH 051/158] drm/i915: Use the engine name directly in the error_state file Instead of using local string names that we will have to keep maintaining, use the engine->name directly. v2: Better invalid engine_id handling, capture_bo will not be able know the engine_id and end up with -1 (Michal). Suggested-by: Michal Wajdeczko Signed-off-by: Michel Thierry Cc: Michal Wajdeczko Cc: Chris Wilson Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180110012151.28261-1-michel.thierry@intel.com [ickle: minor massaging of function names] Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180118175228.2830-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gpu_error.c | 34 +++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 06577574296b..a81351d9e3a6 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -34,16 +34,25 @@ #include "i915_drv.h" -static const char *engine_str(int engine) +static inline const struct intel_engine_cs * +engine_lookup(const struct drm_i915_private *i915, unsigned int id) { - switch (engine) { - case RCS: return "render"; - case VCS: return "bsd"; - case BCS: return "blt"; - case VECS: return "vebox"; - case VCS2: return "bsd2"; - default: return ""; - } + if (id >= I915_NUM_ENGINES) + return NULL; + + return i915->engine[id]; +} + +static inline const char * +__engine_name(const struct intel_engine_cs *engine) +{ + return engine ? engine->name : ""; +} + +static const char * +engine_name(const struct drm_i915_private *i915, unsigned int id) +{ + return __engine_name(engine_lookup(i915, id)); } static const char *tiling_flag(int tiling) @@ -345,7 +354,7 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m, err_puts(m, purgeable_flag(err->purgeable)); err_puts(m, err->userptr ? " userptr" : ""); err_puts(m, err->engine != -1 ? " " : ""); - err_puts(m, engine_str(err->engine)); + err_puts(m, engine_name(m->i915, err->engine)); err_puts(m, i915_cache_level_str(m->i915, err->cache_level)); if (err->name) @@ -415,7 +424,8 @@ static void error_print_engine(struct drm_i915_error_state_buf *m, { int n; - err_printf(m, "%s command stream:\n", engine_str(ee->engine_id)); + err_printf(m, "%s command stream:\n", + engine_name(m->i915, ee->engine_id)); err_printf(m, " IDLE?: %s\n", yesno(ee->idle)); err_printf(m, " START: 0x%08x\n", ee->start); err_printf(m, " HEAD: 0x%08x [0x%08x]\n", ee->head, ee->rq_head); @@ -635,7 +645,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, if (error->engine[i].hangcheck_stalled && error->engine[i].context.pid) { err_printf(m, "Active process (on ring %s): %s [%d], score %d\n", - engine_str(i), + engine_name(m->i915, i), error->engine[i].context.comm, error->engine[i].context.pid, error->engine[i].context.ban_score); From ddd39e4b3f8fb9b69c4dd41019cbe30b049af5ed Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 28 Nov 2017 14:05:53 -0800 Subject: [PATCH 052/158] drm/i915/cnl: apply Display WA #1178 to fix type C dongles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display WA #1178 is meant to fix Aux channel voltage swing too low with some type C dongles. Although it is for type C, HW engineers reported that it can be applied to all external ports even if they are not going to type C. For CNL we apply the workaround every time Aux B, C and D are powering up since they will lose the configuration when powered down. v2: Use common tag for WA Cc: Rodrigo Vivi Cc: Arthur J Runyan Cc: Ville Syrjälä Signed-off-by: Lucas De Marchi Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20171128220553.22435-1-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 11 +++++++++++ drivers/gpu/drm/i915/intel_runtime_pm.c | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a2108e35c599..3ed5d49aa46d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8350,6 +8350,17 @@ enum skl_power_gate { #define SKL_PW_TO_PG(pw) ((pw) - SKL_DISP_PW_1 + SKL_PG1) #define SKL_FUSE_PG_DIST_STATUS(pg) (1 << (27 - (pg))) +#define _CNL_AUX_REG_IDX(pw) ((pw - 1) >> 4) +#define _CNL_AUX_ANAOVRD1_B 0x162250 +#define _CNL_AUX_ANAOVRD1_C 0x162210 +#define _CNL_AUX_ANAOVRD1_D 0x1622D0 +#define CNL_AUX_ANAOVRD1(pw) _MMIO(_PICK(_CNL_AUX_REG_IDX(pw), \ + _CNL_AUX_ANAOVRD1_B, \ + _CNL_AUX_ANAOVRD1_C, \ + _CNL_AUX_ANAOVRD1_D)) +#define CNL_AUX_ANAOVRD1_ENABLE (1<<16) +#define CNL_AUX_ANAOVRD1_LDO_BYPASS (1<<23) + /* Per-pipe DDI Function Control */ #define _TRANS_DDI_FUNC_CTL_A 0x60400 #define _TRANS_DDI_FUNC_CTL_B 0x61400 diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 4996c4ea8a80..5b1aa4b9c72c 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -390,6 +390,15 @@ static void hsw_power_well_enable(struct drm_i915_private *dev_priv, I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), val | HSW_PWR_WELL_CTL_REQ(id)); hsw_wait_for_power_well_enable(dev_priv, power_well); + /* Display WA #1178: cnl */ + if (IS_CANNONLAKE(dev_priv) && + (id == CNL_DISP_PW_AUX_B || id == CNL_DISP_PW_AUX_C || + id == CNL_DISP_PW_AUX_D)) { + val = I915_READ(CNL_AUX_ANAOVRD1(id)); + val |= CNL_AUX_ANAOVRD1_ENABLE | CNL_AUX_ANAOVRD1_LDO_BYPASS; + I915_WRITE(CNL_AUX_ANAOVRD1(id), val); + } + if (wait_fuses) gen9_wait_for_power_well_fuses(dev_priv, pg); From c4fb60b9aba9f939d3f8575df23fd8d5958ec6ed Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Jan 2018 17:33:10 +0200 Subject: [PATCH 053/158] drm/i915/bios: add DP max link rate to VBT child device struct Update VBT defs to reflect revision 216. While at it, default the expected child device struct size to sizeof the size rather than a hardcoded value. v2: Fix bit order (David) Cc: Rodrigo Vivi Signed-off-by: Jani Nikula Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180118153310.32437-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_bios.c | 8 +++++--- drivers/gpu/drm/i915/intel_vbt_defs.h | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 51108ffc28d1..b820d595ebc8 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1323,11 +1323,13 @@ parse_general_definitions(struct drm_i915_private *dev_priv, expected_size = LEGACY_CHILD_DEVICE_CONFIG_SIZE; } else if (bdb->version == 195) { expected_size = 37; - } else if (bdb->version <= 197) { + } else if (bdb->version <= 215) { expected_size = 38; + } else if (bdb->version <= 216) { + expected_size = 39; } else { - expected_size = 38; - BUILD_BUG_ON(sizeof(*child) < 38); + expected_size = sizeof(*child); + BUILD_BUG_ON(sizeof(*child) < 39); DRM_DEBUG_DRIVER("Expected child device config size for VBT version %u not known; assuming %u\n", bdb->version, expected_size); } diff --git a/drivers/gpu/drm/i915/intel_vbt_defs.h b/drivers/gpu/drm/i915/intel_vbt_defs.h index e3d7745a9151..98dff6058d3c 100644 --- a/drivers/gpu/drm/i915/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/intel_vbt_defs.h @@ -412,6 +412,8 @@ struct child_device_config { u16 dp_gpio_pin_num; /* 195 */ u8 dp_iboost_level:4; /* 196 */ u8 hdmi_iboost_level:4; /* 196 */ + u8 dp_max_link_rate:2; /* 216 CNL+ */ + u8 dp_max_link_rate_reserved:6; /* 216 */ } __packed; struct bdb_general_definitions { From 3cfd32654b47c040c3d66d9a7e66f50cf895acd5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Jan 2018 17:06:13 +0200 Subject: [PATCH 054/158] drm/i915: vbt defs typo fixes No more sing-a-ling. Reported-by: Adam Jackson You're-my-ding-a-ling-by: Chris Wilson Reviewed-by: David Weinehall Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180118150613.26140-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_vbt_defs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_vbt_defs.h b/drivers/gpu/drm/i915/intel_vbt_defs.h index 98dff6058d3c..3f5eff49105b 100644 --- a/drivers/gpu/drm/i915/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/intel_vbt_defs.h @@ -227,7 +227,7 @@ struct bdb_general_features { #define DEVICE_TYPE_COMPOSITE_OUTPUT (1 << 9) #define DEVICE_TYPE_DUAL_CHANNEL (1 << 8) #define DEVICE_TYPE_HIGH_SPEED_LINK (1 << 6) -#define DEVICE_TYPE_LVDS_SINGALING (1 << 5) +#define DEVICE_TYPE_LVDS_SIGNALING (1 << 5) #define DEVICE_TYPE_TMDS_DVI_SIGNALING (1 << 4) #define DEVICE_TYPE_VIDEO_SIGNALING (1 << 3) #define DEVICE_TYPE_DISPLAYPORT_OUTPUT (1 << 2) @@ -243,7 +243,7 @@ struct bdb_general_features { DEVICE_TYPE_MIPI_OUTPUT | \ DEVICE_TYPE_COMPOSITE_OUTPUT | \ DEVICE_TYPE_DUAL_CHANNEL | \ - DEVICE_TYPE_LVDS_SINGALING | \ + DEVICE_TYPE_LVDS_SIGNALING | \ DEVICE_TYPE_TMDS_DVI_SIGNALING | \ DEVICE_TYPE_VIDEO_SIGNALING | \ DEVICE_TYPE_DISPLAYPORT_OUTPUT | \ @@ -253,7 +253,7 @@ struct bdb_general_features { (DEVICE_TYPE_INTERNAL_CONNECTOR | \ DEVICE_TYPE_MIPI_OUTPUT | \ DEVICE_TYPE_COMPOSITE_OUTPUT | \ - DEVICE_TYPE_LVDS_SINGALING | \ + DEVICE_TYPE_LVDS_SIGNALING | \ DEVICE_TYPE_TMDS_DVI_SIGNALING | \ DEVICE_TYPE_VIDEO_SIGNALING | \ DEVICE_TYPE_DISPLAYPORT_OUTPUT | \ From a4dd90b1cb6f9f761753f72b4208feee4bf4d946 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 29 Dec 2017 14:55:47 +0200 Subject: [PATCH 055/158] drm/i915: remove redundant ELD connector type update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_edid_to_eld() sets ELD connector type since commit 1d1c36650752 ("drm/edid: set ELD connector type in drm_edid_to_eld()"). Remove the redundant update. (Commit c945b8c14bb7 ("drm/edid: build ELD in drm_add_edid_modes()") and commit d471ed04b487 ("drm/drivers: drop redundant drm_edid_to_eld() calls") are also related.) v2: Rebase, update commit message with commit references. Reviewed-by: Ville Syrjälä Reviewed-by: Alex Deucher Acked-by: Thierry Reding Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20171229125547.28672-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_modes.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index 4e43f873c889..b39846613e3c 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -30,21 +30,6 @@ #include "intel_drv.h" #include "i915_drv.h" -static void intel_connector_update_eld_conn_type(struct drm_connector *connector) -{ - u8 conn_type; - - if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || - connector->connector_type == DRM_MODE_CONNECTOR_eDP) { - conn_type = DRM_ELD_CONN_TYPE_DP; - } else { - conn_type = DRM_ELD_CONN_TYPE_HDMI; - } - - connector->eld[DRM_ELD_SAD_COUNT_CONN_TYPE] &= ~DRM_ELD_CONN_TYPE_MASK; - connector->eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= conn_type; -} - /** * intel_connector_update_modes - update connector from edid * @connector: DRM connector device to use @@ -58,8 +43,6 @@ int intel_connector_update_modes(struct drm_connector *connector, drm_mode_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); - intel_connector_update_eld_conn_type(connector); - return ret; } From 3019062905533ccd71b535f6e5c3ed7e9bb195e0 Mon Sep 17 00:00:00 2001 From: Abdiel Janulgue Date: Fri, 15 Dec 2017 12:20:55 +0200 Subject: [PATCH 056/158] drm/i915: Ignore TMDS clock limit for DP++ when EDID override is set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 4K modes testing by using dummy EDID data has never been working properly on boxes with DP++ (dual-mode) adaptors. The reason for this is that those modes got pruned during hdmi mode validation. intel_hdmi_mode_valid returns CLOCK_HIGH because the pixel clock reported by the 4k mode is higher than dual port TMDS clock limit. However 4k injection does work properly on machines that don't have DP++ adapters because the mode is never validated against the DP++ TMDS clock limit. v2: Don't detect the DP++ limits when we're testing using overridden EDIDs. Make sure to check for the override condition after respecting the value of drm_dp_dual_mode_detect (Jani Nikula). Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101649 Cc: Ville Syrjälä Cc: Jani Nikula Cc: Daniel Vetter Signed-off-by: Abdiel Janulgue Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20171215102055.11729-1-abdiel.janulgue@linux.intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 179d0ad3889d..93e97f9e1aac 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1567,7 +1567,10 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid) * there's nothing connected to the port. */ if (type == DRM_DP_DUAL_MODE_UNKNOWN) { - if (has_edid && + /* An overridden EDID imply that we want this port for testing. + * Make sure not to set limits for that port. + */ + if (has_edid && !connector->override_edid && intel_bios_is_port_dp_dual_mode(dev_priv, port)) { DRM_DEBUG_KMS("Assuming DP dual mode adaptor presence based on VBT\n"); type = DRM_DP_DUAL_MODE_TYPE1_DVI; From e13a3183dae4f511821c4ad1e317a2b132051d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 22 Dec 2017 21:22:25 +0200 Subject: [PATCH 057/158] drm/i915: Nuke a pointless unreachable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The unreachable() is very much unreachable and the compiler knows that, so there's no point in having it. Cc: Ben Widawsky Cc: Jason Ekstrand Cc: Daniel Stone Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20171222192231.17981-3-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cbec1d3efa22..36960b7eb736 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12950,8 +12950,6 @@ static bool intel_primary_plane_format_mod_supported(struct drm_plane *plane, return i965_mod_supported(format, modifier); else return i8xx_mod_supported(format, modifier); - - unreachable(); } static bool intel_cursor_plane_format_mod_supported(struct drm_plane *plane, From 74ac160b3f9585300bd79e52d560c2da896d6078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 22 Dec 2017 21:22:26 +0200 Subject: [PATCH 058/158] drm/i915: Add the missing Y/Yf modifiers for SKL+ sprites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Y/Yf were dropped out from the SKL+ sprite modifier list on account of some watermark issues Daniel Stone was having. My subsequent testing seemed to indicate that things work better now, so add the modifiers back in. v2: Update the commit message with a better explanation Cc: Ben Widawsky Cc: Jason Ekstrand Cc: Daniel Stone Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20171222192231.17981-4-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index dd485f59eb1d..51bd79ad647a 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1162,6 +1162,8 @@ static uint32_t skl_plane_formats[] = { }; static const uint64_t skl_plane_format_modifiers[] = { + I915_FORMAT_MOD_Yf_TILED, + I915_FORMAT_MOD_Y_TILED, I915_FORMAT_MOD_X_TILED, DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID From c21f7904c7d2d89f82dffb5e5b72e698ebfa86a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 22 Dec 2017 21:22:27 +0200 Subject: [PATCH 059/158] drm/i915: Clean up the sprite modifier checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the g4x and snb cases into separate functions to match how we deal with all other platforms. Also sort the switch cases to match the format lists we've declared earlier, to ease comparisons. Cc: Ben Widawsky Cc: Jason Ekstrand Cc: Daniel Stone Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20171222192231.17981-5-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 48 +++++++++++++++++------------ 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 51bd79ad647a..349be8134c76 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1169,12 +1169,9 @@ static const uint64_t skl_plane_format_modifiers[] = { DRM_FORMAT_MOD_INVALID }; -static bool g4x_sprite_plane_format_mod_supported(struct drm_plane *plane, - uint32_t format, - uint64_t modifier) +static bool g4x_mod_supported(uint32_t format, uint64_t modifier) { switch (format) { - case DRM_FORMAT_XBGR8888: case DRM_FORMAT_XRGB8888: case DRM_FORMAT_YUYV: case DRM_FORMAT_YVYU: @@ -1189,22 +1186,38 @@ static bool g4x_sprite_plane_format_mod_supported(struct drm_plane *plane, } } -static bool vlv_sprite_plane_format_mod_supported(struct drm_plane *plane, - uint32_t format, - uint64_t modifier) +static bool snb_mod_supported(uint32_t format, uint64_t modifier) { switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: case DRM_FORMAT_YUYV: case DRM_FORMAT_YVYU: case DRM_FORMAT_UYVY: case DRM_FORMAT_VYUY: + if (modifier == DRM_FORMAT_MOD_LINEAR || + modifier == I915_FORMAT_MOD_X_TILED) + return true; + /* fall through */ + default: + return false; + } +} + +static bool vlv_mod_supported(uint32_t format, uint64_t modifier) +{ + switch (format) { case DRM_FORMAT_RGB565: - case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ABGR8888: case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XBGR2101010: case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: if (modifier == DRM_FORMAT_MOD_LINEAR || modifier == I915_FORMAT_MOD_X_TILED) return true; @@ -1214,11 +1227,8 @@ static bool vlv_sprite_plane_format_mod_supported(struct drm_plane *plane, } } -static bool skl_sprite_plane_format_mod_supported(struct drm_plane *plane, - uint32_t format, - uint64_t modifier) +static bool skl_mod_supported(uint32_t format, uint64_t modifier) { - /* This is the same as primary plane since SKL has universal planes */ switch (format) { case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XBGR8888: @@ -1259,13 +1269,13 @@ static bool intel_sprite_plane_format_mod_supported(struct drm_plane *plane, return false; if (INTEL_GEN(dev_priv) >= 9) - return skl_sprite_plane_format_mod_supported(plane, format, modifier); + return skl_mod_supported(format, modifier); else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - return vlv_sprite_plane_format_mod_supported(plane, format, modifier); + return vlv_mod_supported(format, modifier); + else if (INTEL_GEN(dev_priv) >= 6) + return snb_mod_supported(format, modifier); else - return g4x_sprite_plane_format_mod_supported(plane, format, modifier); - - unreachable(); + return g4x_mod_supported(format, modifier); } static const struct drm_plane_funcs intel_sprite_plane_funcs = { From 77064e2eb83ac6a50563b80c5de3d434d3cf8b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 22 Dec 2017 21:22:28 +0200 Subject: [PATCH 060/158] drm/i915: Add CCS capability for sprites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow sprites to scan out compressed framebuffers. Since different platforms have a different set of planes that support CCS let's add a small helper to determine whether a specific plane supports CCS or not. Currently that information is spread around in many places, and not all the pieces of code even agree with each other. In addition to allowing sprites to scan out compressed fbs, the other fix here is that we stop rejecting them on pipe C on CNL. Cc: Ben Widawsky Cc: Jason Ekstrand Cc: Daniel Stone Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20171222192231.17981-6-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola --- drivers/gpu/drm/i915/intel_display.c | 25 +++----------- drivers/gpu/drm/i915/intel_drv.h | 2 ++ drivers/gpu/drm/i915/intel_sprite.c | 50 ++++++++++++++++++++-------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 36960b7eb736..a323234fa83b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3027,6 +3027,7 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state) static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state) { struct intel_plane *plane = to_intel_plane(plane_state->base.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); struct intel_crtc *crtc = to_intel_crtc(plane_state->base.crtc); const struct drm_framebuffer *fb = plane_state->base.fb; int src_x = plane_state->base.src.x1 >> 16; @@ -3037,17 +3038,8 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state) int y = src_y / vsub; u32 offset; - switch (plane->id) { - case PLANE_PRIMARY: - case PLANE_SPRITE0: - break; - default: - DRM_DEBUG_KMS("RC support only on plane 1 and 2\n"); - return -EINVAL; - } - - if (crtc->pipe == PIPE_C) { - DRM_DEBUG_KMS("No RC support on pipe C\n"); + if (!skl_plane_has_ccs(dev_priv, crtc->pipe, plane->id)) { + DRM_DEBUG_KMS("No RC support on %s\n", plane->base.name); return -EINVAL; } @@ -13160,18 +13152,11 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) primary->frontbuffer_bit = INTEL_FRONTBUFFER_PRIMARY(pipe); primary->check_plane = intel_check_primary_plane; - if (INTEL_GEN(dev_priv) >= 10) { + if (INTEL_GEN(dev_priv) >= 9) { intel_primary_formats = skl_primary_formats; num_formats = ARRAY_SIZE(skl_primary_formats); - modifiers = skl_format_modifiers_ccs; - primary->update_plane = skl_update_plane; - primary->disable_plane = skl_disable_plane; - primary->get_hw_state = skl_plane_get_hw_state; - } else if (INTEL_GEN(dev_priv) >= 9) { - intel_primary_formats = skl_primary_formats; - num_formats = ARRAY_SIZE(skl_primary_formats); - if (pipe < PIPE_C) + if (skl_plane_has_ccs(dev_priv, pipe, PLANE_PRIMARY)) modifiers = skl_format_modifiers_ccs; else modifiers = skl_format_modifiers_noccs; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 48676e99316e..bb849b55548c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1933,6 +1933,8 @@ void skl_update_plane(struct intel_plane *plane, const struct intel_plane_state *plane_state); void skl_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc); bool skl_plane_get_hw_state(struct intel_plane *plane); +bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id); /* intel_tv.c */ void intel_tv_init(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 349be8134c76..cb06acff283d 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1161,7 +1161,17 @@ static uint32_t skl_plane_formats[] = { DRM_FORMAT_VYUY, }; -static const uint64_t skl_plane_format_modifiers[] = { +static const uint64_t skl_plane_format_modifiers_noccs[] = { + I915_FORMAT_MOD_Yf_TILED, + I915_FORMAT_MOD_Y_TILED, + I915_FORMAT_MOD_X_TILED, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static const uint64_t skl_plane_format_modifiers_ccs[] = { + I915_FORMAT_MOD_Yf_TILED_CCS, + I915_FORMAT_MOD_Y_TILED_CCS, I915_FORMAT_MOD_Yf_TILED, I915_FORMAT_MOD_Y_TILED, I915_FORMAT_MOD_X_TILED, @@ -1234,6 +1244,10 @@ static bool skl_mod_supported(uint32_t format, uint64_t modifier) case DRM_FORMAT_XBGR8888: case DRM_FORMAT_ARGB8888: case DRM_FORMAT_ABGR8888: + if (modifier == I915_FORMAT_MOD_Yf_TILED_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_CCS) + return true; + /* fall through */ case DRM_FORMAT_RGB565: case DRM_FORMAT_XRGB2101010: case DRM_FORMAT_XBGR2101010: @@ -1289,6 +1303,23 @@ static const struct drm_plane_funcs intel_sprite_plane_funcs = { .format_mod_supported = intel_sprite_plane_format_mod_supported, }; +bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id) +{ + if (plane_id == PLANE_CURSOR) + return false; + + if (INTEL_GEN(dev_priv) >= 10) + return true; + + if (IS_GEMINILAKE(dev_priv)) + return pipe != PIPE_C; + + return pipe != PIPE_C && + (plane_id == PLANE_PRIMARY || + plane_id == PLANE_SPRITE0); +} + struct intel_plane * intel_sprite_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe, int plane) @@ -1315,7 +1346,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, } intel_plane->base.state = &state->base; - if (INTEL_GEN(dev_priv) >= 10) { + if (INTEL_GEN(dev_priv) >= 9) { intel_plane->can_scale = true; state->scaler_id = -1; @@ -1325,18 +1356,11 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, plane_formats = skl_plane_formats; num_plane_formats = ARRAY_SIZE(skl_plane_formats); - modifiers = skl_plane_format_modifiers; - } else if (INTEL_GEN(dev_priv) >= 9) { - intel_plane->can_scale = true; - state->scaler_id = -1; - intel_plane->update_plane = skl_update_plane; - intel_plane->disable_plane = skl_disable_plane; - intel_plane->get_hw_state = skl_plane_get_hw_state; - - plane_formats = skl_plane_formats; - num_plane_formats = ARRAY_SIZE(skl_plane_formats); - modifiers = skl_plane_format_modifiers; + if (skl_plane_has_ccs(dev_priv, pipe, PLANE_SPRITE0 + plane)) + modifiers = skl_plane_format_modifiers_ccs; + else + modifiers = skl_plane_format_modifiers_noccs; } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { intel_plane->can_scale = false; intel_plane->max_downscale = 1; From 8a97bbcce8c416063b2bdec978d3b242a59de9fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 22 Dec 2017 21:22:29 +0200 Subject: [PATCH 061/158] drm/i915: Allow up to 32KB stride on SKL+ "sprites" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SKL+ "sprites" no longer have 16KB max stride limit that earlier platforms had. Bump up the limit to 32KB. Cc: Ben Widawsky Cc: Jason Ekstrand Cc: Daniel Stone Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20171222192231.17981-7-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index cb06acff283d..94188488db05 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -865,6 +865,7 @@ intel_check_sprite_plane(struct intel_plane *plane, struct drm_rect *src = &state->base.src; struct drm_rect *dst = &state->base.dst; const struct drm_rect *clip = &state->clip; + int max_stride = INTEL_GEN(dev_priv) >= 9 ? 32768 : 16384; int hscale, vscale; int max_scale, min_scale; bool can_scale; @@ -885,7 +886,7 @@ intel_check_sprite_plane(struct intel_plane *plane, } /* FIXME check all gen limits */ - if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) { + if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > max_stride) { DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n"); return -EINVAL; } From 0b7029b7e43fda1304c181a3ade0b429b9edcd9d Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Mon, 18 Dec 2017 10:04:03 +0200 Subject: [PATCH 062/158] drm/i915: Check for fused or unused pipes We may have fused or unused pipes in our system. Let's check that the pipe in question is within limits of accessible pipes. In case, that we are not able to access the pipe, we return early with a warning. v2: Rephrasing of the commit message (Jani) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103206 Reported-by: Thomas Gleixner Tested-by: Jaswinder Singh Rajput Suggested-by: Jani Nikula Reviewed-by: Jani Nikula Signed-off-by: Mika Kahola Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/1513584243-12607-1-git-send-email-mika.kahola@intel.com --- drivers/gpu/drm/i915/intel_audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index f1502a0188eb..522d54fecb53 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -779,7 +779,7 @@ static struct intel_encoder *get_saved_enc(struct drm_i915_private *dev_priv, { struct intel_encoder *encoder; - if (WARN_ON(pipe >= INTEL_INFO(dev_priv)->num_pipes)) + if (WARN_ON(pipe >= ARRAY_SIZE(dev_priv->av_enc_map))) return NULL; /* MST */ From 841b5ed7aaec4578cd7303fb7f456f01b90dd313 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 11 Jan 2018 16:00:03 -0200 Subject: [PATCH 063/158] drm/i915/cnl: Add Port F definition. Some Cannonlake SKUs will come with a full split between port A and port E. This will be called port F although it is not a 6th port, but only a split. Note this patch alone is not sufficient for port F enabling, it's just the first step. v2: Fix size of dvo_ports found by Ander. v3: Adding missing cases from intel_bios.c for Port_F v4: Adding other missing cases and fix the commit message. v5: Rebase on top of display headers rework. v6 (from Paulo): improve commit message, bikeshed bit definitions. Cc: Lucas De Marchi Cc: Manasi Navare Acked-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Rodrigo Vivi Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180111180010.24357-2-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_bios.c | 9 +++++++++ drivers/gpu/drm/i915/intel_display.h | 1 + drivers/gpu/drm/i915/intel_dp.c | 2 ++ drivers/gpu/drm/i915/intel_vbt_defs.h | 2 ++ include/drm/i915_component.h | 3 +-- 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index b820d595ebc8..b0668202dc7e 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1140,6 +1140,7 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, {DVO_PORT_HDMIC, DVO_PORT_DPC, -1}, {DVO_PORT_HDMID, DVO_PORT_DPD, -1}, {DVO_PORT_CRT, DVO_PORT_HDMIE, DVO_PORT_DPE}, + {DVO_PORT_HDMIF, DVO_PORT_DPF, -1}, }; /* @@ -1690,6 +1691,7 @@ bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port por [PORT_C] = { DVO_PORT_DPC, DVO_PORT_HDMIC, }, [PORT_D] = { DVO_PORT_DPD, DVO_PORT_HDMID, }, [PORT_E] = { DVO_PORT_DPE, DVO_PORT_HDMIE, }, + [PORT_F] = { DVO_PORT_DPF, DVO_PORT_HDMIF, }, }; int i; @@ -1728,6 +1730,7 @@ bool intel_bios_is_port_edp(struct drm_i915_private *dev_priv, enum port port) [PORT_C] = DVO_PORT_DPC, [PORT_D] = DVO_PORT_DPD, [PORT_E] = DVO_PORT_DPE, + [PORT_F] = DVO_PORT_DPF, }; int i; @@ -1763,6 +1766,7 @@ static bool child_dev_is_dp_dual_mode(const struct child_device_config *child, [PORT_C] = { DVO_PORT_DPC, DVO_PORT_HDMIC, }, [PORT_D] = { DVO_PORT_DPD, DVO_PORT_HDMID, }, [PORT_E] = { DVO_PORT_DPE, DVO_PORT_HDMIE, }, + [PORT_F] = { DVO_PORT_DPF, DVO_PORT_HDMIF, }, }; if (port == PORT_A || port >= ARRAY_SIZE(port_mapping)) @@ -1929,6 +1933,11 @@ intel_bios_is_lspcon_present(struct drm_i915_private *dev_priv, if (port == PORT_D) return true; break; + case DVO_PORT_DPF: + case DVO_PORT_HDMIF: + if (port == PORT_F) + return true; + break; default: break; } diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h index a0d2b6169361..e47638931b51 100644 --- a/drivers/gpu/drm/i915/intel_display.h +++ b/drivers/gpu/drm/i915/intel_display.h @@ -119,6 +119,7 @@ enum port { PORT_C, PORT_D, PORT_E, + PORT_F, I915_MAX_PORTS }; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 35c5299feab6..71721de39e6b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1378,6 +1378,7 @@ static i915_reg_t skl_aux_ctl_reg(struct drm_i915_private *dev_priv, case PORT_B: case PORT_C: case PORT_D: + case PORT_F: return DP_AUX_CH_CTL(port); default: MISSING_CASE(port); @@ -1393,6 +1394,7 @@ static i915_reg_t skl_aux_data_reg(struct drm_i915_private *dev_priv, case PORT_B: case PORT_C: case PORT_D: + case PORT_F: return DP_AUX_CH_DATA(port, index); default: MISSING_CASE(port); diff --git a/drivers/gpu/drm/i915/intel_vbt_defs.h b/drivers/gpu/drm/i915/intel_vbt_defs.h index 3f5eff49105b..3d3feee9b5dd 100644 --- a/drivers/gpu/drm/i915/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/intel_vbt_defs.h @@ -299,6 +299,8 @@ struct bdb_general_features { #define DVO_PORT_DPA 10 #define DVO_PORT_DPE 11 /* 193 */ #define DVO_PORT_HDMIE 12 /* 193 */ +#define DVO_PORT_DPF 13 /* N/A */ +#define DVO_PORT_HDMIF 14 /* N/A */ #define DVO_PORT_MIPIA 21 /* 171 */ #define DVO_PORT_MIPIB 22 /* 171 */ #define DVO_PORT_MIPIC 23 /* 171 */ diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h index 545c6e0fea7d..346b1f5cb180 100644 --- a/include/drm/i915_component.h +++ b/include/drm/i915_component.h @@ -26,9 +26,8 @@ /* MAX_PORT is the number of port * It must be sync with I915_MAX_PORTS defined i915_drv.h - * 5 should be enough as only HSW, BDW, SKL need such fix. */ -#define MAX_PORTS 5 +#define MAX_PORTS 6 /** * struct i915_audio_component_ops - Ops implemented by i915 driver, called by hda driver From 412310019a20d30e7205c98c314d1f0325922cb4 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 11 Jan 2018 16:00:04 -0200 Subject: [PATCH 064/158] drm/i915/icl: Add initial Icelake definitions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Icelake is an Intel® Processor containing an Intel® Graphics Controller. This is just an initial Icelake definition. PCI IDs, Icelake support and new features coming in following patches. v2: Add .ddb_size and .has_guc (Michal Wajdeczko). v3: Add the ICL_FEATURES macro (Kelvin Gardiner). v4 (from Paulo): Add missing __initconst (Paulo) and say "graphics controller" instead of something that looks like an official marketing name but isn't (Chris). Reviewed-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Rodrigo Vivi Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180111180010.24357-3-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_pci.c | 13 +++++++++++++ drivers/gpu/drm/i915/intel_device_info.c | 1 + drivers/gpu/drm/i915/intel_device_info.h | 2 ++ 4 files changed, 18 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 905d1e32ef6a..a4792d1fe953 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2594,6 +2594,7 @@ intel_info(const struct drm_i915_private *dev_priv) #define IS_GEMINILAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_GEMINILAKE) #define IS_COFFEELAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_COFFEELAKE) #define IS_CANNONLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_CANNONLAKE) +#define IS_ICELAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_ICELAKE) #define IS_MOBILE(dev_priv) ((dev_priv)->info.is_mobile) #define IS_HSW_EARLY_SDV(dev_priv) (IS_HASWELL(dev_priv) && \ (INTEL_DEVID(dev_priv) & 0xFF00) == 0x0C00) @@ -2705,6 +2706,7 @@ intel_info(const struct drm_i915_private *dev_priv) #define IS_GEN8(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(7))) #define IS_GEN9(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(8))) #define IS_GEN10(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(9))) +#define IS_GEN11(dev_priv) (!!((dev_priv)->info.gen_mask & BIT(10))) #define IS_LP(dev_priv) (INTEL_INFO(dev_priv)->is_lp) #define IS_GEN9_LP(dev_priv) (IS_GEN9(dev_priv) && IS_LP(dev_priv)) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 36d48422b475..f28c165fc49d 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -579,6 +579,19 @@ static const struct intel_device_info intel_cannonlake_gt2_info __initconst = { .gt = 2, }; +#define GEN11_FEATURES \ + GEN10_FEATURES, \ + .gen = 11, \ + .ddb_size = 2048, \ + .has_csr = 0 + +static const struct intel_device_info intel_icelake_11_info __initconst = { + GEN11_FEATURES, + .platform = INTEL_ICELAKE, + .is_alpha_support = 1, + .has_resource_streamer = 0, +}; + /* * Make sure any device matches here are from most specific to most * general. For example, since the Quanta match is based on the subsystem diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index d28592e43512..a2c16140169f 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -56,6 +56,7 @@ static const char * const platform_names[] = { PLATFORM_NAME(GEMINILAKE), PLATFORM_NAME(COFFEELAKE), PLATFORM_NAME(CANNONLAKE), + PLATFORM_NAME(ICELAKE), }; #undef PLATFORM_NAME diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index 49cb27bd04c1..9542018d11d0 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -69,6 +69,8 @@ enum intel_platform { INTEL_COFFEELAKE, /* gen10 */ INTEL_CANNONLAKE, + /* gen11 */ + INTEL_ICELAKE, INTEL_MAX_PLATFORMS }; From 0b58436f2d9ad20a4622e96a7a024e6f196f127e Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Thu, 11 Jan 2018 16:00:05 -0200 Subject: [PATCH 065/158] drm/i915/icp: Introduce Ice Lake PCH Add the enum additions to ICP PCH. v2 (from Paulo): don't set any platforms to it yet since ICP support is incomplete. v3 (from Rodrigo): Fix ICP name. Reviewed-by: Paulo Zanoni Signed-off-by: Anusha Srivatsa Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180111180010.24357-4-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a4792d1fe953..3f95799c0ca6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -782,6 +782,7 @@ enum intel_pch { PCH_SPT, /* Sunrisepoint PCH */ PCH_KBP, /* Kaby Lake PCH */ PCH_CNP, /* Cannon Lake PCH */ + PCH_ICP, /* Ice Lake PCH */ PCH_NOP, }; @@ -2849,6 +2850,7 @@ intel_info(const struct drm_i915_private *dev_priv) #define INTEL_PCH_QEMU_DEVICE_ID_TYPE 0x2900 /* qemu q35 has 2918 */ #define INTEL_PCH_TYPE(dev_priv) ((dev_priv)->pch_type) +#define HAS_PCH_ICP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_ICP) #define HAS_PCH_CNP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_CNP) #define HAS_PCH_CNP_LP(dev_priv) \ ((dev_priv)->pch_id == INTEL_PCH_CNP_LP_DEVICE_ID_TYPE) From 4ef99abd07ef3ceb014b4359ec4a977d7ae8a8f9 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Thu, 11 Jan 2018 16:00:06 -0200 Subject: [PATCH 066/158] drm/i915/icp: Get/set proper Raw clock frequency on ICP Add register definitions for setting the rawclock. Set the numerator,denominator and divider values. v2: Simplify the commit message. Simplify the math. Add register bits for numerator. (Paulo) v3 (from Paulo): coding style bikesheds. Reviewed-by: Paulo Zanoni Signed-off-by: Anusha Srivatsa Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180111180010.24357-5-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_cdclk.c | 29 +++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3ed5d49aa46d..79fa4739b64b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7351,6 +7351,8 @@ enum { #define CNP_RAWCLK_DIV(div) ((div) << 16) #define CNP_RAWCLK_FRAC_MASK (0xf << 26) #define CNP_RAWCLK_FRAC(frac) ((frac) << 26) +#define ICP_RAWCLK_DEN(den) ((den) << 26) +#define ICP_RAWCLK_NUM(num) ((num) << 11) #define PCH_DPLL_TMR_CFG _MMIO(0xc6208) diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index f46a61d423a1..c4392ea34a3d 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -2343,6 +2343,30 @@ static int cnp_rawclk(struct drm_i915_private *dev_priv) return divider + fraction; } +static int icp_rawclk(struct drm_i915_private *dev_priv) +{ + u32 rawclk; + int divider, numerator, denominator, frequency; + + if (I915_READ(SFUSE_STRAP) & SFUSE_STRAP_RAW_FREQUENCY) { + frequency = 24000; + divider = 23; + numerator = 0; + denominator = 0; + } else { + frequency = 19200; + divider = 18; + numerator = 1; + denominator = 4; + } + + rawclk = CNP_RAWCLK_DIV(divider) | ICP_RAWCLK_NUM(numerator) | + ICP_RAWCLK_DEN(denominator); + + I915_WRITE(PCH_RAWCLK_FREQ, rawclk); + return frequency; +} + static int pch_rawclk(struct drm_i915_private *dev_priv) { return (I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK) * 1000; @@ -2390,8 +2414,9 @@ static int g4x_hrawclk(struct drm_i915_private *dev_priv) */ void intel_update_rawclk(struct drm_i915_private *dev_priv) { - - if (HAS_PCH_CNP(dev_priv)) + if (HAS_PCH_ICP(dev_priv)) + dev_priv->rawclk_freq = icp_rawclk(dev_priv); + else if (HAS_PCH_CNP(dev_priv)) dev_priv->rawclk_freq = cnp_rawclk(dev_priv); else if (HAS_PCH_SPLIT(dev_priv)) dev_priv->rawclk_freq = pch_rawclk(dev_priv); From b0d6a0f27e2ce77dc48527404d3a15ebf1b5d26d Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Thu, 11 Jan 2018 16:00:07 -0200 Subject: [PATCH 067/158] drm/i915/icp: Add Panel Power Sequencing Support ICP, like BXT, has has two panel power sequencers. v2: Simplify the code. Remove unwanted register definitions. Make code as close to BXT style as possible. (Ville) Also, remove the use of ICP_SECOND_PPS_BACKLIGHT for now. Moving forward, if we are sure we need to set this register, we can access it. v3: Use INTEL_GEN(dev_priv), make code more readeable. (Ville) v4 (from Paulo): - Coding style fixes. - Add a missing HAS_PCH_CNP -> gen10+ check. - Rebase. v5: Use per platform checks rather than INTEL_GEN(). v4 of this patch breaks on CoffeeLake, since CFL uses CNP and per platform check makes sense in that case. v6 (from Paulo): - v5 was a patch on top of v4, not a new version. Now v6 is correctly a new version of the original patch. Cc: Ville Syrjala Reviewed-by: Paulo Zanoni Signed-off-by: Anusha Srivatsa Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180111180010.24357-6-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 71721de39e6b..48342a85e500 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -794,7 +794,8 @@ static void intel_pps_get_registers(struct intel_dp *intel_dp, regs->pp_stat = PP_STATUS(pps_idx); regs->pp_on = PP_ON_DELAYS(pps_idx); regs->pp_off = PP_OFF_DELAYS(pps_idx); - if (!IS_GEN9_LP(dev_priv) && !HAS_PCH_CNP(dev_priv)) + if (!IS_GEN9_LP(dev_priv) && !HAS_PCH_CNP(dev_priv) && + !HAS_PCH_ICP(dev_priv)) regs->pp_div = PP_DIVISOR(pps_idx); } @@ -5229,7 +5230,8 @@ intel_pps_readout_hw_state(struct intel_dp *intel_dp, struct edp_power_seq *seq) pp_on = I915_READ(regs.pp_on); pp_off = I915_READ(regs.pp_off); - if (!IS_GEN9_LP(dev_priv) && !HAS_PCH_CNP(dev_priv)) { + if (!IS_GEN9_LP(dev_priv) && !HAS_PCH_CNP(dev_priv) && + !HAS_PCH_ICP(dev_priv)) { I915_WRITE(regs.pp_ctrl, pp_ctl); pp_div = I915_READ(regs.pp_div); } @@ -5247,7 +5249,8 @@ intel_pps_readout_hw_state(struct intel_dp *intel_dp, struct edp_power_seq *seq) seq->t10 = (pp_off & PANEL_POWER_DOWN_DELAY_MASK) >> PANEL_POWER_DOWN_DELAY_SHIFT; - if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv)) { + if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv) || + HAS_PCH_ICP(dev_priv)) { seq->t11_t12 = ((pp_ctl & BXT_POWER_CYCLE_DELAY_MASK) >> BXT_POWER_CYCLE_DELAY_SHIFT) * 1000; } else { @@ -5418,7 +5421,8 @@ intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp, (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT); /* Compute the divisor for the pp clock, simply match the Bspec * formula. */ - if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv)) { + if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv) || + HAS_PCH_ICP(dev_priv)) { pp_div = I915_READ(regs.pp_ctrl); pp_div &= ~BXT_POWER_CYCLE_DELAY_MASK; pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000) @@ -5444,7 +5448,8 @@ intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp, I915_WRITE(regs.pp_on, pp_on); I915_WRITE(regs.pp_off, pp_off); - if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv)) + if (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv) || + HAS_PCH_ICP(dev_priv)) I915_WRITE(regs.pp_ctrl, pp_div); else I915_WRITE(regs.pp_div, pp_div); @@ -5452,7 +5457,8 @@ intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp, DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n", I915_READ(regs.pp_on), I915_READ(regs.pp_off), - (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv)) ? + (IS_GEN9_LP(dev_priv) || HAS_PCH_CNP(dev_priv) || + HAS_PCH_ICP(dev_priv)) ? (I915_READ(regs.pp_ctrl) & BXT_POWER_CYCLE_DELAY_MASK) : I915_READ(regs.pp_div)); } From ccf6e0d9774657892e6715d519ea1c48c692158a Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Fri, 19 Jan 2018 16:48:12 -0200 Subject: [PATCH 068/158] drm/i915/icp: Add backlight Support for ICP ICP has two backlight controllers - similar to previous platforms like BXT -, but we only use one controller for now, so we can just reuse the CNP code. v2: Remove the usage of ICP_SECOND_PPS_BACKLIGHT register.(Jani) Reuse CNP code since it is very similar.(Ville) v3 (from Paulo): Rebase. v4 (from Paulo): adjust commit message (James) and comment (Rodrigo). Cc: Jani Nikula Cc: Ville Syrjala Acked-by: Rodrigo Vivi Acked-by: James Ausmus Reviewed-by: Paulo Zanoni Signed-off-by: Anusha Srivatsa Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180119184812.2888-1-paulo.r.zanoni@intel.com Signed-off-by: Paulo Zanoni --- drivers/gpu/drm/i915/intel_panel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index fa6831f8c004..e702a6487aa9 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -1719,9 +1719,9 @@ cnp_setup_backlight(struct intel_connector *connector, enum pipe unused) u32 pwm_ctl, val; /* - * CNP has the BXT implementation of backlight, but with only - * one controller. Future platforms could have multiple controllers - * so let's make this extensible and prepared for the future. + * CNP has the BXT implementation of backlight, but with only one + * controller. TODO: ICP has multiple controllers but we only use + * controller 0 for now. */ panel->backlight.controller = 0; @@ -1865,7 +1865,7 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel) panel->backlight.set = bxt_set_backlight; panel->backlight.get = bxt_get_backlight; panel->backlight.hz_to_pwm = bxt_hz_to_pwm; - } else if (HAS_PCH_CNP(dev_priv)) { + } else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_ICP(dev_priv)) { panel->backlight.setup = cnp_setup_backlight; panel->backlight.enable = cnp_enable_backlight; panel->backlight.disable = cnp_disable_backlight; From 5c749c522faca5124d849c3327b5bfa668b122ca Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Thu, 11 Jan 2018 16:00:09 -0200 Subject: [PATCH 069/158] drm/i915/icp: add ICP gmbus and gpio support In ICP, there are three TC ports and 3 DDI ports. v2: - Correct Pin mapping. v3: - Update pin mapping into per platform implementation rather than previous approach of port wise mapping. v4: - Update GMBUS_NUM_PINS (Paulo) v5: - rebase. v6: - Update function name, GMBUS_PIN_NUM (Paulo) v7 (from Paulo): - Make it apply. v8 (from Paulo): - Maintain consistent if ladder ordering. Suggested by: Ville Syrjala Cc: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Anusha Srivatsa Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180111180010.24357-8-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 7 ++++++- drivers/gpu/drm/i915/intel_hdmi.c | 33 +++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_i2c.c | 17 ++++++++++++++-- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 79fa4739b64b..1b28669f4f99 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3063,7 +3063,12 @@ enum i915_power_well_id { #define GMBUS_PIN_2_BXT 2 #define GMBUS_PIN_3_BXT 3 #define GMBUS_PIN_4_CNP 4 -#define GMBUS_NUM_PINS 7 /* including 0 */ +#define GMBUS_PIN_9_TC1_ICP 9 +#define GMBUS_PIN_10_TC2_ICP 10 +#define GMBUS_PIN_11_TC3_ICP 11 +#define GMBUS_PIN_12_TC4_ICP 12 + +#define GMBUS_NUM_PINS 13 /* including 0 */ #define GMBUS1 _MMIO(dev_priv->gpio_mmio_base + 0x5104) /* command/status */ #define GMBUS_SW_CLR_INT (1<<31) #define GMBUS_SW_RDY (1<<30) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 93e97f9e1aac..303c6d5acbde 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1943,6 +1943,37 @@ static u8 cnp_port_to_ddc_pin(struct drm_i915_private *dev_priv, return ddc_pin; } +static u8 icl_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port) +{ + u8 ddc_pin; + + switch (port) { + case PORT_A: + ddc_pin = GMBUS_PIN_1_BXT; + break; + case PORT_B: + ddc_pin = GMBUS_PIN_2_BXT; + break; + case PORT_C: + ddc_pin = GMBUS_PIN_9_TC1_ICP; + break; + case PORT_D: + ddc_pin = GMBUS_PIN_10_TC2_ICP; + break; + case PORT_E: + ddc_pin = GMBUS_PIN_11_TC3_ICP; + break; + case PORT_F: + ddc_pin = GMBUS_PIN_12_TC4_ICP; + break; + default: + MISSING_CASE(port); + ddc_pin = GMBUS_PIN_2_BXT; + break; + } + return ddc_pin; +} + static u8 g4x_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port) { @@ -1985,6 +2016,8 @@ static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv, ddc_pin = bxt_port_to_ddc_pin(dev_priv, port); else if (HAS_PCH_CNP(dev_priv)) ddc_pin = cnp_port_to_ddc_pin(dev_priv, port); + else if (IS_ICELAKE(dev_priv)) + ddc_pin = icl_port_to_ddc_pin(dev_priv, port); else ddc_pin = g4x_port_to_ddc_pin(dev_priv, port); diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index ef9f91a0b0c9..ad1b1a345f2e 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -75,11 +75,22 @@ static const struct gmbus_pin gmbus_pins_cnp[] = { [GMBUS_PIN_4_CNP] = { "dpd", GPIOE }, }; +static const struct gmbus_pin gmbus_pins_icp[] = { + [GMBUS_PIN_1_BXT] = { "dpa", GPIOA }, + [GMBUS_PIN_2_BXT] = { "dpb", GPIOB }, + [GMBUS_PIN_9_TC1_ICP] = { "tc1", GPIOC }, + [GMBUS_PIN_10_TC2_ICP] = { "tc2", GPIOD }, + [GMBUS_PIN_11_TC3_ICP] = { "tc3", GPIOE }, + [GMBUS_PIN_12_TC4_ICP] = { "tc4", GPIOF }, +}; + /* pin is expected to be valid */ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *dev_priv, unsigned int pin) { - if (HAS_PCH_CNP(dev_priv)) + if (HAS_PCH_ICP(dev_priv)) + return &gmbus_pins_icp[pin]; + else if (HAS_PCH_CNP(dev_priv)) return &gmbus_pins_cnp[pin]; else if (IS_GEN9_LP(dev_priv)) return &gmbus_pins_bxt[pin]; @@ -96,7 +107,9 @@ bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv, { unsigned int size; - if (HAS_PCH_CNP(dev_priv)) + if (HAS_PCH_ICP(dev_priv)) + size = ARRAY_SIZE(gmbus_pins_icp); + else if (HAS_PCH_CNP(dev_priv)) size = ARRAY_SIZE(gmbus_pins_cnp); else if (IS_GEN9_LP(dev_priv)) size = ARRAY_SIZE(gmbus_pins_bxt); From 5c8ea01830b1e5a29b6a949e6b69eb606d335fa9 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Thu, 11 Jan 2018 16:00:10 -0200 Subject: [PATCH 070/158] drm/i915/icp: Add the ID for ICL PCH - ICP Add the PCI ID for the ICL PCH - ICP. v2: rebased. v3: rebased. v4: fix ICP name. v5: fix the ID mask (Fei Li). v6 (from Paulo): bikesheds. Cc: Li, Fei Reviewed-by: Paulo Zanoni Signed-off-by: Anusha Srivatsa Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180111180010.24357-9-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 4 ++++ drivers/gpu/drm/i915/i915_drv.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 173d0095e3b2..1fbe37889d92 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -252,6 +252,10 @@ static void intel_detect_pch(struct drm_i915_private *dev_priv) DRM_DEBUG_KMS("Found Cannon Lake LP PCH (CNP-LP)\n"); WARN_ON(!IS_CANNONLAKE(dev_priv) && !IS_COFFEELAKE(dev_priv)); + } else if (id == INTEL_PCH_ICP_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_ICP; + DRM_DEBUG_KMS("Found Ice Lake PCH\n"); + WARN_ON(!IS_ICELAKE(dev_priv)); } else if (id == INTEL_PCH_P2X_DEVICE_ID_TYPE || id == INTEL_PCH_P3X_DEVICE_ID_TYPE || (id == INTEL_PCH_QEMU_DEVICE_ID_TYPE && diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3f95799c0ca6..c707eee2102b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2845,6 +2845,7 @@ intel_info(const struct drm_i915_private *dev_priv) #define INTEL_PCH_KBP_DEVICE_ID_TYPE 0xA280 #define INTEL_PCH_CNP_DEVICE_ID_TYPE 0xA300 #define INTEL_PCH_CNP_LP_DEVICE_ID_TYPE 0x9D80 +#define INTEL_PCH_ICP_DEVICE_ID_TYPE 0x3480 #define INTEL_PCH_P2X_DEVICE_ID_TYPE 0x7100 #define INTEL_PCH_P3X_DEVICE_ID_TYPE 0x7000 #define INTEL_PCH_QEMU_DEVICE_ID_TYPE 0x2900 /* qemu q35 has 2918 */ From a6358dda29a2caa7967833698e690684a031f10d Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 9 Jan 2018 21:23:13 -0200 Subject: [PATCH 071/158] drm/i915/icl: Icelake interrupt register addresses and bits MMIO addresses and register definition for the new interrupt registers in Gen11. v2: Removed spelt out VCS and VECS bit definitions. (Daniel Vetter) v3: Adjust VCS and VECS. (Daniele Ceraolo Spurio) v4: Bikeshedding (Paulo). Cc: Daniele Ceraolo Spurio Reviewed-by: Paulo Zanoni Signed-off-by: Tvrtko Ursulin Signed-off-by: Rodrigo Vivi Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180109232336.11029-5-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 63 +++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1b28669f4f99..43ac9be7c746 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6962,6 +6962,69 @@ enum { #define GEN8_PCU_IIR _MMIO(0x444e8) #define GEN8_PCU_IER _MMIO(0x444ec) +#define GEN11_GFX_MSTR_IRQ _MMIO(0x190010) +#define GEN11_MASTER_IRQ (1 << 31) +#define GEN11_PCU_IRQ (1 << 30) +#define GEN11_DISPLAY_IRQ (1 << 16) +#define GEN11_GT_DW_IRQ(x) (1 << (x)) +#define GEN11_GT_DW1_IRQ (1 << 1) +#define GEN11_GT_DW0_IRQ (1 << 0) + +#define GEN11_DISPLAY_INT_CTL _MMIO(0x44200) +#define GEN11_DISPLAY_IRQ_ENABLE (1 << 31) +#define GEN11_AUDIO_CODEC_IRQ (1 << 24) +#define GEN11_DE_PCH_IRQ (1 << 23) +#define GEN11_DE_MISC_IRQ (1 << 22) +#define GEN11_DE_PORT_IRQ (1 << 20) +#define GEN11_DE_PIPE_C (1 << 18) +#define GEN11_DE_PIPE_B (1 << 17) +#define GEN11_DE_PIPE_A (1 << 16) + +#define GEN11_GT_INTR_DW0 _MMIO(0x190018) +#define GEN11_CSME (31) +#define GEN11_GUNIT (28) +#define GEN11_GUC (25) +#define GEN11_WDPERF (20) +#define GEN11_KCR (19) +#define GEN11_GTPM (16) +#define GEN11_BCS (15) +#define GEN11_RCS0 (0) + +#define GEN11_GT_INTR_DW1 _MMIO(0x19001c) +#define GEN11_VECS(x) (31 - (x)) +#define GEN11_VCS(x) (x) + +#define GEN11_GT_INTR_DW(x) _MMIO(0x190018 + (x * 4)) + +#define GEN11_INTR_IDENTITY_REG0 _MMIO(0x190060) +#define GEN11_INTR_IDENTITY_REG1 _MMIO(0x190064) +#define GEN11_INTR_DATA_VALID (1 << 31) +#define GEN11_INTR_ENGINE_MASK (0xffff) + +#define GEN11_INTR_IDENTITY_REG(x) _MMIO(0x190060 + (x * 4)) + +#define GEN11_IIR_REG0_SELECTOR _MMIO(0x190070) +#define GEN11_IIR_REG1_SELECTOR _MMIO(0x190074) + +#define GEN11_IIR_REG_SELECTOR(x) _MMIO(0x190070 + (x * 4)) + +#define GEN11_RENDER_COPY_INTR_ENABLE _MMIO(0x190030) +#define GEN11_VCS_VECS_INTR_ENABLE _MMIO(0x190034) +#define GEN11_GUC_SG_INTR_ENABLE _MMIO(0x190038) +#define GEN11_GPM_WGBOXPERF_INTR_ENABLE _MMIO(0x19003c) +#define GEN11_CRYPTO_RSVD_INTR_ENABLE _MMIO(0x190040) +#define GEN11_GUNIT_CSME_INTR_ENABLE _MMIO(0x190044) + +#define GEN11_RCS0_RSVD_INTR_MASK _MMIO(0x190090) +#define GEN11_BCS_RSVD_INTR_MASK _MMIO(0x1900a0) +#define GEN11_VCS0_VCS1_INTR_MASK _MMIO(0x1900a8) +#define GEN11_VCS2_VCS3_INTR_MASK _MMIO(0x1900ac) +#define GEN11_VECS0_VECS1_INTR_MASK _MMIO(0x1900d0) +#define GEN11_GUC_SG_INTR_MASK _MMIO(0x1900e8) +#define GEN11_GPM_WGBOXPERF_INTR_MASK _MMIO(0x1900ec) +#define GEN11_CRYPTO_RSVD_INTR_MASK _MMIO(0x1900f0) +#define GEN11_GUNIT_CSME_INTR_MASK _MMIO(0x1900f4) + #define ILK_DISPLAY_CHICKEN2 _MMIO(0x42004) /* Required on all Ironlake and Sandybridge according to the B-Spec. */ #define ILK_ELPIN_409_SELECT (1 << 25) From 7ab4adbd921f9ab69bbe10cc1354a9fb59085a71 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 11 Jan 2018 14:55:06 -0800 Subject: [PATCH 072/158] drm/i915: Return a default RCS context size Instead of returning whatever size the latest GEN used. This is because context sizes for new GENs can go up or down, but the only safe thing to do for missing cases is to use the largest known one, whatever that is. Suggested-by: Rodrigo Vivi Reviewed-by: Daniele Ceraolo Spurio Signed-off-by: Oscar Mateo Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/1515711307-28979-1-git-send-email-oscar.mateo@intel.com --- drivers/gpu/drm/i915/intel_engine_cs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index b221610f2365..3639af5bdc23 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -38,6 +38,7 @@ */ #define HSW_CXT_TOTAL_SIZE (17 * PAGE_SIZE) +#define DEFAULT_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE) #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE) #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE) #define GEN10_LR_CONTEXT_RENDER_SIZE (18 * PAGE_SIZE) @@ -157,6 +158,7 @@ __intel_engine_context_size(struct drm_i915_private *dev_priv, u8 class) switch (INTEL_GEN(dev_priv)) { default: MISSING_CASE(INTEL_GEN(dev_priv)); + return DEFAULT_LR_CONTEXT_RENDER_SIZE; case 10: return GEN10_LR_CONTEXT_RENDER_SIZE; case 9: From b86aa4458ac6e8be44dfb281b8019fc7822f5538 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 11 Jan 2018 14:55:07 -0800 Subject: [PATCH 073/158] drm/i915/icl: Gen11 render context size Gen11 removes the Resource Streamer, which frees up a big chunk of the context image. BSpec indicates 12544 DWORDs (13 pages), plus one page for PPHWSP. Please notice that, when looking at the BSpec context image table, the right filter has to be applied as some rows are excluded for specific GENs. Also, some rows apply per-subslice (for the calculation above, we have supposed I915_MAX_SUBSLICES = 8). v2: Rebase. v3: Use the right size as per the BSpec. v4: - Rebased on top of the default context size (Rodrigo) - Clarify in the commit message where the subslice calculation comes from. v5: s/12538/12544/ (Daniele) BSpec: 18907 Cc: Rodrigo Vivi Acked-by: Ben Widawsky (older version) Reviewed-by: Daniele Ceraolo Spurio Signed-off-by: Tvrtko Ursulin Signed-off-by: Oscar Mateo Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/1515711307-28979-2-git-send-email-oscar.mateo@intel.com --- drivers/gpu/drm/i915/intel_engine_cs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 3639af5bdc23..a1a67f689b3a 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -42,6 +42,7 @@ #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE) #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE) #define GEN10_LR_CONTEXT_RENDER_SIZE (18 * PAGE_SIZE) +#define GEN11_LR_CONTEXT_RENDER_SIZE (14 * PAGE_SIZE) #define GEN8_LR_CONTEXT_OTHER_SIZE ( 2 * PAGE_SIZE) @@ -159,6 +160,8 @@ __intel_engine_context_size(struct drm_i915_private *dev_priv, u8 class) default: MISSING_CASE(INTEL_GEN(dev_priv)); return DEFAULT_LR_CONTEXT_RENDER_SIZE; + case 11: + return GEN11_LR_CONTEXT_RENDER_SIZE; case 10: return GEN10_LR_CONTEXT_RENDER_SIZE; case 9: From bd724318b682587ad2f989ab8e0f7b3d4486ced5 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 19 Jan 2018 12:49:26 +0000 Subject: [PATCH 074/158] drm/i915/guc: Keep GuC log disabled by default It looks that GuC log functionality is not fully functional yet and causes issues when enabled by auto(-1) modparam on debug builds. For example, but not limited to: [ 30.062893] ====================================================== [ 30.062894] WARNING: possible circular locking dependency detected [ 30.062895] 4.15.0-rc8-CI-CI_DRM_3648+ #1 Tainted: G U [ 30.062896] ------------------------------------------------------ [ 30.062897] debugfs_test/1268 is trying to acquire lock: [ 30.062898] (&dev->struct_mutex){+.+.}, at: [<00000000e4213449>] i915_mutex_lock_interruptible+0x47/0x130 [i915] [ 30.062921] but task is already holding lock: [ 30.062921] (&mm->mmap_sem){++++}, at: [<00000000dd7adc93>] __do_page_fault+0x106/0x560 [ 30.062924] which lock already depends on the new lock. References: 0ed87953532652 ("drm/i915/guc: Redefine guc_log_level modparam values") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104693 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104694 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104695 Signed-off-by: Michal Wajdeczko Cc: Chris Wilson Cc: Jani Saarinen Cc: Tomi Sarvela Cc: Marta Lofstedt Cc: Michal Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20180119124926.29844-1-michal.wajdeczko@intel.com Reviewed-by: Michal Winiarski Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_params.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index c96360398072..430f5f9d0ff4 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -48,7 +48,7 @@ struct drm_printer; param(int, enable_ips, 1) \ param(int, invert_brightness, 0) \ param(int, enable_guc, 0) \ - param(int, guc_log_level, -1) \ + param(int, guc_log_level, 0) \ param(char *, guc_firmware_path, NULL) \ param(char *, huc_firmware_path, NULL) \ param(int, mmio_debug, 0) \ From f0111b04ff43ec237fb4419f164a7d1ed1d02bcf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 19 Jan 2018 14:46:57 +0000 Subject: [PATCH 075/158] drm/i915: Shrink the request kmem_cache on allocation error If we fail to allocate a new request, make sure we recover the pages that are in the process of being freed by inserting an RCU barrier. v2: Comment before the shrink and barrier in the error path. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180119144657.22606-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_request.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c index 72bdc203716f..a0f451b4a4e8 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.c +++ b/drivers/gpu/drm/i915/i915_gem_request.c @@ -696,6 +696,17 @@ i915_gem_request_alloc(struct intel_engine_cs *engine, if (ret) goto err_unreserve; + /* + * We've forced the client to stall and catch up with whatever + * backlog there might have been. As we are assuming that we + * caused the mempressure, now is an opportune time to + * recover as much memory from the request pool as is possible. + * Having already penalized the client to stall, we spend + * a little extra time to re-optimise page allocation. + */ + kmem_cache_shrink(dev_priv->requests); + rcu_barrier(); /* Recover the TYPESAFE_BY_RCU pages */ + req = kmem_cache_alloc(dev_priv->requests, GFP_KERNEL); if (!req) { ret = -ENOMEM; From 861023e0b6c44d6373abb3e63f853592adda0e3b Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Wed, 20 Dec 2017 12:10:21 -0800 Subject: [PATCH 076/158] drm/i915/psr: Don't name status or debug registers like control registers. Avoids some typo pitfalls. Cc: Chris Wilson Cc: Rodrigo Vivi Signed-off-by: Dhinakaran Pandiyan Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20171220201021.17619-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++-- drivers/gpu/drm/i915/i915_reg.h | 6 +++--- drivers/gpu/drm/i915/intel_psr.c | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index cc659b4b2a45..80dc679c0f01 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2591,9 +2591,9 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) seq_printf(m, "Performance_Counter: %u\n", psrperf); } if (dev_priv->psr.psr2_support) { - u32 psr2 = I915_READ(EDP_PSR2_STATUS_CTL); + u32 psr2 = I915_READ(EDP_PSR2_STATUS); - seq_printf(m, "EDP_PSR2_STATUS_CTL: %x [%s]\n", + seq_printf(m, "EDP_PSR2_STATUS: %x [%s]\n", psr2, psr2_live_status(psr2)); } mutex_unlock(&dev_priv->psr.lock); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 43ac9be7c746..3dd72d4bb4e0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4071,7 +4071,7 @@ enum { #define EDP_PSR_AUX_CTL _MMIO(dev_priv->psr_mmio_base + 0x10) #define EDP_PSR_AUX_DATA(i) _MMIO(dev_priv->psr_mmio_base + 0x14 + (i) * 4) /* 5 registers */ -#define EDP_PSR_STATUS_CTL _MMIO(dev_priv->psr_mmio_base + 0x40) +#define EDP_PSR_STATUS _MMIO(dev_priv->psr_mmio_base + 0x40) #define EDP_PSR_STATUS_STATE_MASK (7<<29) #define EDP_PSR_STATUS_STATE_IDLE (0<<29) #define EDP_PSR_STATUS_STATE_SRDONACK (1<<29) @@ -4098,7 +4098,7 @@ enum { #define EDP_PSR_PERF_CNT _MMIO(dev_priv->psr_mmio_base + 0x44) #define EDP_PSR_PERF_CNT_MASK 0xffffff -#define EDP_PSR_DEBUG_CTL _MMIO(dev_priv->psr_mmio_base + 0x60) +#define EDP_PSR_DEBUG _MMIO(dev_priv->psr_mmio_base + 0x60) #define EDP_PSR_DEBUG_MASK_MAX_SLEEP (1<<28) #define EDP_PSR_DEBUG_MASK_LPSP (1<<27) #define EDP_PSR_DEBUG_MASK_MEMUP (1<<26) @@ -4121,7 +4121,7 @@ enum { #define EDP_PSR2_IDLE_MASK 0xf #define EDP_PSR2_FRAME_BEFORE_SU(a) ((a)<<4) -#define EDP_PSR2_STATUS_CTL _MMIO(0x6f940) +#define EDP_PSR2_STATUS _MMIO(0x6f940) #define EDP_PSR2_STATUS_STATE_MASK (0xf<<28) #define EDP_PSR2_STATUS_STATE_SHIFT 28 diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 863650366425..e9feffdea899 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -465,7 +465,7 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp, chicken |= PSR2_ADD_VERTICAL_LINE_COUNT; I915_WRITE(CHICKEN_TRANS(cpu_transcoder), chicken); - I915_WRITE(EDP_PSR_DEBUG_CTL, + I915_WRITE(EDP_PSR_DEBUG, EDP_PSR_DEBUG_MASK_MEMUP | EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP | @@ -479,7 +479,7 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp, * preventing other hw tracking issues now we can rely * on frontbuffer tracking. */ - I915_WRITE(EDP_PSR_DEBUG_CTL, + I915_WRITE(EDP_PSR_DEBUG, EDP_PSR_DEBUG_MASK_MEMUP | EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP); @@ -589,7 +589,7 @@ static void hsw_psr_disable(struct intel_dp *intel_dp, 0); if (dev_priv->psr.psr2_support) { - psr_status = EDP_PSR2_STATUS_CTL; + psr_status = EDP_PSR2_STATUS; psr_status_mask = EDP_PSR2_STATUS_STATE_MASK; I915_WRITE(EDP_PSR2_CTL, @@ -597,7 +597,7 @@ static void hsw_psr_disable(struct intel_dp *intel_dp, ~(EDP_PSR2_ENABLE | EDP_SU_TRACK_ENABLE)); } else { - psr_status = EDP_PSR_STATUS_CTL; + psr_status = EDP_PSR_STATUS; psr_status_mask = EDP_PSR_STATUS_STATE_MASK; I915_WRITE(EDP_PSR_CTL, @@ -672,19 +672,19 @@ static void intel_psr_work(struct work_struct *work) if (HAS_DDI(dev_priv)) { if (dev_priv->psr.psr2_support) { if (intel_wait_for_register(dev_priv, - EDP_PSR2_STATUS_CTL, - EDP_PSR2_STATUS_STATE_MASK, - 0, - 50)) { + EDP_PSR2_STATUS, + EDP_PSR2_STATUS_STATE_MASK, + 0, + 50)) { DRM_ERROR("Timed out waiting for PSR2 Idle for re-enable\n"); return; } } else { if (intel_wait_for_register(dev_priv, - EDP_PSR_STATUS_CTL, - EDP_PSR_STATUS_STATE_MASK, - 0, - 50)) { + EDP_PSR_STATUS, + EDP_PSR_STATUS_STATE_MASK, + 0, + 50)) { DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n"); return; } From 073cd7816685ac77c6d8b4d321a5586c9177b76a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 21 Jan 2018 17:31:43 +0000 Subject: [PATCH 077/158] drm/i915: Protect WC stash allocation against direct reclaim As we attempt to allocate pages for use in a new WC stash, direct reclaim may run underneath us and fill up the WC stash. We have to be careful then not to overflow the pvec. Fixes: 66df1014efba ("drm/i915: Keep a small stash of preallocated WC pages") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103109 Signed-off-by: Chris Wilson Cc: Matthew Auld Cc: Joonas Lahtinen Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20180121173143.17090-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 32 ++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 26dee5e61e99..be227512430a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -377,6 +377,7 @@ static gen6_pte_t iris_pte_encode(dma_addr_t addr, static struct page *vm_alloc_page(struct i915_address_space *vm, gfp_t gfp) { struct pagevec *pvec = &vm->free_pages; + struct pagevec stash; if (I915_SELFTEST_ONLY(should_fail(&vm->fault_attr, 1))) i915_gem_shrink_all(vm->i915); @@ -395,7 +396,15 @@ static struct page *vm_alloc_page(struct i915_address_space *vm, gfp_t gfp) if (likely(pvec->nr)) return pvec->pages[--pvec->nr]; - /* Otherwise batch allocate pages to amoritize cost of set_pages_wc. */ + /* + * Otherwise batch allocate pages to amoritize cost of set_pages_wc. + * + * We have to be careful as page allocation may trigger the shrinker + * (via direct reclaim) which will fill up the WC stash underneath us. + * So we add our WB pages into a temporary pvec on the stack and merge + * them into the WC stash after all the allocations are complete. + */ + pagevec_init(&stash); do { struct page *page; @@ -403,15 +412,24 @@ static struct page *vm_alloc_page(struct i915_address_space *vm, gfp_t gfp) if (unlikely(!page)) break; - pvec->pages[pvec->nr++] = page; - } while (pagevec_space(pvec)); + stash.pages[stash.nr++] = page; + } while (stash.nr < pagevec_space(pvec)); - if (unlikely(!pvec->nr)) - return NULL; + if (stash.nr) { + int nr = min_t(int, stash.nr, pagevec_space(pvec)); + struct page **pages = stash.pages + stash.nr - nr; - set_pages_array_wc(pvec->pages, pvec->nr); + if (nr && !set_pages_array_wc(pages, nr)) { + memcpy(pvec->pages + pvec->nr, + pages, sizeof(pages[0]) * nr); + pvec->nr += nr; + stash.nr -= nr; + } - return pvec->pages[--pvec->nr]; + pagevec_release(&stash); + } + + return likely(pvec->nr) ? pvec->pages[--pvec->nr] : NULL; } static void vm_free_pages_release(struct i915_address_space *vm, From c0cfb10d9e1de490e36d3b9d4228c0ea0ca30677 Mon Sep 17 00:00:00 2001 From: Manasi Navare Date: Thu, 12 Oct 2017 12:13:38 -0700 Subject: [PATCH 078/158] drm/i915/edp: Do not do link training fallback or prune modes on EDP In case of eDP because the panel has a fixed mode, the link rate and lane count at which it is trained corresponds to the link BW required to support the native resolution of the panel. In case of panles with lower resolutions where fewer lanes are hooked up internally, that number is reflected in the MAX_LANE_COUNT DPCD register of the panel. So it is pointless to fallback to lower link rate/lane count in case of link training failure on eDP connector since the lower link BW will not support the native resolution of the panel and we cannot prune the preferred mode on the eDP connector. In case of Link training failure on the eDP panel, something is wrong in the HW internally and hence driver errors out with a loud and clear DRM_ERROR message. v2: * Fix the DEBUG_ERROR and add {} in else (Ville Syrjala) Cc: Clinton Taylor Cc: Jim Bride Cc: Jani Nikula Cc: Ville Syrjala Cc: Dave Airlie Cc: Daniel Vetter Signed-off-by: Manasi Navare Reviewed-by: Ville Syrjala Reference: https://bugs.freedesktop.org/show_bug.cgi?id=103369 Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/1507835618-23051-1-git-send-email-manasi.d.navare@intel.com --- drivers/gpu/drm/i915/intel_dp_link_training.c | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c index 05907fa8a553..cf8fef8b6f58 100644 --- a/drivers/gpu/drm/i915/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c @@ -328,14 +328,22 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) return; failure_handling: - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d", - intel_connector->base.base.id, - intel_connector->base.name, - intel_dp->link_rate, intel_dp->lane_count); - if (!intel_dp_get_link_train_fallback_values(intel_dp, - intel_dp->link_rate, - intel_dp->lane_count)) - /* Schedule a Hotplug Uevent to userspace to start modeset */ - schedule_work(&intel_connector->modeset_retry_work); + /* Dont fallback and prune modes if its eDP */ + if (!intel_dp_is_edp(intel_dp)) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d", + intel_connector->base.base.id, + intel_connector->base.name, + intel_dp->link_rate, intel_dp->lane_count); + if (!intel_dp_get_link_train_fallback_values(intel_dp, + intel_dp->link_rate, + intel_dp->lane_count)) + /* Schedule a Hotplug Uevent to userspace to start modeset */ + schedule_work(&intel_connector->modeset_retry_work); + } else { + DRM_ERROR("[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d", + intel_connector->base.base.id, + intel_connector->base.name, + intel_dp->link_rate, intel_dp->lane_count); + } return; } From ae504be2e0099986d678405301e93a739e9f59a7 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 19 Jan 2018 10:00:03 +0000 Subject: [PATCH 079/158] drm/i915: Downgrade incorrect engine constructor usage warnings to development Render engine constructor helpers must only be called from the render engine constructors, but there is no need to burden the production binaries with warnings which can only be triggered during development. Signed-off-by: Tvrtko Ursulin Cc: Michel Thierry Reviewed-by: Chris Wilson Reviewed-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180119100005.9072-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/intel_engine_cs.c | 3 ++- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index a1a67f689b3a..7eebfbb95e89 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1394,7 +1394,8 @@ int init_workarounds_ring(struct intel_engine_cs *engine) struct drm_i915_private *dev_priv = engine->i915; int err; - WARN_ON(engine->id != RCS); + if (GEM_WARN_ON(engine->id != RCS)) + return -EINVAL; dev_priv->workarounds.count = 0; dev_priv->workarounds.hw_whitelist_count[engine->id] = 0; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index ff25f209d0a5..251311e41373 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1414,7 +1414,7 @@ static int intel_init_workaround_bb(struct intel_engine_cs *engine) unsigned int i; int ret; - if (WARN_ON(engine->id != RCS || !engine->scratch)) + if (GEM_WARN_ON(engine->id != RCS || !engine->scratch)) return -EINVAL; switch (INTEL_GEN(engine->i915)) { From 10bde236eff901407bdbcad2e605edaf7ba23bdb Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 19 Jan 2018 10:00:04 +0000 Subject: [PATCH 080/158] drm/i915: Per-engine scratch VMA is mandatory We fail engine initialization if the scratch VMA cannot be created so there is no point in error handle it later. If the initialization ordering gets messed up, we can explode during development just as well. Signed-off-by: Tvrtko Ursulin Reviewed-by: Chris Wilson Reviewed-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180119100005.9072-2-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 251311e41373..51e61b04a555 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1414,7 +1414,7 @@ static int intel_init_workaround_bb(struct intel_engine_cs *engine) unsigned int i; int ret; - if (GEM_WARN_ON(engine->id != RCS || !engine->scratch)) + if (GEM_WARN_ON(engine->id != RCS)) return -EINVAL; switch (INTEL_GEN(engine->i915)) { From c1beabcf143c72ecdfe76bf50aa6e385a6192d08 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 22 Jan 2018 13:55:41 +0000 Subject: [PATCH 081/158] drm/i915: Increase render/media power gating hysteresis for gen9+ On gen9+, after an idle period the HW will disable the entire power well to conserve power (by preventing current leakage). It takes around a 100 microseconds to bring the power well back online afterwards. With the current hysteresis value of 25us (really 25 * 1280ns), we do not have sufficient time to respond to an interrupt and schedule the next execution before the HW powers itself down. (At present, we prevent this by grabbing the forcewake for prolonged periods of time, but that overkill fixed in the next patch.) The minimum we want to set the power gating hysteresis to is the length of time it takes us to service the GPU, which across a broad spectrum of machines is about 250us. (Note this also brings guc latency into the same ballpark as execlists.) v2: Include some notes on where I plucked the numbers from. Testcase: igt/gem_exec_nop/sequential Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Cc: Michal Wajdeczko Cc: Sagar Arun Kamble Cc: Michel Thierry Cc: Michal Winiarski Reviewed-by: Sagar Arun Kamble Link: https://patchwork.freedesktop.org/patch/msgid/20180122135541.32222-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_pm.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 1db79a860b96..0b92ea1dbd40 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6626,9 +6626,29 @@ static void gen9_enable_rc6(struct drm_i915_private *dev_priv) I915_WRITE(GEN6_RC_SLEEP, 0); - /* 2c: Program Coarse Power Gating Policies. */ - I915_WRITE(GEN9_MEDIA_PG_IDLE_HYSTERESIS, 25); - I915_WRITE(GEN9_RENDER_PG_IDLE_HYSTERESIS, 25); + /* + * 2c: Program Coarse Power Gating Policies. + * + * Bspec's guidance is to use 25us (really 25 * 1280ns) here. What we + * use instead is a more conservative estimate for the maximum time + * it takes us to service a CS interrupt and submit a new ELSP - that + * is the time which the GPU is idle waiting for the CPU to select the + * next request to execute. If the idle hysteresis is less than that + * interrupt service latency, the hardware will automatically gate + * the power well and we will then incur the wake up cost on top of + * the service latency. A similar guide from intel_pstate is that we + * do not want the enable hysteresis to less than the wakeup latency. + * + * igt/gem_exec_nop/sequential provides a rough estimate for the + * service latency, and puts it around 10us for Broadwell (and other + * big core) and around 40us for Broxton (and other low power cores). + * [Note that for legacy ringbuffer submission, this is less than 1us!] + * However, the wakeup latency on Broxton is closer to 100us. To be + * conservative, we have to factor in a context switch on top (due + * to ksoftirqd). + */ + I915_WRITE(GEN9_MEDIA_PG_IDLE_HYSTERESIS, 250); + I915_WRITE(GEN9_RENDER_PG_IDLE_HYSTERESIS, 250); /* 3a: Enable RC6 */ I915_WRITE(GEN6_RC6_THRESHOLD, 37500); /* 37.5/125ms per EI */ From bb5db7e1601b368e7aad5e4ceded75de70f6fddb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 22 Jan 2018 10:07:14 +0000 Subject: [PATCH 082/158] drm/i915/execlists: Skip forcewake for ELSP submission Now that we can read the CSB from the HWSP, we may avoid having to perform mmio reads entirely and so forgo the rigmarole of the forcewake dance. v2: Include forcewake hint for GEM_TRACE readback of mmio. If we don't hold fw ourselves, the reads may return garbage. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180122100714.15137-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 51e61b04a555..22d471a4228d 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -778,6 +778,7 @@ static void execlists_submission_tasklet(unsigned long data) struct intel_engine_execlists * const execlists = &engine->execlists; struct execlist_port * const port = execlists->port; struct drm_i915_private *dev_priv = engine->i915; + bool fw = false; /* We can skip acquiring intel_runtime_pm_get() here as it was taken * on our behalf by the request (see i915_gem_mark_busy()) and it will @@ -788,8 +789,6 @@ static void execlists_submission_tasklet(unsigned long data) */ GEM_BUG_ON(!dev_priv->gt.awake); - intel_uncore_forcewake_get(dev_priv, execlists->fw_domains); - /* Prefer doing test_and_clear_bit() as a two stage operation to avoid * imposing the cost of a locked atomic transaction when submitting a * new request (outside of the context-switch interrupt). @@ -818,6 +817,12 @@ static void execlists_submission_tasklet(unsigned long data) */ __clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); if (unlikely(execlists->csb_head == -1)) { /* following a reset */ + if (!fw) { + intel_uncore_forcewake_get(dev_priv, + execlists->fw_domains); + fw = true; + } + head = readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine))); tail = GEN8_CSB_WRITE_PTR(head); head = GEN8_CSB_READ_PTR(head); @@ -830,10 +835,10 @@ static void execlists_submission_tasklet(unsigned long data) head = execlists->csb_head; tail = READ_ONCE(buf[write_idx]); } - GEM_TRACE("%s cs-irq head=%d [%d], tail=%d [%d]\n", + GEM_TRACE("%s cs-irq head=%d [%d%s], tail=%d [%d%s]\n", engine->name, - head, GEN8_CSB_READ_PTR(readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), - tail, GEN8_CSB_WRITE_PTR(readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine))))); + head, GEN8_CSB_READ_PTR(readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?", + tail, GEN8_CSB_WRITE_PTR(readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?"); while (head != tail) { struct drm_i915_gem_request *rq; @@ -943,7 +948,8 @@ static void execlists_submission_tasklet(unsigned long data) if (!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT)) execlists_dequeue(engine); - intel_uncore_forcewake_put(dev_priv, execlists->fw_domains); + if (fw) + intel_uncore_forcewake_put(dev_priv, execlists->fw_domains); } static void insert_request(struct intel_engine_cs *engine, From a8e6f3888b05c1e7b685800a3371ce050720368f Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Tue, 23 Jan 2018 09:40:50 -0800 Subject: [PATCH 083/158] drm/i915/cnp: Ignore VBT request for know invalid DDC pin. Let's ignore VBT request if the pin is clearly wrong. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104139 Cc: Kai Heng Feng Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180123174050.4261-1-rodrigo.vivi@intel.com Reviewed-by: Radhakrishna Sripada --- drivers/gpu/drm/i915/intel_bios.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index b0668202dc7e..95f0b310d656 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1115,9 +1115,14 @@ static const u8 cnp_ddc_pin_map[] = { static u8 map_ddc_pin(struct drm_i915_private *dev_priv, u8 vbt_pin) { - if (HAS_PCH_CNP(dev_priv) && - vbt_pin > 0 && vbt_pin < ARRAY_SIZE(cnp_ddc_pin_map)) - return cnp_ddc_pin_map[vbt_pin]; + if (HAS_PCH_CNP(dev_priv)) { + if (vbt_pin > 0 && vbt_pin < ARRAY_SIZE(cnp_ddc_pin_map)) + return cnp_ddc_pin_map[vbt_pin]; + if (vbt_pin > GMBUS_PIN_4_CNP) { + DRM_DEBUG_KMS("Ignoring alternate pin: VBT claims DDC pin %d, which is not valid for this platform\n", vbt_pin); + return 0; + } + } return vbt_pin; } From c559c2a071ff01a3b8b9ce38d3b09d3f403cff10 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Tue, 23 Jan 2018 13:52:45 -0800 Subject: [PATCH 084/158] drm/i915/cnl: Fix aux selection for WA 1178 Current code always select _CNL_AUX_ANAOVRD1_B register regardless the pw in use. CNL_DISP_PW_AUX_B = 9 CNL_DISP_PW_AUX_C = 10 CNL_DISP_PW_AUX_D = 11 And for pick we want B = 0 C = 1 D = 2 Fixes: ddd39e4b3f8f ("drm/i915/cnl: apply Display WA #1178 to fix type C dongles") Cc: Lucas De Marchi Signed-off-by: Rodrigo Vivi Acked-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20180123215245.24026-1-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3dd72d4bb4e0..9c56e2165b2a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8420,7 +8420,7 @@ enum skl_power_gate { #define SKL_PW_TO_PG(pw) ((pw) - SKL_DISP_PW_1 + SKL_PG1) #define SKL_FUSE_PG_DIST_STATUS(pg) (1 << (27 - (pg))) -#define _CNL_AUX_REG_IDX(pw) ((pw - 1) >> 4) +#define _CNL_AUX_REG_IDX(pw) ((pw) - 9) #define _CNL_AUX_ANAOVRD1_B 0x162250 #define _CNL_AUX_ANAOVRD1_C 0x162210 #define _CNL_AUX_ANAOVRD1_D 0x1622D0 From 8810bc5609117aad1dd01c1c8c4cd3847ec2fd3e Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 23 Jan 2018 13:45:58 +0000 Subject: [PATCH 085/158] drm/i915/pmu: Fix sysfs exported counter config We need to generate the event config value using the uAPI class and not the driver internal one. Signed-off-by: Tvrtko Ursulin Fixes: 109ec558370f ("drm/i915/pmu: Only enumerate available counters in sysfs") Cc: Tvrtko Ursulin Cc: Chris Wilson Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180123134558.3222-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 065a28c713c4..ecb0198bfb7a 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -843,7 +843,7 @@ create_event_attributes(struct drm_i915_private *i915) *attr_iter++ = &i915_iter->attr.attr; i915_iter = add_i915_attr(i915_iter, str, - __I915_PMU_ENGINE(engine->class, + __I915_PMU_ENGINE(engine->uabi_class, engine->instance, engine_events[i].sample)); From 751d115302466113ab757db5771d1e9e74d1b0b7 Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Tue, 23 Jan 2018 16:43:48 -0800 Subject: [PATCH 086/158] drm/i915/lrc: Update reg_state macros to pass checkpatch The macros we use to init the reg_state had the following issues reported by checkpatch --strict. Macro argument reuse 'reg_state' - possible side-effects Macro argument reuse 'pos' - possible side-effects Macro argument reuse 'ppgtt' - possible side-effects spaces preferred around that '+' (ctx:VxV) So fix these issues before they are moved to a new header file. Suggested-by: Chris Wilson Signed-off-by: Michel Thierry Cc: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180124004349.22126-1-michel.thierry@intel.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lrc.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 22d471a4228d..cde99b87beb0 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -186,19 +186,24 @@ #define CTX_GPGPU_CSR_BASE_ADDRESS 0x44 #define CTX_REG(reg_state, pos, reg, val) do { \ - (reg_state)[(pos)+0] = i915_mmio_reg_offset(reg); \ - (reg_state)[(pos)+1] = (val); \ + u32 *reg_state__ = (reg_state); \ + const u32 pos__ = (pos); \ + (reg_state__)[(pos__) + 0] = i915_mmio_reg_offset(reg); \ + (reg_state__)[(pos__) + 1] = (val); \ } while (0) -#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) do { \ - const u64 _addr = i915_page_dir_dma_addr((ppgtt), (n)); \ - reg_state[CTX_PDP ## n ## _UDW+1] = upper_32_bits(_addr); \ - reg_state[CTX_PDP ## n ## _LDW+1] = lower_32_bits(_addr); \ +#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) do { \ + u32 *reg_state__ = (reg_state); \ + const u64 addr__ = i915_page_dir_dma_addr((ppgtt), (n)); \ + (reg_state__)[CTX_PDP ## n ## _UDW + 1] = upper_32_bits(addr__); \ + (reg_state__)[CTX_PDP ## n ## _LDW + 1] = lower_32_bits(addr__); \ } while (0) #define ASSIGN_CTX_PML4(ppgtt, reg_state) do { \ - reg_state[CTX_PDP0_UDW + 1] = upper_32_bits(px_dma(&ppgtt->pml4)); \ - reg_state[CTX_PDP0_LDW + 1] = lower_32_bits(px_dma(&ppgtt->pml4)); \ + u32 *reg_state__ = (reg_state); \ + const u64 addr__ = px_dma(&ppgtt->pml4); \ + (reg_state__)[CTX_PDP0_UDW + 1] = upper_32_bits(addr__); \ + (reg_state__)[CTX_PDP0_LDW + 1] = lower_32_bits(addr__); \ } while (0) #define GEN8_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x17 From 578f1ac689b185b602a0e02613714419a2a45e67 Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Tue, 23 Jan 2018 16:43:49 -0800 Subject: [PATCH 087/158] drm/i915: Move LRC register offsets to a header file Newer platforms may have subtle offset changes, which will increase the number of defines, so it is probably better to start moving them to its own header file. Also move the macros used while setting the reg state. v2: Rename to intel_lrc_reg.h, to be consistent with i915_reg.h and intel_guc_reg.h (Chris) v3: License notice shenanigans. v4: Documentation/process/coding-style.rst is always right (Chris) v5: Rebase. Signed-off-by: Michel Thierry Cc: Michal Wajdeczko Cc: Lucas De Marchi Cc: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180124004349.22126-2-michel.thierry@intel.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lrc.c | 55 +---------------------- drivers/gpu/drm/i915/intel_lrc_reg.h | 67 ++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 54 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_lrc_reg.h diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index cde99b87beb0..ec3012623697 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -137,6 +137,7 @@ #include #include "i915_drv.h" #include "i915_gem_render_state.h" +#include "intel_lrc_reg.h" #include "intel_mocs.h" #define RING_EXECLIST_QFULL (1 << 0x2) @@ -156,60 +157,6 @@ #define GEN8_CTX_STATUS_COMPLETED_MASK \ (GEN8_CTX_STATUS_COMPLETE | GEN8_CTX_STATUS_PREEMPTED) -#define CTX_LRI_HEADER_0 0x01 -#define CTX_CONTEXT_CONTROL 0x02 -#define CTX_RING_HEAD 0x04 -#define CTX_RING_TAIL 0x06 -#define CTX_RING_BUFFER_START 0x08 -#define CTX_RING_BUFFER_CONTROL 0x0a -#define CTX_BB_HEAD_U 0x0c -#define CTX_BB_HEAD_L 0x0e -#define CTX_BB_STATE 0x10 -#define CTX_SECOND_BB_HEAD_U 0x12 -#define CTX_SECOND_BB_HEAD_L 0x14 -#define CTX_SECOND_BB_STATE 0x16 -#define CTX_BB_PER_CTX_PTR 0x18 -#define CTX_RCS_INDIRECT_CTX 0x1a -#define CTX_RCS_INDIRECT_CTX_OFFSET 0x1c -#define CTX_LRI_HEADER_1 0x21 -#define CTX_CTX_TIMESTAMP 0x22 -#define CTX_PDP3_UDW 0x24 -#define CTX_PDP3_LDW 0x26 -#define CTX_PDP2_UDW 0x28 -#define CTX_PDP2_LDW 0x2a -#define CTX_PDP1_UDW 0x2c -#define CTX_PDP1_LDW 0x2e -#define CTX_PDP0_UDW 0x30 -#define CTX_PDP0_LDW 0x32 -#define CTX_LRI_HEADER_2 0x41 -#define CTX_R_PWR_CLK_STATE 0x42 -#define CTX_GPGPU_CSR_BASE_ADDRESS 0x44 - -#define CTX_REG(reg_state, pos, reg, val) do { \ - u32 *reg_state__ = (reg_state); \ - const u32 pos__ = (pos); \ - (reg_state__)[(pos__) + 0] = i915_mmio_reg_offset(reg); \ - (reg_state__)[(pos__) + 1] = (val); \ -} while (0) - -#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) do { \ - u32 *reg_state__ = (reg_state); \ - const u64 addr__ = i915_page_dir_dma_addr((ppgtt), (n)); \ - (reg_state__)[CTX_PDP ## n ## _UDW + 1] = upper_32_bits(addr__); \ - (reg_state__)[CTX_PDP ## n ## _LDW + 1] = lower_32_bits(addr__); \ -} while (0) - -#define ASSIGN_CTX_PML4(ppgtt, reg_state) do { \ - u32 *reg_state__ = (reg_state); \ - const u64 addr__ = px_dma(&ppgtt->pml4); \ - (reg_state__)[CTX_PDP0_UDW + 1] = upper_32_bits(addr__); \ - (reg_state__)[CTX_PDP0_LDW + 1] = lower_32_bits(addr__); \ -} while (0) - -#define GEN8_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x17 -#define GEN9_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x26 -#define GEN10_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x19 - /* Typical size of the average request (2 pipecontrols and a MI_BB) */ #define EXECLISTS_REQUEST_SIZE 64 /* bytes */ #define WA_TAIL_DWORDS 2 diff --git a/drivers/gpu/drm/i915/intel_lrc_reg.h b/drivers/gpu/drm/i915/intel_lrc_reg.h new file mode 100644 index 000000000000..a53336e2fc97 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_lrc_reg.h @@ -0,0 +1,67 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright © 2014-2018 Intel Corporation + */ + +#ifndef _INTEL_LRC_REG_H_ +#define _INTEL_LRC_REG_H_ + +#include + +/* GEN8+ Reg State Context */ +#define CTX_LRI_HEADER_0 0x01 +#define CTX_CONTEXT_CONTROL 0x02 +#define CTX_RING_HEAD 0x04 +#define CTX_RING_TAIL 0x06 +#define CTX_RING_BUFFER_START 0x08 +#define CTX_RING_BUFFER_CONTROL 0x0a +#define CTX_BB_HEAD_U 0x0c +#define CTX_BB_HEAD_L 0x0e +#define CTX_BB_STATE 0x10 +#define CTX_SECOND_BB_HEAD_U 0x12 +#define CTX_SECOND_BB_HEAD_L 0x14 +#define CTX_SECOND_BB_STATE 0x16 +#define CTX_BB_PER_CTX_PTR 0x18 +#define CTX_RCS_INDIRECT_CTX 0x1a +#define CTX_RCS_INDIRECT_CTX_OFFSET 0x1c +#define CTX_LRI_HEADER_1 0x21 +#define CTX_CTX_TIMESTAMP 0x22 +#define CTX_PDP3_UDW 0x24 +#define CTX_PDP3_LDW 0x26 +#define CTX_PDP2_UDW 0x28 +#define CTX_PDP2_LDW 0x2a +#define CTX_PDP1_UDW 0x2c +#define CTX_PDP1_LDW 0x2e +#define CTX_PDP0_UDW 0x30 +#define CTX_PDP0_LDW 0x32 +#define CTX_LRI_HEADER_2 0x41 +#define CTX_R_PWR_CLK_STATE 0x42 +#define CTX_GPGPU_CSR_BASE_ADDRESS 0x44 + +#define CTX_REG(reg_state, pos, reg, val) do { \ + u32 *reg_state__ = (reg_state); \ + const u32 pos__ = (pos); \ + (reg_state__)[(pos__) + 0] = i915_mmio_reg_offset(reg); \ + (reg_state__)[(pos__) + 1] = (val); \ +} while (0) + +#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) do { \ + u32 *reg_state__ = (reg_state); \ + const u64 addr__ = i915_page_dir_dma_addr((ppgtt), (n)); \ + (reg_state__)[CTX_PDP ## n ## _UDW + 1] = upper_32_bits(addr__); \ + (reg_state__)[CTX_PDP ## n ## _LDW + 1] = lower_32_bits(addr__); \ +} while (0) + +#define ASSIGN_CTX_PML4(ppgtt, reg_state) do { \ + u32 *reg_state__ = (reg_state); \ + const u64 addr__ = px_dma(&ppgtt->pml4); \ + (reg_state__)[CTX_PDP0_UDW + 1] = upper_32_bits(addr__); \ + (reg_state__)[CTX_PDP0_LDW + 1] = lower_32_bits(addr__); \ +} while (0) + +#define GEN8_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x17 +#define GEN9_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x26 +#define GEN10_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x19 + +#endif /* _INTEL_LRC_REG_H_ */ From 517aaffe0c1b54b4f732e872a89681c650d3527f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 23 Jan 2018 21:04:12 +0000 Subject: [PATCH 088/158] drm/i915/execlists: Inhibit context save/restore for the fake preempt context We only use the preempt context to inject an idle point into execlists. We never need to reference its logical state, so tell the GPU never to load it or save it. v2: BIT(2) for save-inhibit. N.B. Daniele mentioned this bit mbz for ICL, and has been moved into the submission process rather than the context image. Suggested-by: Daniele Ceraolo Spurio Signed-off-by: Chris Wilson Cc: Michal Winiarski Cc: Michel Thierry Cc: Michal Wajdeczko Cc: Tvrtko Ursulin Cc: Mika Kuoppala Cc: Daniele Ceraolo Spurio Reviewed-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180123210412.17653-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 4 ++++ drivers/gpu/drm/i915/intel_lrc.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index ec3012623697..89e92defbcfe 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -2237,6 +2237,10 @@ populate_lr_context(struct i915_gem_context *ctx, if (!engine->default_state) regs[CTX_CONTEXT_CONTROL + 1] |= _MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT); + if (ctx->hw_id == PREEMPT_ID) + regs[CTX_CONTEXT_CONTROL + 1] |= + _MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT | + CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT); i915_gem_object_unpin_map(ctx_obj); diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 6d4f9b995a11..636ced41225d 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -37,6 +37,7 @@ #define CTX_CTRL_INHIBIT_SYN_CTX_SWITCH (1 << 3) #define CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT (1 << 0) #define CTX_CTRL_RS_CTX_ENABLE (1 << 1) +#define CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT (1 << 2) #define RING_CONTEXT_STATUS_BUF_BASE(engine) _MMIO((engine)->mmio_base + 0x370) #define RING_CONTEXT_STATUS_BUF_LO(engine, i) _MMIO((engine)->mmio_base + 0x370 + (i) * 8) #define RING_CONTEXT_STATUS_BUF_HI(engine, i) _MMIO((engine)->mmio_base + 0x370 + (i) * 8 + 4) From 6f56103d7e95f96568a460493ff6c0ced45f538b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 24 Jan 2018 11:36:07 +0000 Subject: [PATCH 089/158] drm/i915: Track the number of times we have woken the GPU up By counting the number of times we have woken up, we have a very simple means of defining an epoch, which will come in handy if we want to perform deferred tasks at the end of an epoch (i.e. while we are going to sleep) without imposing on the next activity cycle. v2: No reason to specify precise number of bits here. v3: Take Tvrtko's advice and reserve 0 as an invalid epoch. Signed-off-by: Chris Wilson Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180124113608.14909-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_debugfs.c | 7 ++++--- drivers/gpu/drm/i915/i915_drv.h | 6 ++++++ drivers/gpu/drm/i915/i915_gem_request.c | 2 ++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 80dc679c0f01..338735252e23 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2717,7 +2717,8 @@ static int i915_runtime_pm_status(struct seq_file *m, void *unused) if (!HAS_RUNTIME_PM(dev_priv)) seq_puts(m, "Runtime power management not supported\n"); - seq_printf(m, "GPU idle: %s\n", yesno(!dev_priv->gt.awake)); + seq_printf(m, "GPU idle: %s (epoch %u)\n", + yesno(!dev_priv->gt.awake), dev_priv->gt.epoch); seq_printf(m, "IRQs disabled: %s\n", yesno(!intel_irqs_enabled(dev_priv))); #ifdef CONFIG_PM @@ -3150,8 +3151,8 @@ static int i915_engine_info(struct seq_file *m, void *unused) intel_runtime_pm_get(dev_priv); - seq_printf(m, "GT awake? %s\n", - yesno(dev_priv->gt.awake)); + seq_printf(m, "GT awake? %s (epoch %u)\n", + yesno(dev_priv->gt.awake), dev_priv->gt.epoch); seq_printf(m, "Global active requests: %d\n", dev_priv->gt.active_requests); seq_printf(m, "CS timestamp frequency: %u kHz\n", diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c707eee2102b..1f9df2861d54 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2312,6 +2312,12 @@ struct drm_i915_private { */ bool awake; + /** + * The number of times we have woken up. + */ + unsigned int epoch; +#define I915_EPOCH_INVALID 0 + /** * We leave the user IRQ off as much as possible, * but this means that requests will finish and never diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c index a0f451b4a4e8..06ec27a68f5c 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.c +++ b/drivers/gpu/drm/i915/i915_gem_request.c @@ -274,6 +274,8 @@ static void mark_busy(struct drm_i915_private *i915) intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ); i915->gt.awake = true; + if (unlikely(++i915->gt.epoch == 0)) /* keep 0 as invalid */ + i915->gt.epoch = 1; intel_enable_gt_powersave(i915); i915_update_gfx_val(i915); From 84a1074920523430f9dc30ff907f4801b4820072 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 24 Jan 2018 11:36:08 +0000 Subject: [PATCH 090/158] drm/i915: Shrink the GEM kmem_caches upon idling When we finally decide the gpu is idle, that is a good time to shrink our kmem_caches. v3: Defer until an rcu grace period after we idle. v4: Think about epoch wraparound and how likely that is. v5: Use I915_EPOCH_INVALID magic. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180124113608.14909-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 79 +++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7f0684ccc724..ba43482d0a0c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3334,6 +3334,65 @@ i915_gem_retire_work_handler(struct work_struct *work) } } +static void shrink_caches(struct drm_i915_private *i915) +{ + /* + * kmem_cache_shrink() discards empty slabs and reorders partially + * filled slabs to prioritise allocating from the mostly full slabs, + * with the aim of reducing fragmentation. + */ + kmem_cache_shrink(i915->priorities); + kmem_cache_shrink(i915->dependencies); + kmem_cache_shrink(i915->requests); + kmem_cache_shrink(i915->luts); + kmem_cache_shrink(i915->vmas); + kmem_cache_shrink(i915->objects); +} + +struct sleep_rcu_work { + union { + struct rcu_head rcu; + struct work_struct work; + }; + struct drm_i915_private *i915; + unsigned int epoch; +}; + +static inline bool +same_epoch(struct drm_i915_private *i915, unsigned int epoch) +{ + /* + * There is a small chance that the epoch wrapped since we started + * sleeping. If we assume that epoch is at least a u32, then it will + * take at least 2^32 * 100ms for it to wrap, or about 326 years. + */ + return epoch == READ_ONCE(i915->gt.epoch); +} + +static void __sleep_work(struct work_struct *work) +{ + struct sleep_rcu_work *s = container_of(work, typeof(*s), work); + struct drm_i915_private *i915 = s->i915; + unsigned int epoch = s->epoch; + + kfree(s); + if (same_epoch(i915, epoch)) + shrink_caches(i915); +} + +static void __sleep_rcu(struct rcu_head *rcu) +{ + struct sleep_rcu_work *s = container_of(rcu, typeof(*s), rcu); + struct drm_i915_private *i915 = s->i915; + + if (same_epoch(i915, s->epoch)) { + INIT_WORK(&s->work, __sleep_work); + queue_work(i915->wq, &s->work); + } else { + kfree(s); + } +} + static inline bool new_requests_since_last_retire(const struct drm_i915_private *i915) { @@ -3346,6 +3405,7 @@ i915_gem_idle_work_handler(struct work_struct *work) { struct drm_i915_private *dev_priv = container_of(work, typeof(*dev_priv), gt.idle_work.work); + unsigned int epoch = I915_EPOCH_INVALID; bool rearm_hangcheck; ktime_t end; @@ -3405,6 +3465,8 @@ i915_gem_idle_work_handler(struct work_struct *work) GEM_BUG_ON(!dev_priv->gt.awake); dev_priv->gt.awake = false; + epoch = dev_priv->gt.epoch; + GEM_BUG_ON(epoch == I915_EPOCH_INVALID); rearm_hangcheck = false; if (INTEL_GEN(dev_priv) >= 6) @@ -3421,6 +3483,23 @@ out_rearm: GEM_BUG_ON(!dev_priv->gt.awake); i915_queue_hangcheck(dev_priv); } + + /* + * When we are idle, it is an opportune time to reap our caches. + * However, we have many objects that utilise RCU and the ordered + * i915->wq that this work is executing on. To try and flush any + * pending frees now we are idle, we first wait for an RCU grace + * period, and then queue a task (that will run last on the wq) to + * shrink and re-optimize the caches. + */ + if (same_epoch(dev_priv, epoch)) { + struct sleep_rcu_work *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s) { + s->i915 = dev_priv; + s->epoch = epoch; + call_rcu(&s->rcu, __sleep_rcu); + } + } } void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file) From c19e1124e7e8cb1f8fbb685fd9b7d0a42087bd62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 23 Jan 2018 20:33:43 +0200 Subject: [PATCH 091/158] drm/i915: Use enum plane_id for frontbuffer tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the ad-hoc plane indexing scheme used by the frontbuffer tracking with enum plane_id. The old video overlay not being part of the plane_id namespace will just be given the high bit. v2: Drop the unintended whitespace change (Chris) Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180123183343.9181-1-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 11 +++-------- drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_fbc.c | 2 +- drivers/gpu/drm/i915/intel_sprite.c | 2 +- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1f9df2861d54..88255f9c3cc4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2410,16 +2410,11 @@ enum hdmi_force_audio { * * We have one bit per pipe and per scanout plane type. */ -#define INTEL_MAX_SPRITE_BITS_PER_PIPE 5 #define INTEL_FRONTBUFFER_BITS_PER_PIPE 8 -#define INTEL_FRONTBUFFER_PRIMARY(pipe) \ - (1 << (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe))) -#define INTEL_FRONTBUFFER_CURSOR(pipe) \ - (1 << (1 + (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe)))) -#define INTEL_FRONTBUFFER_SPRITE(pipe, plane) \ - (1 << (2 + plane + (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe)))) +#define INTEL_FRONTBUFFER(pipe, plane_id) \ + (1 << ((plane_id) + INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe))) #define INTEL_FRONTBUFFER_OVERLAY(pipe) \ - (1 << (2 + INTEL_MAX_SPRITE_BITS_PER_PIPE + (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe)))) + (1 << (INTEL_FRONTBUFFER_BITS_PER_PIPE - 1 + INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe))) #define INTEL_FRONTBUFFER_ALL_MASK(pipe) \ (0xff << (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe))) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a323234fa83b..03b817279a5b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13149,7 +13149,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) else primary->i9xx_plane = (enum i9xx_plane_id) pipe; primary->id = PLANE_PRIMARY; - primary->frontbuffer_bit = INTEL_FRONTBUFFER_PRIMARY(pipe); + primary->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, primary->id); primary->check_plane = intel_check_primary_plane; if (INTEL_GEN(dev_priv) >= 9) { @@ -13270,7 +13270,7 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv, cursor->pipe = pipe; cursor->i9xx_plane = (enum i9xx_plane_id) pipe; cursor->id = PLANE_CURSOR; - cursor->frontbuffer_bit = INTEL_FRONTBUFFER_CURSOR(pipe); + cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id); if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) { cursor->update_plane = i845_update_cursor; diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 9dc2b8b5f2db..a8a8a80497a8 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -1373,7 +1373,7 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) for_each_pipe(dev_priv, pipe) { fbc->possible_framebuffer_bits |= - INTEL_FRONTBUFFER_PRIMARY(pipe); + INTEL_FRONTBUFFER(pipe, PLANE_PRIMARY); if (fbc_on_pipe_a_only(dev_priv)) break; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 94188488db05..e4e4a1cbdd47 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1423,7 +1423,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, intel_plane->pipe = pipe; intel_plane->i9xx_plane = plane; intel_plane->id = PLANE_SPRITE0 + plane; - intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe, plane); + intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, intel_plane->id); intel_plane->check_plane = intel_check_sprite_plane; possible_crtcs = (1 << pipe); From 0519c102f5285476d7868a387bdb6c58385e4074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 22 Jan 2018 19:41:31 +0200 Subject: [PATCH 092/158] drm/i915: Implement display w/a #1143 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently SKL/KBL/CFL need some manual help to get the programmed HDMI vswing to stick. Implement the relevant workaround (display w/a #1143). Note that the relevant chicken bits live in a transcoder register even though the bits affect a specific DDI port rather than a specific transcoder. Hence we must pick the correct transcoder register instance based on the port rather than based on the cpu_transcoder. Also note that for completeness I included support for DDI A/E in the code even though we never have HDMI on those ports. v2: CFL needs the w/a as well (Rodrigo and Art) Cc: Rodrigo Vivi Cc: Art Runyan Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180122174131.28046-1-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_reg.h | 8 ++++-- drivers/gpu/drm/i915/intel_ddi.c | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9c56e2165b2a..b06db954c79f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7079,8 +7079,12 @@ enum { #define CHICKEN_TRANS_A 0x420c0 #define CHICKEN_TRANS_B 0x420c4 #define CHICKEN_TRANS(trans) _MMIO_TRANS(trans, CHICKEN_TRANS_A, CHICKEN_TRANS_B) -#define PSR2_VSC_ENABLE_PROG_HEADER (1<<12) -#define PSR2_ADD_VERTICAL_LINE_COUNT (1<<15) +#define DDI_TRAINING_OVERRIDE_ENABLE (1<<19) +#define DDI_TRAINING_OVERRIDE_VALUE (1<<18) +#define DDIE_TRAINING_OVERRIDE_ENABLE (1<<17) /* CHICKEN_TRANS_A only */ +#define DDIE_TRAINING_OVERRIDE_VALUE (1<<16) /* CHICKEN_TRANS_A only */ +#define PSR2_ADD_VERTICAL_LINE_COUNT (1<<15) +#define PSR2_VSC_ENABLE_PROG_HEADER (1<<12) #define DISP_ARB_CTL _MMIO(0x45000) #define DISP_FBC_MEMORY_WAKE (1<<31) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index f51645a08dca..2756a69b6207 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2404,6 +2404,48 @@ static void intel_enable_ddi_hdmi(struct intel_encoder *encoder, crtc_state->hdmi_high_tmds_clock_ratio, crtc_state->hdmi_scrambling); + /* Display WA #1143: skl,kbl,cfl */ + if (IS_GEN9_BC(dev_priv)) { + /* + * For some reason these chicken bits have been + * stuffed into a transcoder register, event though + * the bits affect a specific DDI port rather than + * a specific transcoder. + */ + static const enum transcoder port_to_transcoder[] = { + [PORT_A] = TRANSCODER_EDP, + [PORT_B] = TRANSCODER_A, + [PORT_C] = TRANSCODER_B, + [PORT_D] = TRANSCODER_C, + [PORT_E] = TRANSCODER_A, + }; + enum transcoder transcoder = port_to_transcoder[port]; + u32 val; + + val = I915_READ(CHICKEN_TRANS(transcoder)); + + if (port == PORT_E) + val |= DDIE_TRAINING_OVERRIDE_ENABLE | + DDIE_TRAINING_OVERRIDE_VALUE; + else + val |= DDI_TRAINING_OVERRIDE_ENABLE | + DDI_TRAINING_OVERRIDE_VALUE; + + I915_WRITE(CHICKEN_TRANS(transcoder), val); + POSTING_READ(CHICKEN_TRANS(transcoder)); + + udelay(1); + + if (port == PORT_E) + val &= ~(DDIE_TRAINING_OVERRIDE_ENABLE | + DDIE_TRAINING_OVERRIDE_VALUE); + else + val &= ~(DDI_TRAINING_OVERRIDE_ENABLE | + DDI_TRAINING_OVERRIDE_VALUE); + + I915_WRITE(CHICKEN_TRANS(transcoder), val); + } + /* In HDMI/DVI mode, the port width, and swing/emphasis values * are ignored so nothing special needs to be done besides * enabling the port. From 16af25faae8ef72b4ff2feeca65f6e864c3ef929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 19 Jan 2018 16:41:52 +0200 Subject: [PATCH 093/158] drm/i915: Add a comment exlaining CCS hsub/vsub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's document why we claim hsub==8,vsub==16 for CCS. v2: Replace my explanation with Jason's Cc: Daniel Vetter Cc: Ben Widawsky Cc: Jason Ekstrand Cc: Daniel Stone Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180119144152.17224-1-ville.syrjala@linux.intel.com Reviewed-by: Jason Ekstrand --- drivers/gpu/drm/i915/intel_display.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 03b817279a5b..f9372a21e326 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2387,6 +2387,20 @@ static unsigned int intel_fb_modifier_to_tiling(uint64_t fb_modifier) } } +/* + * From the Sky Lake PRM: + * "The Color Control Surface (CCS) contains the compression status of + * the cache-line pairs. The compression state of the cache-line pair + * is specified by 2 bits in the CCS. Each CCS cache-line represents + * an area on the main surface of 16 x16 sets of 128 byte Y-tiled + * cache-line-pairs. CCS is always Y tiled." + * + * Since cache line pairs refers to horizontally adjacent cache lines, + * each cache line in the CCS corresponds to an area of 32x16 cache + * lines on the main surface. Since each pixel is 4 bytes, this gives + * us a ratio of one byte in the CCS for each 8x16 pixels in the + * main surface. + */ static const struct drm_format_info ccs_formats[] = { { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, }, { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, }, From 1be333d34e22db8fd07dca7efa78b93189eddf6b Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Wed, 24 Jan 2018 21:16:56 +0530 Subject: [PATCH 094/158] drm/i915/guc: Grab RPM wakelock while disabling GuC interrupts Disabling GuC interrupts involves access to GuC IRQ control registers hence ensure device is RPM awake. v1-v2: old changelog 1: Add comment about need to synchronize flush work and log runtime destroy 2: Moved patch earlier in the series and removed comment about future work. (Tvrtko) v3: Added assert_rpm_wakelock_held() to gen9_*_guc_interrupts. (Chris) Signed-off-by: Sagar Arun Kamble Cc: Michal Wajdeczko Cc: Daniele Ceraolo Spurio Cc: Tvrtko Ursulin Cc: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/1516808821-3638-1-git-send-email-sagar.a.kamble@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 6 ++++++ drivers/gpu/drm/i915/intel_guc_log.c | 3 +++ 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 3517c6548e2c..85c46a25265d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -452,6 +452,8 @@ void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv) void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv) { + assert_rpm_wakelock_held(dev_priv); + spin_lock_irq(&dev_priv->irq_lock); gen6_reset_pm_iir(dev_priv, dev_priv->pm_guc_events); spin_unlock_irq(&dev_priv->irq_lock); @@ -459,6 +461,8 @@ void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv) void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv) { + assert_rpm_wakelock_held(dev_priv); + spin_lock_irq(&dev_priv->irq_lock); if (!dev_priv->guc.interrupts_enabled) { WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & @@ -471,6 +475,8 @@ void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv) void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv) { + assert_rpm_wakelock_held(dev_priv); + spin_lock_irq(&dev_priv->irq_lock); dev_priv->guc.interrupts_enabled = false; diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 2ffc966aa196..8f2da309508a 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -639,7 +639,10 @@ void i915_guc_log_unregister(struct drm_i915_private *dev_priv) mutex_lock(&dev_priv->drm.struct_mutex); /* GuC logging is currently the only user of Guc2Host interrupts */ + intel_runtime_pm_get(dev_priv); gen9_disable_guc_interrupts(dev_priv); + intel_runtime_pm_put(dev_priv); + guc_log_runtime_destroy(&dev_priv->guc); mutex_unlock(&dev_priv->drm.struct_mutex); } From 1ed21cb4142bccd23d988e2b47541c302f4d09fb Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Wed, 24 Jan 2018 21:16:57 +0530 Subject: [PATCH 095/158] drm/i915/guc: Enable interrupts before resuming GuC during runtime resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GuC log streaming needs interrupts enabled prior to GuC resume but runtime pm interrupt setup was happening post GuC resume. Fix it. While at it, fix the unwinding of steps in the runtime suspend path. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104695 Signed-off-by: Sagar Arun Kamble Cc: Chris Wilson Cc: Michal Wajdeczko Cc: Michał Winiarski Cc: Joonas Lahtinen Cc: Marta Lofstedt Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/1516808821-3638-2-git-send-email-sagar.a.kamble@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 1fbe37889d92..95e1c161a887 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -2600,6 +2600,11 @@ static int intel_runtime_suspend(struct device *kdev) intel_runtime_pm_enable_interrupts(dev_priv); + intel_guc_resume(dev_priv); + + i915_gem_init_swizzling(dev_priv); + i915_gem_restore_fences(dev_priv); + enable_rpm_wakeref_asserts(dev_priv); return ret; @@ -2665,8 +2670,6 @@ static int intel_runtime_resume(struct device *kdev) if (intel_uncore_unclaimed_mmio(dev_priv)) DRM_DEBUG_DRIVER("Unclaimed access during suspend, bios?\n"); - intel_guc_resume(dev_priv); - if (IS_GEN9_LP(dev_priv)) { bxt_disable_dc9(dev_priv); bxt_display_core_init(dev_priv, true); @@ -2681,6 +2684,10 @@ static int intel_runtime_resume(struct device *kdev) intel_uncore_runtime_resume(dev_priv); + intel_runtime_pm_enable_interrupts(dev_priv); + + intel_guc_resume(dev_priv); + /* * No point of rolling back things in case of an error, as the best * we can do is to hope that things will still work (and disable RPM). @@ -2688,8 +2695,6 @@ static int intel_runtime_resume(struct device *kdev) i915_gem_init_swizzling(dev_priv); i915_gem_restore_fences(dev_priv); - intel_runtime_pm_enable_interrupts(dev_priv); - /* * On VLV/CHV display interrupts are part of the display * power well, so hpd is reinitialized from there. For From 70deeaddc6e6c51bb5e2b088dd92bb5a0e5b8d8a Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Wed, 24 Jan 2018 21:16:58 +0530 Subject: [PATCH 096/158] drm/i915/guc: Fix lockdep due to log relay channel handling under struct_mutex This patch fixes lockdep issue due to circular locking dependency of struct_mutex, i_mutex_key, mmap_sem, relay_channels_mutex. For GuC log relay channel we create debugfs file that requires i_mutex_key lock and we are doing that under struct_mutex. So we introduced newer dependency as: &dev->struct_mutex --> &sb->s_type->i_mutex_key#3 --> &mm->mmap_sem However, there is dependency from mmap_sem to struct_mutex. Hence we separate the relay create/destroy operation from under struct_mutex. Also added runtime check of relay buffer status. Reviewed-by: Chris Wilson ====================================================== WARNING: possible circular locking dependency detected 4.15.0-rc6-CI-Patchwork_7614+ #1 Not tainted ------------------------------------------------------ debugfs_test/1388 is trying to acquire lock: (&dev->struct_mutex){+.+.}, at: [<00000000d5e1d915>] i915_mutex_lock_interruptible+0x47/0x130 [i915] but task is already holding lock: (&mm->mmap_sem){++++}, at: [<0000000029a9c131>] __do_page_fault+0x106/0x560 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #3 (&mm->mmap_sem){++++}: _copy_to_user+0x1e/0x70 filldir+0x8c/0xf0 dcache_readdir+0xeb/0x160 iterate_dir+0xdc/0x140 SyS_getdents+0xa0/0x130 entry_SYSCALL_64_fastpath+0x1c/0x89 -> #2 (&sb->s_type->i_mutex_key#3){++++}: start_creating+0x59/0x110 __debugfs_create_file+0x2e/0xe0 relay_create_buf_file+0x62/0x80 relay_late_setup_files+0x84/0x250 guc_log_late_setup+0x4f/0x110 [i915] i915_guc_log_register+0x32/0x40 [i915] i915_driver_load+0x7b6/0x1720 [i915] i915_pci_probe+0x2e/0x90 [i915] pci_device_probe+0x9c/0x120 driver_probe_device+0x2a3/0x480 __driver_attach+0xd9/0xe0 bus_for_each_dev+0x57/0x90 bus_add_driver+0x168/0x260 driver_register+0x52/0xc0 do_one_initcall+0x39/0x150 do_init_module+0x56/0x1ef load_module+0x231c/0x2d70 SyS_finit_module+0xa5/0xe0 entry_SYSCALL_64_fastpath+0x1c/0x89 -> #1 (relay_channels_mutex){+.+.}: relay_open+0x12c/0x2b0 intel_guc_log_runtime_create+0xab/0x230 [i915] intel_guc_init+0x81/0x120 [i915] intel_uc_init+0x29/0xa0 [i915] i915_gem_init+0x182/0x530 [i915] i915_driver_load+0xaa9/0x1720 [i915] i915_pci_probe+0x2e/0x90 [i915] pci_device_probe+0x9c/0x120 driver_probe_device+0x2a3/0x480 __driver_attach+0xd9/0xe0 bus_for_each_dev+0x57/0x90 bus_add_driver+0x168/0x260 driver_register+0x52/0xc0 do_one_initcall+0x39/0x150 do_init_module+0x56/0x1ef load_module+0x231c/0x2d70 SyS_finit_module+0xa5/0xe0 entry_SYSCALL_64_fastpath+0x1c/0x89 -> #0 (&dev->struct_mutex){+.+.}: __mutex_lock+0x81/0x9b0 i915_mutex_lock_interruptible+0x47/0x130 [i915] i915_gem_fault+0x201/0x790 [i915] __do_fault+0x15/0x70 __handle_mm_fault+0x677/0xdc0 handle_mm_fault+0x14f/0x2f0 __do_page_fault+0x2d1/0x560 page_fault+0x4c/0x60 other info that might help us debug this: Chain exists of: &dev->struct_mutex --> &sb->s_type->i_mutex_key#3 --> &mm->mmap_sem Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&mm->mmap_sem); lock(&sb->s_type->i_mutex_key#3); lock(&mm->mmap_sem); lock(&dev->struct_mutex); *** DEADLOCK *** 1 lock held by debugfs_test/1388: #0: (&mm->mmap_sem){++++}, at: [<0000000029a9c131>] __do_page_fault+0x106/0x560 stack backtrace: CPU: 2 PID: 1388 Comm: debugfs_test Not tainted 4.15.0-rc6-CI-Patchwork_7614+ #1 Hardware name: To Be Filled By O.E.M. To Be Filled By O.E.M./J4205-ITX, BIOS P1.10 09/29/2016 Call Trace: dump_stack+0x5f/0x86 print_circular_bug.isra.18+0x1d0/0x2c0 __lock_acquire+0x14ae/0x1b60 ? lock_acquire+0xaf/0x200 lock_acquire+0xaf/0x200 ? i915_mutex_lock_interruptible+0x47/0x130 [i915] __mutex_lock+0x81/0x9b0 ? i915_mutex_lock_interruptible+0x47/0x130 [i915] ? i915_mutex_lock_interruptible+0x47/0x130 [i915] ? i915_mutex_lock_interruptible+0x47/0x130 [i915] i915_mutex_lock_interruptible+0x47/0x130 [i915] ? __pm_runtime_resume+0x4f/0x80 i915_gem_fault+0x201/0x790 [i915] __do_fault+0x15/0x70 ? _raw_spin_unlock+0x29/0x40 __handle_mm_fault+0x677/0xdc0 handle_mm_fault+0x14f/0x2f0 __do_page_fault+0x2d1/0x560 ? page_fault+0x36/0x60 page_fault+0x4c/0x60 v2: Added lock protection to guc->log.runtime.relay_chan (Chris) Fixed locking inside guc_flush_logs uncovered by new lockdep. v3: Locking guc_read_update_log_buffer entirely with relay_lock. (Chris) Prepared intel_guc_init_early. Moved relay_lock inside relay_create relay_destroy, relay_file_create, guc_read_update_log_buffer. (Michal) Removed struct_mutex lock around guc_log_flush and removed usage of guc_log_has_relay() from runtime_create path as it needs struct_mutex lock. v4: Handle NULL relay sub buffer pointer earlier in read_update_log_buffer (Chris). Fixed comment suffix **/. (Michal) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104693 Testcase: igt/debugfs_test/read_all_entries # with enable_guc=1 and guc_log_level=1 Signed-off-by: Sagar Arun Kamble Cc: Michal Wajdeczko Cc: Daniele Ceraolo Spurio Cc: Tvrtko Ursulin Cc: Chris Wilson Cc: Joonas Lahtinen Cc: Marta Lofstedt Cc: Michal Winiarski Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/1516808821-3638-3-git-send-email-sagar.a.kamble@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 12 +- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_gem.c | 4 +- drivers/gpu/drm/i915/intel_guc.c | 7 +- drivers/gpu/drm/i915/intel_guc_log.c | 171 ++++++++++++++++++++------- drivers/gpu/drm/i915/intel_guc_log.h | 12 ++ drivers/gpu/drm/i915/intel_uc.c | 26 +++- drivers/gpu/drm/i915/intel_uc.h | 4 +- 8 files changed, 172 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 338735252e23..d3def0ef63bd 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2467,7 +2467,6 @@ static int i915_guc_log_control_get(void *data, u64 *val) static int i915_guc_log_control_set(void *data, u64 val) { struct drm_i915_private *dev_priv = data; - int ret; if (!HAS_GUC(dev_priv)) return -ENODEV; @@ -2475,16 +2474,7 @@ static int i915_guc_log_control_set(void *data, u64 val) if (!dev_priv->guc.log.vma) return -EINVAL; - ret = mutex_lock_interruptible(&dev_priv->drm.struct_mutex); - if (ret) - return ret; - - intel_runtime_pm_get(dev_priv); - ret = i915_guc_log_control(dev_priv, val); - intel_runtime_pm_put(dev_priv); - - mutex_unlock(&dev_priv->drm.struct_mutex); - return ret; + return i915_guc_log_control(dev_priv, val); } DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops, diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 95e1c161a887..1ec12add34b2 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -626,7 +626,7 @@ static void i915_gem_fini(struct drm_i915_private *dev_priv) i915_gem_contexts_fini(dev_priv); mutex_unlock(&dev_priv->drm.struct_mutex); - intel_uc_fini_wq(dev_priv); + intel_uc_fini_misc(dev_priv); i915_gem_cleanup_userptr(dev_priv); i915_gem_drain_freed_objects(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ba43482d0a0c..062b21408698 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5272,7 +5272,7 @@ int i915_gem_init(struct drm_i915_private *dev_priv) if (ret) return ret; - ret = intel_uc_init_wq(dev_priv); + ret = intel_uc_init_misc(dev_priv); if (ret) return ret; @@ -5368,7 +5368,7 @@ err_unlock: intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); mutex_unlock(&dev_priv->drm.struct_mutex); - intel_uc_fini_wq(dev_priv); + intel_uc_fini_misc(dev_priv); if (ret != -EIO) i915_gem_cleanup_userptr(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index ea30e7c34a04..21140ccd7a97 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -64,6 +64,7 @@ void intel_guc_init_early(struct intel_guc *guc) { intel_guc_fw_init_early(guc); intel_guc_ct_init_early(&guc->ct); + intel_guc_log_init_early(guc); mutex_init(&guc->send_mutex); guc->send = intel_guc_send_nop; @@ -87,8 +88,10 @@ int intel_guc_init_wq(struct intel_guc *guc) */ guc->log.runtime.flush_wq = alloc_ordered_workqueue("i915-guc_log", WQ_HIGHPRI | WQ_FREEZABLE); - if (!guc->log.runtime.flush_wq) + if (!guc->log.runtime.flush_wq) { + DRM_ERROR("Couldn't allocate workqueue for GuC log\n"); return -ENOMEM; + } /* * Even though both sending GuC action, and adding a new workitem to @@ -109,6 +112,8 @@ int intel_guc_init_wq(struct intel_guc *guc) WQ_HIGHPRI); if (!guc->preempt_wq) { destroy_workqueue(guc->log.runtime.flush_wq); + DRM_ERROR("Couldn't allocate workqueue for GuC " + "preemption\n"); return -ENOMEM; } } diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 8f2da309508a..d10ec53f9290 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -153,6 +153,8 @@ static int guc_log_relay_file_create(struct intel_guc *guc) if (!i915_modparams.guc_log_level) return 0; + mutex_lock(&guc->log.runtime.relay_lock); + /* For now create the log file in /sys/kernel/debug/dri/0 dir */ log_dir = dev_priv->drm.primary->debugfs_root; @@ -169,16 +171,26 @@ static int guc_log_relay_file_create(struct intel_guc *guc) */ if (!log_dir) { DRM_ERROR("Debugfs dir not available yet for GuC log file\n"); - return -ENODEV; + ret = -ENODEV; + goto out_unlock; } ret = relay_late_setup_files(guc->log.runtime.relay_chan, "guc_log", log_dir); if (ret < 0 && ret != -EEXIST) { DRM_ERROR("Couldn't associate relay chan with file %d\n", ret); - return ret; + goto out_unlock; } - return 0; +out_unlock: + mutex_unlock(&guc->log.runtime.relay_lock); + return ret; +} + +static bool guc_log_has_relay(struct intel_guc *guc) +{ + lockdep_assert_held(&guc->log.runtime.relay_lock); + + return guc->log.runtime.relay_chan != NULL; } static void guc_move_to_next_buf(struct intel_guc *guc) @@ -188,6 +200,9 @@ static void guc_move_to_next_buf(struct intel_guc *guc) */ smp_wmb(); + if (!guc_log_has_relay(guc)) + return; + /* All data has been written, so now move the offset of sub buffer. */ relay_reserve(guc->log.runtime.relay_chan, guc->log.vma->obj->base.size); @@ -197,7 +212,7 @@ static void guc_move_to_next_buf(struct intel_guc *guc) static void *guc_get_write_buffer(struct intel_guc *guc) { - if (!guc->log.runtime.relay_chan) + if (!guc_log_has_relay(guc)) return NULL; /* Just get the base address of a new sub buffer and copy data into it @@ -265,9 +280,22 @@ static void guc_read_update_log_buffer(struct intel_guc *guc) /* Get the pointer to shared GuC log buffer */ log_buf_state = src_data = guc->log.runtime.buf_addr; + mutex_lock(&guc->log.runtime.relay_lock); + /* Get the pointer to local buffer to store the logs */ log_buf_snapshot_state = dst_data = guc_get_write_buffer(guc); + if (unlikely(!log_buf_snapshot_state)) { + /* Used rate limited to avoid deluge of messages, logs might be + * getting consumed by User at a slow rate. + */ + DRM_ERROR_RATELIMITED("no sub-buffer to capture logs\n"); + guc->log.capture_miss_count++; + mutex_unlock(&guc->log.runtime.relay_lock); + + return; + } + /* Actual logs are present from the 2nd page */ src_data += PAGE_SIZE; dst_data += PAGE_SIZE; @@ -293,9 +321,6 @@ static void guc_read_update_log_buffer(struct intel_guc *guc) log_buf_state->flush_to_file = 0; log_buf_state++; - if (unlikely(!log_buf_snapshot_state)) - continue; - /* First copy the state structure in snapshot buffer */ memcpy(log_buf_snapshot_state, &log_buf_state_local, sizeof(struct guc_log_buffer_state)); @@ -335,15 +360,9 @@ static void guc_read_update_log_buffer(struct intel_guc *guc) dst_data += buffer_size; } - if (log_buf_snapshot_state) - guc_move_to_next_buf(guc); - else { - /* Used rate limited to avoid deluge of messages, logs might be - * getting consumed by User at a slow rate. - */ - DRM_ERROR_RATELIMITED("no sub-buffer to capture logs\n"); - guc->log.capture_miss_count++; - } + guc_move_to_next_buf(guc); + + mutex_unlock(&guc->log.runtime.relay_lock); } static void capture_logs_work(struct work_struct *work) @@ -363,8 +382,6 @@ static int guc_log_runtime_create(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); void *vaddr; - struct rchan *guc_log_relay_chan; - size_t n_subbufs, subbuf_size; int ret; lockdep_assert_held(&dev_priv->drm.struct_mutex); @@ -387,8 +404,44 @@ static int guc_log_runtime_create(struct intel_guc *guc) guc->log.runtime.buf_addr = vaddr; + return 0; +} + +static void guc_log_runtime_destroy(struct intel_guc *guc) +{ + /* + * It's possible that the runtime stuff was never allocated because + * GuC log was disabled at the boot time. + */ + if (!guc_log_has_runtime(guc)) + return; + + i915_gem_object_unpin_map(guc->log.vma->obj); + guc->log.runtime.buf_addr = NULL; +} + +void intel_guc_log_init_early(struct intel_guc *guc) +{ + mutex_init(&guc->log.runtime.relay_lock); + INIT_WORK(&guc->log.runtime.flush_work, capture_logs_work); +} + +int intel_guc_log_relay_create(struct intel_guc *guc) +{ + struct drm_i915_private *dev_priv = guc_to_i915(guc); + struct rchan *guc_log_relay_chan; + size_t n_subbufs, subbuf_size; + int ret; + + if (!i915_modparams.guc_log_level) + return 0; + + mutex_lock(&guc->log.runtime.relay_lock); + + GEM_BUG_ON(guc_log_has_relay(guc)); + /* Keep the size of sub buffers same as shared log buffer */ - subbuf_size = guc->log.vma->obj->base.size; + subbuf_size = GUC_LOG_SIZE; /* Store up to 8 snapshots, which is large enough to buffer sufficient * boot time logs and provides enough leeway to User, in terms of @@ -407,33 +460,39 @@ static int guc_log_runtime_create(struct intel_guc *guc) DRM_ERROR("Couldn't create relay chan for GuC logging\n"); ret = -ENOMEM; - goto err_vaddr; + goto err; } GEM_BUG_ON(guc_log_relay_chan->subbuf_size < subbuf_size); guc->log.runtime.relay_chan = guc_log_relay_chan; - INIT_WORK(&guc->log.runtime.flush_work, capture_logs_work); + mutex_unlock(&guc->log.runtime.relay_lock); + return 0; -err_vaddr: - i915_gem_object_unpin_map(guc->log.vma->obj); - guc->log.runtime.buf_addr = NULL; +err: + mutex_unlock(&guc->log.runtime.relay_lock); + /* logging will be off */ + i915_modparams.guc_log_level = 0; return ret; } -static void guc_log_runtime_destroy(struct intel_guc *guc) +void intel_guc_log_relay_destroy(struct intel_guc *guc) { + mutex_lock(&guc->log.runtime.relay_lock); + /* - * It's possible that the runtime stuff was never allocated because + * It's possible that the relay was never allocated because * GuC log was disabled at the boot time. */ - if (!guc_log_has_runtime(guc)) - return; + if (!guc_log_has_relay(guc)) + goto out_unlock; relay_close(guc->log.runtime.relay_chan); - i915_gem_object_unpin_map(guc->log.vma->obj); - guc->log.runtime.buf_addr = NULL; + guc->log.runtime.relay_chan = NULL; + +out_unlock: + mutex_unlock(&guc->log.runtime.relay_lock); } static int guc_log_late_setup(struct intel_guc *guc) @@ -441,17 +500,24 @@ static int guc_log_late_setup(struct intel_guc *guc) struct drm_i915_private *dev_priv = guc_to_i915(guc); int ret; - lockdep_assert_held(&dev_priv->drm.struct_mutex); - if (!guc_log_has_runtime(guc)) { /* * If log was disabled at boot time, then setup needed to handle * log buffer flush interrupts would not have been done yet, so * do that now. */ - ret = guc_log_runtime_create(guc); + ret = intel_guc_log_relay_create(guc); if (ret) goto err; + + mutex_lock(&dev_priv->drm.struct_mutex); + intel_runtime_pm_get(dev_priv); + ret = guc_log_runtime_create(guc); + intel_runtime_pm_put(dev_priv); + mutex_unlock(&dev_priv->drm.struct_mutex); + + if (ret) + goto err_relay; } ret = guc_log_relay_file_create(guc); @@ -461,7 +527,11 @@ static int guc_log_late_setup(struct intel_guc *guc) return 0; err_runtime: + mutex_lock(&dev_priv->drm.struct_mutex); guc_log_runtime_destroy(guc); + mutex_unlock(&dev_priv->drm.struct_mutex); +err_relay: + intel_guc_log_relay_destroy(guc); err: /* logging will remain off */ i915_modparams.guc_log_level = 0; @@ -490,7 +560,11 @@ static void guc_flush_logs(struct intel_guc *guc) return; /* First disable the interrupts, will be renabled afterwards */ + mutex_lock(&dev_priv->drm.struct_mutex); + intel_runtime_pm_get(dev_priv); gen9_disable_guc_interrupts(dev_priv); + intel_runtime_pm_put(dev_priv); + mutex_unlock(&dev_priv->drm.struct_mutex); /* Before initiating the forceful flush, wait for any pending/ongoing * flush to complete otherwise forceful flush may not actually happen. @@ -498,7 +572,9 @@ static void guc_flush_logs(struct intel_guc *guc) flush_work(&guc->log.runtime.flush_work); /* Ask GuC to update the log buffer state */ + intel_runtime_pm_get(dev_priv); guc_log_flush(guc); + intel_runtime_pm_put(dev_priv); /* GuC would have updated log buffer by now, so capture it */ guc_log_capture_logs(guc); @@ -509,17 +585,10 @@ int intel_guc_log_create(struct intel_guc *guc) struct i915_vma *vma; unsigned long offset; u32 flags; - u32 size; int ret; GEM_BUG_ON(guc->log.vma); - /* The first page is to save log buffer state. Allocate one - * extra page for others in case for overlap */ - size = (1 + GUC_LOG_DPC_PAGES + 1 + - GUC_LOG_ISR_PAGES + 1 + - GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT; - /* We require SSE 4.1 for fast reads from the GuC log buffer and * it should be present on the chipsets supporting GuC based * submisssions. @@ -529,7 +598,7 @@ int intel_guc_log_create(struct intel_guc *guc) goto err; } - vma = intel_guc_allocate_vma(guc, size); + vma = intel_guc_allocate_vma(guc, GUC_LOG_SIZE); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto err; @@ -584,7 +653,15 @@ int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val) return 0; verbosity = enable_logging ? control_val - 1 : 0; + + ret = mutex_lock_interruptible(&dev_priv->drm.struct_mutex); + if (ret) + return ret; + intel_runtime_pm_get(dev_priv); ret = guc_log_control(guc, enable_logging, verbosity); + intel_runtime_pm_put(dev_priv); + mutex_unlock(&dev_priv->drm.struct_mutex); + if (ret < 0) { DRM_DEBUG_DRIVER("guc_logging_control action failed %d\n", ret); return ret; @@ -605,7 +682,11 @@ int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val) } /* GuC logging is currently the only user of Guc2Host interrupts */ + mutex_lock(&dev_priv->drm.struct_mutex); + intel_runtime_pm_get(dev_priv); gen9_enable_guc_interrupts(dev_priv); + intel_runtime_pm_put(dev_priv); + mutex_unlock(&dev_priv->drm.struct_mutex); } else { /* * Once logging is disabled, GuC won't generate logs & send an @@ -627,13 +708,13 @@ void i915_guc_log_register(struct drm_i915_private *dev_priv) if (!USES_GUC_SUBMISSION(dev_priv) || !i915_modparams.guc_log_level) return; - mutex_lock(&dev_priv->drm.struct_mutex); guc_log_late_setup(&dev_priv->guc); - mutex_unlock(&dev_priv->drm.struct_mutex); } void i915_guc_log_unregister(struct drm_i915_private *dev_priv) { + struct intel_guc *guc = &dev_priv->guc; + if (!USES_GUC_SUBMISSION(dev_priv)) return; @@ -643,6 +724,8 @@ void i915_guc_log_unregister(struct drm_i915_private *dev_priv) gen9_disable_guc_interrupts(dev_priv); intel_runtime_pm_put(dev_priv); - guc_log_runtime_destroy(&dev_priv->guc); + guc_log_runtime_destroy(guc); mutex_unlock(&dev_priv->drm.struct_mutex); + + intel_guc_log_relay_destroy(guc); } diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index f512cf79339b..c638b9d76d04 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -32,6 +32,13 @@ struct drm_i915_private; struct intel_guc; +/* + * The first page is to save log buffer state. Allocate one + * extra page for others in case for overlap + */ +#define GUC_LOG_SIZE ((1 + GUC_LOG_DPC_PAGES + 1 + GUC_LOG_ISR_PAGES + \ + 1 + GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT) + struct intel_guc_log { u32 flags; struct i915_vma *vma; @@ -41,6 +48,8 @@ struct intel_guc_log { struct workqueue_struct *flush_wq; struct work_struct flush_work; struct rchan *relay_chan; + /* To serialize the access to relay_chan */ + struct mutex relay_lock; } runtime; /* logging related stats */ u32 capture_miss_count; @@ -52,6 +61,9 @@ struct intel_guc_log { int intel_guc_log_create(struct intel_guc *guc); void intel_guc_log_destroy(struct intel_guc *guc); +void intel_guc_log_init_early(struct intel_guc *guc); +int intel_guc_log_relay_create(struct intel_guc *guc); +void intel_guc_log_relay_destroy(struct intel_guc *guc); int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val); void i915_guc_log_register(struct drm_i915_private *dev_priv); void i915_guc_log_unregister(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index f78a17b24798..e3f3509d6692 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -236,28 +236,44 @@ static void guc_disable_communication(struct intel_guc *guc) guc->send = intel_guc_send_nop; } -int intel_uc_init_wq(struct drm_i915_private *dev_priv) +int intel_uc_init_misc(struct drm_i915_private *dev_priv) { + struct intel_guc *guc = &dev_priv->guc; int ret; if (!USES_GUC(dev_priv)) return 0; - ret = intel_guc_init_wq(&dev_priv->guc); + ret = intel_guc_init_wq(guc); if (ret) { DRM_ERROR("Couldn't allocate workqueues for GuC\n"); - return ret; + goto err; + } + + ret = intel_guc_log_relay_create(guc); + if (ret) { + DRM_ERROR("Couldn't allocate relay for GuC log\n"); + goto err_relay; } return 0; + +err_relay: + intel_guc_fini_wq(guc); +err: + return ret; } -void intel_uc_fini_wq(struct drm_i915_private *dev_priv) +void intel_uc_fini_misc(struct drm_i915_private *dev_priv) { + struct intel_guc *guc = &dev_priv->guc; + if (!USES_GUC(dev_priv)) return; - intel_guc_fini_wq(&dev_priv->guc); + intel_guc_fini_wq(guc); + + intel_guc_log_relay_destroy(guc); } int intel_uc_init(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/intel_uc.h b/drivers/gpu/drm/i915/intel_uc.h index 8a7249722ef1..f2984e01e257 100644 --- a/drivers/gpu/drm/i915/intel_uc.h +++ b/drivers/gpu/drm/i915/intel_uc.h @@ -33,8 +33,8 @@ void intel_uc_init_early(struct drm_i915_private *dev_priv); void intel_uc_init_mmio(struct drm_i915_private *dev_priv); void intel_uc_init_fw(struct drm_i915_private *dev_priv); void intel_uc_fini_fw(struct drm_i915_private *dev_priv); -int intel_uc_init_wq(struct drm_i915_private *dev_priv); -void intel_uc_fini_wq(struct drm_i915_private *dev_priv); +int intel_uc_init_misc(struct drm_i915_private *dev_priv); +void intel_uc_fini_misc(struct drm_i915_private *dev_priv); int intel_uc_init_hw(struct drm_i915_private *dev_priv); void intel_uc_fini_hw(struct drm_i915_private *dev_priv); int intel_uc_init(struct drm_i915_private *dev_priv); From 065dd5ad6c94fde283477016ecb9525e30622431 Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Wed, 24 Jan 2018 21:16:59 +0530 Subject: [PATCH 097/158] drm/i915/guc: Update name and prototype of i915_guc_log_control i915_guc_log_control is GuC interface and GuC APIs that are not user facing should be named with "intel_guc" prefix hence we change name to intel_guc_log_control. Also changed the parameter to intel_guc struct. v2: Move log vma check to intel_guc_log_control (Michal) Return -ENODEV when log isn't initialized. (Chris) Suggested-by: Michal Wajdeczko Signed-off-by: Sagar Arun Kamble Cc: Michal Wajdeczko Cc: Chris Wilson Reviewed-by: Michal Wajdeczko Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/1516808821-3638-4-git-send-email-sagar.a.kamble@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 5 +---- drivers/gpu/drm/i915/intel_guc_log.c | 7 +++++-- drivers/gpu/drm/i915/intel_guc_log.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d3def0ef63bd..3849ded354e3 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2471,10 +2471,7 @@ static int i915_guc_log_control_set(void *data, u64 val) if (!HAS_GUC(dev_priv)) return -ENODEV; - if (!dev_priv->guc.log.vma) - return -EINVAL; - - return i915_guc_log_control(dev_priv, val); + return intel_guc_log_control(&dev_priv->guc, val); } DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops, diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index d10ec53f9290..cb10f7aeb042 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -637,13 +637,16 @@ void intel_guc_log_destroy(struct intel_guc *guc) i915_vma_unpin_and_release(&guc->log.vma); } -int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val) +int intel_guc_log_control(struct intel_guc *guc, u64 control_val) { - struct intel_guc *guc = &dev_priv->guc; + struct drm_i915_private *dev_priv = guc_to_i915(guc); bool enable_logging = control_val > 0; u32 verbosity; int ret; + if (!guc->log.vma) + return -ENODEV; + BUILD_BUG_ON(GUC_LOG_VERBOSITY_MIN); if (control_val > 1 + GUC_LOG_VERBOSITY_MAX) return -EINVAL; diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index c638b9d76d04..dab0e949567a 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -64,7 +64,7 @@ void intel_guc_log_destroy(struct intel_guc *guc); void intel_guc_log_init_early(struct intel_guc *guc); int intel_guc_log_relay_create(struct intel_guc *guc); void intel_guc_log_relay_destroy(struct intel_guc *guc); -int i915_guc_log_control(struct drm_i915_private *dev_priv, u64 control_val); +int intel_guc_log_control(struct intel_guc *guc, u64 control_val); void i915_guc_log_register(struct drm_i915_private *dev_priv); void i915_guc_log_unregister(struct drm_i915_private *dev_priv); From 2fcf06805cb063085127d7e3f4ed7842682b3fff Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Wed, 24 Jan 2018 21:17:00 +0530 Subject: [PATCH 098/158] drm/i915/guc: Fix comments style in intel_guc_log.c Use consistent multi-line comment style as per guideline. v2: Reverted comments prefix update to kernel-doc comment. (Chris) Suggested-by: Michal Wajdeczko Signed-off-by: Sagar Arun Kamble Cc: Michal Wajdeczko Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/1516808821-3638-5-git-send-email-sagar.a.kamble@intel.com --- drivers/gpu/drm/i915/intel_guc_log.c | 45 ++++++++++++++++++---------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index cb10f7aeb042..86a33214cbfc 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -81,7 +81,8 @@ static int subbuf_start_callback(struct rchan_buf *buf, void *prev_subbuf, size_t prev_padding) { - /* Use no-overwrite mode by default, where relay will stop accepting + /* + * Use no-overwrite mode by default, where relay will stop accepting * new data if there are no empty sub buffers left. * There is no strict synchronization enforced by relay between Consumer * and Producer. In overwrite mode, there is a possibility of getting @@ -107,7 +108,8 @@ static struct dentry *create_buf_file_callback(const char *filename, { struct dentry *buf_file; - /* This to enable the use of a single buffer for the relay channel and + /* + * This to enable the use of a single buffer for the relay channel and * correspondingly have a single file exposed to User, through which * it can collect the logs in order without any post-processing. * Need to set 'is_global' even if parent is NULL for early logging. @@ -117,7 +119,8 @@ static struct dentry *create_buf_file_callback(const char *filename, if (!parent) return NULL; - /* Not using the channel filename passed as an argument, since for each + /* + * Not using the channel filename passed as an argument, since for each * channel relay appends the corresponding CPU number to the filename * passed in relay_open(). This should be fine as relay just needs a * dentry of the file associated with the channel buffer and that file's @@ -158,7 +161,8 @@ static int guc_log_relay_file_create(struct intel_guc *guc) /* For now create the log file in /sys/kernel/debug/dri/0 dir */ log_dir = dev_priv->drm.primary->debugfs_root; - /* If /sys/kernel/debug/dri/0 location do not exist, then debugfs is + /* + * If /sys/kernel/debug/dri/0 location do not exist, then debugfs is * not mounted and so can't create the relay file. * The relay API seems to fit well with debugfs only, for availing relay * there are 3 requirements which can be met for debugfs file only in a @@ -195,7 +199,8 @@ static bool guc_log_has_relay(struct intel_guc *guc) static void guc_move_to_next_buf(struct intel_guc *guc) { - /* Make sure the updates made in the sub buffer are visible when + /* + * Make sure the updates made in the sub buffer are visible when * Consumer sees the following update to offset inside the sub buffer. */ smp_wmb(); @@ -215,7 +220,8 @@ static void *guc_get_write_buffer(struct intel_guc *guc) if (!guc_log_has_relay(guc)) return NULL; - /* Just get the base address of a new sub buffer and copy data into it + /* + * Just get the base address of a new sub buffer and copy data into it * ourselves. NULL will be returned in no-overwrite mode, if all sub * buffers are full. Could have used the relay_write() to indirectly * copy the data, but that would have been bit convoluted, as we need to @@ -286,7 +292,8 @@ static void guc_read_update_log_buffer(struct intel_guc *guc) log_buf_snapshot_state = dst_data = guc_get_write_buffer(guc); if (unlikely(!log_buf_snapshot_state)) { - /* Used rate limited to avoid deluge of messages, logs might be + /* + * Used rate limited to avoid deluge of messages, logs might be * getting consumed by User at a slow rate. */ DRM_ERROR_RATELIMITED("no sub-buffer to capture logs\n"); @@ -301,7 +308,8 @@ static void guc_read_update_log_buffer(struct intel_guc *guc) dst_data += PAGE_SIZE; for (type = GUC_ISR_LOG_BUFFER; type < GUC_MAX_LOG_BUFFER; type++) { - /* Make a copy of the state structure, inside GuC log buffer + /* + * Make a copy of the state structure, inside GuC log buffer * (which is uncached mapped), on the stack to avoid reading * from it multiple times. */ @@ -325,7 +333,8 @@ static void guc_read_update_log_buffer(struct intel_guc *guc) memcpy(log_buf_snapshot_state, &log_buf_state_local, sizeof(struct guc_log_buffer_state)); - /* The write pointer could have been updated by GuC firmware, + /* + * The write pointer could have been updated by GuC firmware, * after sending the flush interrupt to Host, for consistency * set write pointer value to same value of sampled_write_ptr * in the snapshot buffer. @@ -392,7 +401,8 @@ static int guc_log_runtime_create(struct intel_guc *guc) if (ret) return ret; - /* Create a WC (Uncached for read) vmalloc mapping of log + /* + * Create a WC (Uncached for read) vmalloc mapping of log * buffer pages, so that we can directly get the data * (up-to-date) from memory. */ @@ -443,14 +453,16 @@ int intel_guc_log_relay_create(struct intel_guc *guc) /* Keep the size of sub buffers same as shared log buffer */ subbuf_size = GUC_LOG_SIZE; - /* Store up to 8 snapshots, which is large enough to buffer sufficient + /* + * Store up to 8 snapshots, which is large enough to buffer sufficient * boot time logs and provides enough leeway to User, in terms of * latency, for consuming the logs from relay. Also doesn't take * up too much memory. */ n_subbufs = 8; - /* Create a relay channel, so that we have buffers for storing + /* + * Create a relay channel, so that we have buffers for storing * the GuC firmware logs, the channel will be linked with a file * later on when debugfs is registered. */ @@ -544,7 +556,8 @@ static void guc_log_capture_logs(struct intel_guc *guc) guc_read_update_log_buffer(guc); - /* Generally device is expected to be active only at this + /* + * Generally device is expected to be active only at this * time, so get/put should be really quick. */ intel_runtime_pm_get(dev_priv); @@ -566,7 +579,8 @@ static void guc_flush_logs(struct intel_guc *guc) intel_runtime_pm_put(dev_priv); mutex_unlock(&dev_priv->drm.struct_mutex); - /* Before initiating the forceful flush, wait for any pending/ongoing + /* + * Before initiating the forceful flush, wait for any pending/ongoing * flush to complete otherwise forceful flush may not actually happen. */ flush_work(&guc->log.runtime.flush_work); @@ -589,7 +603,8 @@ int intel_guc_log_create(struct intel_guc *guc) GEM_BUG_ON(guc->log.vma); - /* We require SSE 4.1 for fast reads from the GuC log buffer and + /* + * We require SSE 4.1 for fast reads from the GuC log buffer and * it should be present on the chipsets supporting GuC based * submisssions. */ From 09b1a4e4b583b4c54c819563717949807fdbb640 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 25 Jan 2018 11:24:42 +0000 Subject: [PATCH 099/158] drm/i915/lrc: Clear context restore/save inhibit flags for new contexts CTX_CONTEXT_CONTROL (CTX_SR_CTL) operates as a masked register and so will only apply the bits that are selected by the upper half. In the case of selectively enabling sr inhibit, this may mean the context keeps the current setting (so forgetting to save the context later, eventually leading to a very upset GPU!). Fixes: 517aaffe0c1b ("drm/i915/execlists: Inhibit context save/restore for the fake preempt context") Signed-off-by: Chris Wilson Cc: Michal Winiarski Cc: Michel Thierry Cc: Michal Wajdeczko Cc: Tvrtko Ursulin Cc: Mika Kuoppala Cc: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20180125112443.12745-1-chris@chris-wilson.co.uk Reviewed-by: Michel Thierry --- drivers/gpu/drm/i915/intel_lrc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 89e92defbcfe..29b14d7d4b07 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -456,6 +456,12 @@ static void inject_preempt_context(struct intel_engine_cs *engine) ce->ring->tail &= (ce->ring->size - 1); ce->lrc_reg_state[CTX_RING_TAIL+1] = ce->ring->tail; + GEM_BUG_ON((ce->lrc_reg_state[CTX_CONTEXT_CONTROL + 1] & + _MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT | + CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT)) != + _MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT | + CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT)); + GEM_TRACE("%s\n", engine->name); for (n = execlists_num_ports(&engine->execlists); --n; ) elsp_write(0, engine->execlists.elsp); @@ -2118,6 +2124,8 @@ static void execlists_init_reg_state(u32 *regs, MI_LRI_FORCE_POSTED; CTX_REG(regs, CTX_CONTEXT_CONTROL, RING_CONTEXT_CONTROL(engine), + _MASKED_BIT_DISABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT | + CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT) | _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH | (HAS_RESOURCE_STREAMER(dev_priv) ? CTX_CTRL_RS_CTX_ENABLE : 0))); From 1d2a19c2567c74ff3c50fa1a0823052adee9c49f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 26 Jan 2018 12:18:46 +0000 Subject: [PATCH 100/158] drm/i915/lrc: Remove superfluous WARN_ON Remove the WARN_ON(ce->state) inside the static function only called when ce->state == NULL and downgrade the w/a batch setup warning into a developer only mode (GEM_WARN_ON). v2: Move the deferred alloc guard into the callee, eliminating the need for the WARN_ON: add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-1 (-1) Function old new delta execlists_context_pin 1819 1818 -1 Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180126121846.12007-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 29b14d7d4b07..2fa328d512fc 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1092,11 +1092,9 @@ execlists_context_pin(struct intel_engine_cs *engine, goto out; GEM_BUG_ON(!ce->pin_count); /* no overflow please! */ - if (!ce->state) { - ret = execlists_context_deferred_alloc(ctx, engine); - if (ret) - goto err; - } + ret = execlists_context_deferred_alloc(ctx, engine); + if (ret) + goto err; GEM_BUG_ON(!ce->state); ret = __context_pin(ctx, ce->state); @@ -1413,7 +1411,8 @@ static int intel_init_workaround_bb(struct intel_engine_cs *engine) */ for (i = 0; i < ARRAY_SIZE(wa_bb_fn); i++) { wa_bb[i]->offset = batch_ptr - batch; - if (WARN_ON(!IS_ALIGNED(wa_bb[i]->offset, CACHELINE_BYTES))) { + if (GEM_WARN_ON(!IS_ALIGNED(wa_bb[i]->offset, + CACHELINE_BYTES))) { ret = -EINVAL; break; } @@ -2265,7 +2264,8 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, struct intel_ring *ring; int ret; - WARN_ON(ce->state); + if (ce->state) + return 0; context_size = round_up(engine->context_size, I915_GTT_PAGE_SIZE); From 5db47e37b38755c5e26e6b8fbc1a32ce73495940 Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Mon, 29 Jan 2018 08:33:46 +0000 Subject: [PATCH 101/158] Revert "drm/i915: mark all device info struct with __initconst" This reverts commit 5b54eddd3920e9f6f1a6d972454baf350cbae77e. Conflicts: drivers/gpu/drm/i915/i915_pci.c Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104805 Signed-off-by: Lionel Landwerlin Reviewed-by: Chris Wilson Fixes: 5b54eddd3920 ("drm/i915: mark all device info struct with __initconst") Link: https://patchwork.freedesktop.org/patch/msgid/20180129083346.29173-1-lionel.g.landwerlin@intel.com --- drivers/gpu/drm/i915/i915_pci.c | 96 ++++++++++++++++----------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index f28c165fc49d..138228dd7782 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -74,19 +74,19 @@ GEN_DEFAULT_PAGE_SIZES, \ CURSOR_OFFSETS -static const struct intel_device_info intel_i830_info __initconst = { +static const struct intel_device_info intel_i830_info = { GEN2_FEATURES, .platform = INTEL_I830, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2, /* legal, last one wins */ }; -static const struct intel_device_info intel_i845g_info __initconst = { +static const struct intel_device_info intel_i845g_info = { GEN2_FEATURES, .platform = INTEL_I845G, }; -static const struct intel_device_info intel_i85x_info __initconst = { +static const struct intel_device_info intel_i85x_info = { GEN2_FEATURES, .platform = INTEL_I85X, .is_mobile = 1, .num_pipes = 2, /* legal, last one wins */ @@ -94,7 +94,7 @@ static const struct intel_device_info intel_i85x_info __initconst = { .has_fbc = 1, }; -static const struct intel_device_info intel_i865g_info __initconst = { +static const struct intel_device_info intel_i865g_info = { GEN2_FEATURES, .platform = INTEL_I865G, }; @@ -108,7 +108,7 @@ static const struct intel_device_info intel_i865g_info __initconst = { GEN_DEFAULT_PAGE_SIZES, \ CURSOR_OFFSETS -static const struct intel_device_info intel_i915g_info __initconst = { +static const struct intel_device_info intel_i915g_info = { GEN3_FEATURES, .platform = INTEL_I915G, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, @@ -116,7 +116,7 @@ static const struct intel_device_info intel_i915g_info __initconst = { .unfenced_needs_alignment = 1, }; -static const struct intel_device_info intel_i915gm_info __initconst = { +static const struct intel_device_info intel_i915gm_info = { GEN3_FEATURES, .platform = INTEL_I915GM, .is_mobile = 1, @@ -128,7 +128,7 @@ static const struct intel_device_info intel_i915gm_info __initconst = { .unfenced_needs_alignment = 1, }; -static const struct intel_device_info intel_i945g_info __initconst = { +static const struct intel_device_info intel_i945g_info = { GEN3_FEATURES, .platform = INTEL_I945G, .has_hotplug = 1, .cursor_needs_physical = 1, @@ -137,7 +137,7 @@ static const struct intel_device_info intel_i945g_info __initconst = { .unfenced_needs_alignment = 1, }; -static const struct intel_device_info intel_i945gm_info __initconst = { +static const struct intel_device_info intel_i945gm_info = { GEN3_FEATURES, .platform = INTEL_I945GM, .is_mobile = 1, .has_hotplug = 1, .cursor_needs_physical = 1, @@ -148,14 +148,14 @@ static const struct intel_device_info intel_i945gm_info __initconst = { .unfenced_needs_alignment = 1, }; -static const struct intel_device_info intel_g33_info __initconst = { +static const struct intel_device_info intel_g33_info = { GEN3_FEATURES, .platform = INTEL_G33, .has_hotplug = 1, .has_overlay = 1, }; -static const struct intel_device_info intel_pineview_info __initconst = { +static const struct intel_device_info intel_pineview_info = { GEN3_FEATURES, .platform = INTEL_PINEVIEW, .is_mobile = 1, .has_hotplug = 1, @@ -172,7 +172,7 @@ static const struct intel_device_info intel_pineview_info __initconst = { GEN_DEFAULT_PAGE_SIZES, \ CURSOR_OFFSETS -static const struct intel_device_info intel_i965g_info __initconst = { +static const struct intel_device_info intel_i965g_info = { GEN4_FEATURES, .platform = INTEL_I965G, .has_overlay = 1, @@ -180,7 +180,7 @@ static const struct intel_device_info intel_i965g_info __initconst = { .has_snoop = false, }; -static const struct intel_device_info intel_i965gm_info __initconst = { +static const struct intel_device_info intel_i965gm_info = { GEN4_FEATURES, .platform = INTEL_I965GM, .is_mobile = 1, .has_fbc = 1, @@ -190,13 +190,13 @@ static const struct intel_device_info intel_i965gm_info __initconst = { .has_snoop = false, }; -static const struct intel_device_info intel_g45_info __initconst = { +static const struct intel_device_info intel_g45_info = { GEN4_FEATURES, .platform = INTEL_G45, .ring_mask = RENDER_RING | BSD_RING, }; -static const struct intel_device_info intel_gm45_info __initconst = { +static const struct intel_device_info intel_gm45_info = { GEN4_FEATURES, .platform = INTEL_GM45, .is_mobile = 1, .has_fbc = 1, @@ -215,12 +215,12 @@ static const struct intel_device_info intel_gm45_info __initconst = { GEN_DEFAULT_PAGE_SIZES, \ CURSOR_OFFSETS -static const struct intel_device_info intel_ironlake_d_info __initconst = { +static const struct intel_device_info intel_ironlake_d_info = { GEN5_FEATURES, .platform = INTEL_IRONLAKE, }; -static const struct intel_device_info intel_ironlake_m_info __initconst = { +static const struct intel_device_info intel_ironlake_m_info = { GEN5_FEATURES, .platform = INTEL_IRONLAKE, .is_mobile = 1, .has_fbc = 1, @@ -243,12 +243,12 @@ static const struct intel_device_info intel_ironlake_m_info __initconst = { GEN6_FEATURES, \ .platform = INTEL_SANDYBRIDGE -static const struct intel_device_info intel_sandybridge_d_gt1_info __initconst = { +static const struct intel_device_info intel_sandybridge_d_gt1_info = { SNB_D_PLATFORM, .gt = 1, }; -static const struct intel_device_info intel_sandybridge_d_gt2_info __initconst = { +static const struct intel_device_info intel_sandybridge_d_gt2_info = { SNB_D_PLATFORM, .gt = 2, }; @@ -259,12 +259,12 @@ static const struct intel_device_info intel_sandybridge_d_gt2_info __initconst = .is_mobile = 1 -static const struct intel_device_info intel_sandybridge_m_gt1_info __initconst = { +static const struct intel_device_info intel_sandybridge_m_gt1_info = { SNB_M_PLATFORM, .gt = 1, }; -static const struct intel_device_info intel_sandybridge_m_gt2_info __initconst = { +static const struct intel_device_info intel_sandybridge_m_gt2_info = { SNB_M_PLATFORM, .gt = 2, }; @@ -288,12 +288,12 @@ static const struct intel_device_info intel_sandybridge_m_gt2_info __initconst = .platform = INTEL_IVYBRIDGE, \ .has_l3_dpf = 1 -static const struct intel_device_info intel_ivybridge_d_gt1_info __initconst = { +static const struct intel_device_info intel_ivybridge_d_gt1_info = { IVB_D_PLATFORM, .gt = 1, }; -static const struct intel_device_info intel_ivybridge_d_gt2_info __initconst = { +static const struct intel_device_info intel_ivybridge_d_gt2_info = { IVB_D_PLATFORM, .gt = 2, }; @@ -304,17 +304,17 @@ static const struct intel_device_info intel_ivybridge_d_gt2_info __initconst = { .is_mobile = 1, \ .has_l3_dpf = 1 -static const struct intel_device_info intel_ivybridge_m_gt1_info __initconst = { +static const struct intel_device_info intel_ivybridge_m_gt1_info = { IVB_M_PLATFORM, .gt = 1, }; -static const struct intel_device_info intel_ivybridge_m_gt2_info __initconst = { +static const struct intel_device_info intel_ivybridge_m_gt2_info = { IVB_M_PLATFORM, .gt = 2, }; -static const struct intel_device_info intel_ivybridge_q_info __initconst = { +static const struct intel_device_info intel_ivybridge_q_info = { GEN7_FEATURES, .platform = INTEL_IVYBRIDGE, .gt = 2, @@ -322,7 +322,7 @@ static const struct intel_device_info intel_ivybridge_q_info __initconst = { .has_l3_dpf = 1, }; -static const struct intel_device_info intel_valleyview_info __initconst = { +static const struct intel_device_info intel_valleyview_info = { .platform = INTEL_VALLEYVIEW, .gen = 7, .is_lp = 1, @@ -358,17 +358,17 @@ static const struct intel_device_info intel_valleyview_info __initconst = { .platform = INTEL_HASWELL, \ .has_l3_dpf = 1 -static const struct intel_device_info intel_haswell_gt1_info __initconst = { +static const struct intel_device_info intel_haswell_gt1_info = { HSW_PLATFORM, .gt = 1, }; -static const struct intel_device_info intel_haswell_gt2_info __initconst = { +static const struct intel_device_info intel_haswell_gt2_info = { HSW_PLATFORM, .gt = 2, }; -static const struct intel_device_info intel_haswell_gt3_info __initconst = { +static const struct intel_device_info intel_haswell_gt3_info = { HSW_PLATFORM, .gt = 3, }; @@ -388,17 +388,17 @@ static const struct intel_device_info intel_haswell_gt3_info __initconst = { .gen = 8, \ .platform = INTEL_BROADWELL -static const struct intel_device_info intel_broadwell_gt1_info __initconst = { +static const struct intel_device_info intel_broadwell_gt1_info = { BDW_PLATFORM, .gt = 1, }; -static const struct intel_device_info intel_broadwell_gt2_info __initconst = { +static const struct intel_device_info intel_broadwell_gt2_info = { BDW_PLATFORM, .gt = 2, }; -static const struct intel_device_info intel_broadwell_rsvd_info __initconst = { +static const struct intel_device_info intel_broadwell_rsvd_info = { BDW_PLATFORM, .gt = 3, /* According to the device ID those devices are GT3, they were @@ -406,13 +406,13 @@ static const struct intel_device_info intel_broadwell_rsvd_info __initconst = { */ }; -static const struct intel_device_info intel_broadwell_gt3_info __initconst = { +static const struct intel_device_info intel_broadwell_gt3_info = { BDW_PLATFORM, .gt = 3, .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING, }; -static const struct intel_device_info intel_cherryview_info __initconst = { +static const struct intel_device_info intel_cherryview_info = { .gen = 8, .num_pipes = 3, .has_hotplug = 1, .is_lp = 1, @@ -455,12 +455,12 @@ static const struct intel_device_info intel_cherryview_info __initconst = { .gen = 9, \ .platform = INTEL_SKYLAKE -static const struct intel_device_info intel_skylake_gt1_info __initconst = { +static const struct intel_device_info intel_skylake_gt1_info = { SKL_PLATFORM, .gt = 1, }; -static const struct intel_device_info intel_skylake_gt2_info __initconst = { +static const struct intel_device_info intel_skylake_gt2_info = { SKL_PLATFORM, .gt = 2, }; @@ -470,12 +470,12 @@ static const struct intel_device_info intel_skylake_gt2_info __initconst = { .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING -static const struct intel_device_info intel_skylake_gt3_info __initconst = { +static const struct intel_device_info intel_skylake_gt3_info = { SKL_GT3_PLUS_PLATFORM, .gt = 3, }; -static const struct intel_device_info intel_skylake_gt4_info __initconst = { +static const struct intel_device_info intel_skylake_gt4_info = { SKL_GT3_PLUS_PLATFORM, .gt = 4, }; @@ -511,13 +511,13 @@ static const struct intel_device_info intel_skylake_gt4_info __initconst = { IVB_CURSOR_OFFSETS, \ BDW_COLORS -static const struct intel_device_info intel_broxton_info __initconst = { +static const struct intel_device_info intel_broxton_info = { GEN9_LP_FEATURES, .platform = INTEL_BROXTON, .ddb_size = 512, }; -static const struct intel_device_info intel_geminilake_info __initconst = { +static const struct intel_device_info intel_geminilake_info = { GEN9_LP_FEATURES, .platform = INTEL_GEMINILAKE, .ddb_size = 1024, @@ -529,17 +529,17 @@ static const struct intel_device_info intel_geminilake_info __initconst = { .gen = 9, \ .platform = INTEL_KABYLAKE -static const struct intel_device_info intel_kabylake_gt1_info __initconst = { +static const struct intel_device_info intel_kabylake_gt1_info = { KBL_PLATFORM, .gt = 1, }; -static const struct intel_device_info intel_kabylake_gt2_info __initconst = { +static const struct intel_device_info intel_kabylake_gt2_info = { KBL_PLATFORM, .gt = 2, }; -static const struct intel_device_info intel_kabylake_gt3_info __initconst = { +static const struct intel_device_info intel_kabylake_gt3_info = { KBL_PLATFORM, .gt = 3, .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING, @@ -550,17 +550,17 @@ static const struct intel_device_info intel_kabylake_gt3_info __initconst = { .gen = 9, \ .platform = INTEL_COFFEELAKE -static const struct intel_device_info intel_coffeelake_gt1_info __initconst = { +static const struct intel_device_info intel_coffeelake_gt1_info = { CFL_PLATFORM, .gt = 1, }; -static const struct intel_device_info intel_coffeelake_gt2_info __initconst = { +static const struct intel_device_info intel_coffeelake_gt2_info = { CFL_PLATFORM, .gt = 2, }; -static const struct intel_device_info intel_coffeelake_gt3_info __initconst = { +static const struct intel_device_info intel_coffeelake_gt3_info = { CFL_PLATFORM, .gt = 3, .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING, @@ -571,7 +571,7 @@ static const struct intel_device_info intel_coffeelake_gt3_info __initconst = { .ddb_size = 1024, \ GLK_COLORS -static const struct intel_device_info intel_cannonlake_gt2_info __initconst = { +static const struct intel_device_info intel_cannonlake_gt2_info = { GEN10_FEATURES, .is_alpha_support = 1, .platform = INTEL_CANNONLAKE, @@ -585,7 +585,7 @@ static const struct intel_device_info intel_cannonlake_gt2_info __initconst = { .ddb_size = 2048, \ .has_csr = 0 -static const struct intel_device_info intel_icelake_11_info __initconst = { +static const struct intel_device_info intel_icelake_11_info = { GEN11_FEATURES, .platform = INTEL_ICELAKE, .is_alpha_support = 1, From 7fb9ee5db24a5892d3af8487de39d7b4a7fc2ea8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Jan 2018 10:28:40 +0000 Subject: [PATCH 102/158] drm/i915: Simplify guard logic for setup_scratch_page() Older gcc is complaining it can't follow the guards and thinks that addr may be used uninitialised In the process, we can simplify down to one loop, add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-131 (-131) Function old new delta setup_scratch_page 545 414 -131 Reported-by: Geert Uytterhoeven Signed-off-by: Chris Wilson Cc: Matthew Auld Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20180129102840.19901-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 69 ++++++++++++++--------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index be227512430a..b65426c0457d 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -543,9 +543,7 @@ static void fill_page_dma_32(struct i915_address_space *vm, static int setup_scratch_page(struct i915_address_space *vm, gfp_t gfp) { - struct page *page = NULL; - dma_addr_t addr; - int order; + unsigned long size; /* * In order to utilize 64K pages for an object with a size < 2M, we will @@ -559,48 +557,47 @@ setup_scratch_page(struct i915_address_space *vm, gfp_t gfp) * TODO: we should really consider write-protecting the scratch-page and * sharing between ppgtt */ + size = I915_GTT_PAGE_SIZE_4K; if (i915_vm_is_48bit(vm) && HAS_PAGE_SIZES(vm->i915, I915_GTT_PAGE_SIZE_64K)) { - order = get_order(I915_GTT_PAGE_SIZE_64K); - page = alloc_pages(gfp | __GFP_ZERO | __GFP_NOWARN, order); - if (page) { - addr = dma_map_page(vm->dma, page, 0, - I915_GTT_PAGE_SIZE_64K, - PCI_DMA_BIDIRECTIONAL); - if (unlikely(dma_mapping_error(vm->dma, addr))) { - __free_pages(page, order); - page = NULL; - } - - if (!IS_ALIGNED(addr, I915_GTT_PAGE_SIZE_64K)) { - dma_unmap_page(vm->dma, addr, - I915_GTT_PAGE_SIZE_64K, - PCI_DMA_BIDIRECTIONAL); - __free_pages(page, order); - page = NULL; - } - } + size = I915_GTT_PAGE_SIZE_64K; + gfp |= __GFP_NOWARN; } + gfp |= __GFP_ZERO | __GFP_RETRY_MAYFAIL; - if (!page) { - order = 0; - page = alloc_page(gfp | __GFP_ZERO); + do { + int order = get_order(size); + struct page *page; + dma_addr_t addr; + + page = alloc_pages(gfp, order); if (unlikely(!page)) - return -ENOMEM; + goto skip; - addr = dma_map_page(vm->dma, page, 0, PAGE_SIZE, + addr = dma_map_page(vm->dma, page, 0, size, PCI_DMA_BIDIRECTIONAL); - if (unlikely(dma_mapping_error(vm->dma, addr))) { - __free_page(page); + if (unlikely(dma_mapping_error(vm->dma, addr))) + goto free_page; + + if (unlikely(!IS_ALIGNED(addr, size))) + goto unmap_page; + + vm->scratch_page.page = page; + vm->scratch_page.daddr = addr; + vm->scratch_page.order = order; + return 0; + +unmap_page: + dma_unmap_page(vm->dma, addr, size, PCI_DMA_BIDIRECTIONAL); +free_page: + __free_pages(page, order); +skip: + if (size == I915_GTT_PAGE_SIZE_4K) return -ENOMEM; - } - } - vm->scratch_page.page = page; - vm->scratch_page.daddr = addr; - vm->scratch_page.order = order; - - return 0; + size = I915_GTT_PAGE_SIZE_4K; + gfp &= ~__GFP_NOWARN; + } while (1); } static void cleanup_scratch_page(struct i915_address_space *vm) From c7cc144d8f625cfb8f338e66d875d0ec42fc399a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Jan 2018 09:49:12 +0000 Subject: [PATCH 103/158] drm/i915: Assert that we do not try to unsubmit a completed request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assert that we do not try to unsubmit a completed request, as should we try to resubmit it later, the ring is already past the request's breadcrumb and the breadcrumb will not be updated. Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180129094912.14428-1-chris@chris-wilson.co.uk Reviewed-by: Michał Winiarski --- drivers/gpu/drm/i915/i915_gem_request.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c index 06ec27a68f5c..0a890ef4c420 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.c +++ b/drivers/gpu/drm/i915/i915_gem_request.c @@ -537,6 +537,8 @@ void __i915_gem_request_unsubmit(struct drm_i915_gem_request *request) */ GEM_BUG_ON(!request->global_seqno); GEM_BUG_ON(request->global_seqno != engine->timeline->seqno); + GEM_BUG_ON(i915_seqno_passed(intel_engine_get_seqno(engine), + request->global_seqno)); engine->timeline->seqno--; /* We may be recursing from the signal callback of another i915 fence */ From 3393ce1ed8fc43dbdb83952facaf04e644ca1d54 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 25 Jan 2018 14:25:24 -0800 Subject: [PATCH 104/158] drm/i915/cnp: Properly handle VBT ddc pin out of bounds. If the table result is out of bounds on the array map there is something really wrong with VBT pin so we don't return that vbt_pin, but only return 0 instead. This basically reverts commit 'a8e6f3888b05 ("drm/i915/cnp: Ignore VBT request for know invalid DDC pin.")' Also this properly fixes commit 9c3b2689d01f ("drm/i915/cnl: Map VBT DDC Pin to BSpec DDC Pin.") v2: Do in a way that we don't break other platforms. (Jani) v3: Keep debug message (Jani) v4: Don't mess with 0 mapping was noticed by Jani and addressed with a simple solution suggested by Lucas that makes this even simpler. Fixes: a8e6f3888b05 ("drm/i915/cnp: Ignore VBT request for know invalid DDC pin.") Fixes: 9c3b2689d01f ("drm/i915/cnl: Map VBT DDC Pin to BSpec DDC Pin.") Cc: Radhakrishna Sripada Cc: Jani Nikula Cc: Kai Heng Feng Cc: Lucas De Marchi Suggested-by: Lucas De Marchi Signed-off-by: Rodrigo Vivi Reviewed-by: Lucas De Marchi Tested-by: Kai-Heng Feng Link: https://patchwork.freedesktop.org/patch/msgid/20180125222524.22059-1-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/intel_bios.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 95f0b310d656..cf3f8f1ba6f7 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1107,6 +1107,7 @@ static void sanitize_aux_ch(struct drm_i915_private *dev_priv, } static const u8 cnp_ddc_pin_map[] = { + [0] = 0, /* N/A */ [DDC_BUS_DDI_B] = GMBUS_PIN_1_BXT, [DDC_BUS_DDI_C] = GMBUS_PIN_2_BXT, [DDC_BUS_DDI_D] = GMBUS_PIN_4_CNP, /* sic */ @@ -1116,9 +1117,9 @@ static const u8 cnp_ddc_pin_map[] = { static u8 map_ddc_pin(struct drm_i915_private *dev_priv, u8 vbt_pin) { if (HAS_PCH_CNP(dev_priv)) { - if (vbt_pin > 0 && vbt_pin < ARRAY_SIZE(cnp_ddc_pin_map)) + if (vbt_pin < ARRAY_SIZE(cnp_ddc_pin_map)) { return cnp_ddc_pin_map[vbt_pin]; - if (vbt_pin > GMBUS_PIN_4_CNP) { + } else { DRM_DEBUG_KMS("Ignoring alternate pin: VBT claims DDC pin %d, which is not valid for this platform\n", vbt_pin); return 0; } From c322c649529f9a827f09f19ab5c2fbd9361b6020 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 16 Jan 2018 13:24:14 +0200 Subject: [PATCH 105/158] drm/i915: Add display WA #1175 for planes ending close to right screen edge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As described in the WA on GLK and CNL planes on the right edge of the screen that have less than 4 pixels visible from the beginning of the plane to the edge of the screen can cause FIFO underflow and display corruption. On GLK/CNL I could trigger the problem only if the plane was at the same time also aligned to the top edge of the screen (after clipping) and there were exactly 2 pixels visible from the start of the plane to the right edge of the screen (so couldn't trigger it with 1 or 3 pixels visible). Nevertheless, to be sure, I also applied the WA for these cases. I also couldn't see any problem with the cursor plane and later Art confirmed that it's not affected, so the WA is applied only for the other plane types. v2: - Use -ERANGE instead of -EINVAL. (Chris) Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180116112415.22060-1-imre.deak@intel.com --- drivers/gpu/drm/i915/intel_display.c | 28 ++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_drv.h | 3 ++- drivers/gpu/drm/i915/intel_sprite.c | 2 +- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f9372a21e326..eba716e6a7a7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2931,14 +2931,19 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state return true; } -static int skl_check_main_surface(struct intel_plane_state *plane_state) +static int skl_check_main_surface(const struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) { + struct drm_i915_private *dev_priv = + to_i915(plane_state->base.plane->dev); const struct drm_framebuffer *fb = plane_state->base.fb; unsigned int rotation = plane_state->base.rotation; int x = plane_state->base.src.x1 >> 16; int y = plane_state->base.src.y1 >> 16; int w = drm_rect_width(&plane_state->base.src) >> 16; int h = drm_rect_height(&plane_state->base.src) >> 16; + int dst_x = plane_state->base.dst.x1; + int pipe_src_w = crtc_state->pipe_src_w; int max_width = skl_max_plane_width(fb, 0, rotation); int max_height = 4096; u32 alignment, offset, aux_offset = plane_state->aux.offset; @@ -2949,6 +2954,20 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state) return -EINVAL; } + /* + * Display WA #1175: cnl,glk + * Planes other than the cursor may cause FIFO underflow and display + * corruption if starting less than 4 pixels from the right edge of + * the screen. + */ + if ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) && + dst_x > pipe_src_w - 4) { + DRM_DEBUG_KMS("requested plane X start position %d invalid (valid range %d-%d)\n", + dst_x, + 0, pipe_src_w - 4); + return -ERANGE; + } + intel_add_fb_offsets(&x, &y, plane_state, 0); offset = intel_compute_tile_offset(&x, &y, plane_state, 0); alignment = intel_surf_alignment(fb, 0); @@ -3073,7 +3092,8 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state) return 0; } -int skl_check_plane_surface(struct intel_plane_state *plane_state) +int skl_check_plane_surface(const struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) { const struct drm_framebuffer *fb = plane_state->base.fb; unsigned int rotation = plane_state->base.rotation; @@ -3113,7 +3133,7 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state) plane_state->aux.y = 0; } - ret = skl_check_main_surface(plane_state); + ret = skl_check_main_surface(crtc_state, plane_state); if (ret) return ret; @@ -12778,7 +12798,7 @@ intel_check_primary_plane(struct intel_plane *plane, return 0; if (INTEL_GEN(dev_priv) >= 9) { - ret = skl_check_plane_surface(state); + ret = skl_check_plane_surface(crtc_state, state); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bb849b55548c..1695b2a76c13 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1507,7 +1507,8 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane, unsigned int rotation); -int skl_check_plane_surface(struct intel_plane_state *plane_state); +int skl_check_plane_surface(const struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state); int i9xx_check_plane_surface(struct intel_plane_state *plane_state); /* intel_csr.c */ diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index e4e4a1cbdd47..630d20eecf3c 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1028,7 +1028,7 @@ intel_check_sprite_plane(struct intel_plane *plane, dst->y2 = crtc_y + crtc_h; if (INTEL_GEN(dev_priv) >= 9) { - ret = skl_check_plane_surface(state); + ret = skl_check_plane_surface(crtc_state, state); if (ret) return ret; From 394676f05bee6ddea67e9aafc978a7b9afb72528 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 16 Jan 2018 13:24:15 +0200 Subject: [PATCH 106/158] drm/i915: Add WA for planes ending close to left screen edge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While running the kms_plane clipping test I noticed a similar problem to the one described in Display WA #1175. In this case, similarly for planes other than the cursor, with 1 or 3 pixels visible from the left edge of the screen to the end of the plane and an odd plane X offset used for clipping causes the same kind of underflow and display corruption as described for WA #1175. Fix this in a similar way as that WA rejecting planes ending <4 pixels from the left screen edge. v2: - Rebase on v2 of patch 1/1. Testcase: igt/kms_plane/plane-clipping-pipe-*-planes Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180116112415.22060-2-imre.deak@intel.com --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index eba716e6a7a7..f246ae26ee18 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2959,12 +2959,16 @@ static int skl_check_main_surface(const struct intel_crtc_state *crtc_state, * Planes other than the cursor may cause FIFO underflow and display * corruption if starting less than 4 pixels from the right edge of * the screen. + * Besides the above WA fix the similar problem, where planes other + * than the cursor ending less than 4 pixels from the left edge of the + * screen may cause FIFO underflow and display corruption. */ if ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) && - dst_x > pipe_src_w - 4) { - DRM_DEBUG_KMS("requested plane X start position %d invalid (valid range %d-%d)\n", - dst_x, - 0, pipe_src_w - 4); + (dst_x + w < 4 || dst_x > pipe_src_w - 4)) { + DRM_DEBUG_KMS("requested plane X %s position %d invalid (valid range %d-%d)\n", + dst_x + w < 4 ? "end" : "start", + dst_x + w < 4 ? dst_x + w : dst_x, + 4, pipe_src_w - 4); return -ERANGE; } From 3f43031b169361fefe032c13ebf644d17f3d76d6 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 29 Jan 2018 15:22:14 -0800 Subject: [PATCH 107/158] drm/i915/cnl: Add Cannonlake PCI IDs for another SKU. The only difference is that this SKUs has the full Port A/E split named as Port F. But since SKUs differences don't matter on the platform definition group and ids, let's merge all off them together. v2: Really include the PCI IDs to the picidlist[]; v3: Add the PCI Id for another SKU (Anusha). v4: Update IDs, really include to pciidlists again. v5: Unify all GT2 IDs. v6: Unify in a way that we don't break early-quirks.c v7: Remove GT reference since it doesn't matter here (Paulo) Also move IS_CNL_WITH_PORT_F macro to this patch to make it easier for review this part and also to get used sooner. v8: Rebased on top of commit 5db47e37b387 ("Revert "drm/i915: mark all device info struct with __initconst"") Cc: Dhinakaran Pandiyan Cc: Paulo Zanoni Cc: Lucas De Marchi Signed-off-by: Anusha Srivatsa Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180129232223.766-1-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_pci.c | 5 ++--- include/drm/i915_pciids.h | 18 +++++++----------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 88255f9c3cc4..8b5c1a839655 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2648,6 +2648,8 @@ intel_info(const struct drm_i915_private *dev_priv) (dev_priv)->info.gt == 2) #define IS_CFL_GT3(dev_priv) (IS_COFFEELAKE(dev_priv) && \ (dev_priv)->info.gt == 3) +#define IS_CNL_WITH_PORT_F(dev_priv) (IS_CANNONLAKE(dev_priv) && \ + (INTEL_DEVID(dev_priv) & 0x0004) == 0x0004) #define IS_ALPHA_SUPPORT(intel_info) ((intel_info)->is_alpha_support) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 138228dd7782..4e7a10c89782 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -571,7 +571,7 @@ static const struct intel_device_info intel_coffeelake_gt3_info = { .ddb_size = 1024, \ GLK_COLORS -static const struct intel_device_info intel_cannonlake_gt2_info = { +static const struct intel_device_info intel_cannonlake_info = { GEN10_FEATURES, .is_alpha_support = 1, .platform = INTEL_CANNONLAKE, @@ -649,8 +649,7 @@ static const struct pci_device_id pciidlist[] = { INTEL_CFL_U_GT1_IDS(&intel_coffeelake_gt1_info), INTEL_CFL_U_GT2_IDS(&intel_coffeelake_gt2_info), INTEL_CFL_U_GT3_IDS(&intel_coffeelake_gt3_info), - INTEL_CNL_U_GT2_IDS(&intel_cannonlake_gt2_info), - INTEL_CNL_Y_GT2_IDS(&intel_cannonlake_gt2_info), + INTEL_CNL_IDS(&intel_cannonlake_info), {0, 0, 0} }; MODULE_DEVICE_TABLE(pci, pciidlist); diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index 5db0458dd832..9e1fe6634424 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -414,24 +414,20 @@ INTEL_CFL_U_GT2_IDS(info), \ INTEL_CFL_U_GT3_IDS(info) -/* CNL U 2+2 */ -#define INTEL_CNL_U_GT2_IDS(info) \ +/* CNL */ +#define INTEL_CNL_IDS(info) \ INTEL_VGA_DEVICE(0x5A52, info), \ INTEL_VGA_DEVICE(0x5A5A, info), \ INTEL_VGA_DEVICE(0x5A42, info), \ - INTEL_VGA_DEVICE(0x5A4A, info) - -/* CNL Y 2+2 */ -#define INTEL_CNL_Y_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x5A4A, info), \ INTEL_VGA_DEVICE(0x5A51, info), \ INTEL_VGA_DEVICE(0x5A59, info), \ INTEL_VGA_DEVICE(0x5A41, info), \ INTEL_VGA_DEVICE(0x5A49, info), \ INTEL_VGA_DEVICE(0x5A71, info), \ - INTEL_VGA_DEVICE(0x5A79, info) - -#define INTEL_CNL_IDS(info) \ - INTEL_CNL_U_GT2_IDS(info), \ - INTEL_CNL_Y_GT2_IDS(info) + INTEL_VGA_DEVICE(0x5A79, info), \ + INTEL_VGA_DEVICE(0x5A54, info), \ + INTEL_VGA_DEVICE(0x5A5C, info), \ + INTEL_VGA_DEVICE(0x5A44, info) #endif /* _I915_PCIIDS_H */ From a324fcaca314cafccda77a68ef1f7f6a1355de2c Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 29 Jan 2018 15:22:15 -0800 Subject: [PATCH 108/158] drm/i915/cnl: Add AUX-F support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some Cannonlake SKUs we have a dedicated Aux for port F, that is only the full split between port A and port E. There is still no Aux E for Port E, as in previous platforms, because port_E still means shared lanes with port A. v2: Rebase. v3: Add couple missed PORT_F cases on intel_dp. v4: Rebase and fix commit message. v5: Squash Imre's "drm/i915: Add missing AUX_F power well string" v6: Rebase on top of display headers rework. v7: s/IS_CANNONLAKE/IS_CNL_WITH_PORT_F (DK) v8: Fix Aux bits for Port F (DK) v9: Fix VBT definition of Port F (DK). v10: Squash power well addition to this patch to avoid warns as pointed by DK. v11: Clean up squashed commit message. (David) v12: Remove unnecessary handling for older platforms (DK) Adding AUX_F to PG2 following other existent ones. (DK) Cc: David Weinehall Cc: Dhinakaran Pandiyan Cc: Lucas De Marchi Cc: Imre Deak Cc: Manasi Navare Cc: Ville Syrjälä Signed-off-by: Rodrigo Vivi Reviewed-by: David Weinehall Reviewed-by: Dhinakaran Pandiyan Link: https://patchwork.freedesktop.org/patch/msgid/20180129232223.766-2-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_irq.c | 6 ++++++ drivers/gpu/drm/i915/i915_reg.h | 9 +++++++++ drivers/gpu/drm/i915/intel_display.h | 1 + drivers/gpu/drm/i915/intel_dp.c | 6 ++++++ drivers/gpu/drm/i915/intel_runtime_pm.c | 22 ++++++++++++++++++++++ 6 files changed, 45 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8b5c1a839655..d29f95d8999a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1255,6 +1255,7 @@ enum modeset_restore { #define DP_AUX_B 0x10 #define DP_AUX_C 0x20 #define DP_AUX_D 0x30 +#define DP_AUX_F 0x60 #define DDC_PIN_B 0x05 #define DDC_PIN_C 0x04 diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 85c46a25265d..79fadb50ab69 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2585,6 +2585,9 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) GEN9_AUX_CHANNEL_C | GEN9_AUX_CHANNEL_D; + if (IS_CNL_WITH_PORT_F(dev_priv)) + tmp_mask |= CNL_AUX_CHANNEL_F; + if (iir & tmp_mask) { dp_aux_irq_handler(dev_priv); found = true; @@ -3617,6 +3620,9 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) de_pipe_masked |= GEN8_DE_PIPE_IRQ_FAULT_ERRORS; } + if (IS_CNL_WITH_PORT_F(dev_priv)) + de_port_masked |= CNL_AUX_CHANNEL_F; + de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b06db954c79f..98b4d8357a4c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1312,6 +1312,7 @@ enum i915_power_well_id { CNL_DISP_PW_AUX_B = GLK_DISP_PW_AUX_B, CNL_DISP_PW_AUX_C = GLK_DISP_PW_AUX_C, CNL_DISP_PW_AUX_D, + CNL_DISP_PW_AUX_F, SKL_DISP_PW_1 = 14, SKL_DISP_PW_2, @@ -5283,6 +5284,13 @@ enum { #define _DPD_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64320) #define _DPD_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64324) +#define _DPF_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64510) +#define _DPF_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64514) +#define _DPF_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64518) +#define _DPF_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6451c) +#define _DPF_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64520) +#define _DPF_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64524) + #define DP_AUX_CH_CTL(port) _MMIO_PORT(port, _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL) #define DP_AUX_CH_DATA(port, i) _MMIO(_PORT(port, _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ @@ -6938,6 +6946,7 @@ enum { #define GEN8_DE_PORT_IMR _MMIO(0x44444) #define GEN8_DE_PORT_IIR _MMIO(0x44448) #define GEN8_DE_PORT_IER _MMIO(0x4444c) +#define CNL_AUX_CHANNEL_F (1 << 28) #define GEN9_AUX_CHANNEL_D (1 << 27) #define GEN9_AUX_CHANNEL_C (1 << 26) #define GEN9_AUX_CHANNEL_B (1 << 25) diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h index e47638931b51..30fa2041a45f 100644 --- a/drivers/gpu/drm/i915/intel_display.h +++ b/drivers/gpu/drm/i915/intel_display.h @@ -172,6 +172,7 @@ enum intel_display_power_domain { POWER_DOMAIN_AUX_B, POWER_DOMAIN_AUX_C, POWER_DOMAIN_AUX_D, + POWER_DOMAIN_AUX_F, POWER_DOMAIN_GMBUS, POWER_DOMAIN_MODESET, POWER_DOMAIN_GT_IRQ, diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 48342a85e500..ba0bbce742a5 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1299,6 +1299,9 @@ static enum port intel_aux_port(struct drm_i915_private *dev_priv, case DP_AUX_D: aux_port = PORT_D; break; + case DP_AUX_F: + aux_port = PORT_F; + break; default: MISSING_CASE(info->alternate_aux_channel); aux_port = PORT_A; @@ -5998,6 +6001,9 @@ intel_dp_init_connector_port_info(struct intel_digital_port *intel_dig_port) /* FIXME: Check VBT for actual wiring of PORT E */ intel_dp->aux_power_domain = POWER_DOMAIN_AUX_D; break; + case PORT_F: + intel_dp->aux_power_domain = POWER_DOMAIN_AUX_F; + break; default: MISSING_CASE(encoder->port); } diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 5b1aa4b9c72c..a274e930f045 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -124,6 +124,8 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) return "AUX_C"; case POWER_DOMAIN_AUX_D: return "AUX_D"; + case POWER_DOMAIN_AUX_F: + return "AUX_F"; case POWER_DOMAIN_GMBUS: return "GMBUS"; case POWER_DOMAIN_INIT: @@ -1828,6 +1830,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, BIT_ULL(POWER_DOMAIN_AUX_B) | \ BIT_ULL(POWER_DOMAIN_AUX_C) | \ BIT_ULL(POWER_DOMAIN_AUX_D) | \ + BIT_ULL(POWER_DOMAIN_AUX_F) | \ BIT_ULL(POWER_DOMAIN_AUDIO) | \ BIT_ULL(POWER_DOMAIN_VGA) | \ BIT_ULL(POWER_DOMAIN_INIT)) @@ -1855,6 +1858,9 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, #define CNL_DISPLAY_AUX_D_POWER_DOMAINS ( \ BIT_ULL(POWER_DOMAIN_AUX_D) | \ BIT_ULL(POWER_DOMAIN_INIT)) +#define CNL_DISPLAY_AUX_F_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_AUX_F) | \ + BIT_ULL(POWER_DOMAIN_INIT)) #define CNL_DISPLAY_DC_OFF_POWER_DOMAINS ( \ CNL_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ BIT_ULL(POWER_DOMAIN_GT_IRQ) | \ @@ -2405,6 +2411,12 @@ static struct i915_power_well cnl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_DDI_D, }, + { + .name = "AUX F", + .domains = CNL_DISPLAY_AUX_F_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = CNL_DISP_PW_AUX_F, + }, }; static int @@ -2520,6 +2532,16 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) set_power_wells(power_domains, skl_power_wells); } else if (IS_CANNONLAKE(dev_priv)) { set_power_wells(power_domains, cnl_power_wells); + + /* + * Aux IO is getting enabled for all ports + * regardless the presence or use. So, in order to avoid + * timeouts, lets remove it from the list + * for the SKUs without port F. + */ + if (!IS_CNL_WITH_PORT_F(dev_priv)) + power_domains->power_well_count -= 1; + } else if (IS_BROXTON(dev_priv)) { set_power_wells(power_domains, bxt_power_wells); } else if (IS_GEMINILAKE(dev_priv)) { From b1ae6a8b7a85e830a6831cc76e33350e6a58437a Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 29 Jan 2018 15:22:16 -0800 Subject: [PATCH 109/158] drm/i915/cnl: Extend Wa 1178 to Aux F. We also need to extend this WA to Aux F. Cc: Dhinakaran Pandiyan Cc: Lucas De Marchi Signed-off-by: Rodrigo Vivi Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20180129232223.766-3-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 4 +++- drivers/gpu/drm/i915/intel_runtime_pm.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 98b4d8357a4c..d8e283cef448 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8437,10 +8437,12 @@ enum skl_power_gate { #define _CNL_AUX_ANAOVRD1_B 0x162250 #define _CNL_AUX_ANAOVRD1_C 0x162210 #define _CNL_AUX_ANAOVRD1_D 0x1622D0 +#define _CNL_AUX_ANAOVRD1_F 0x162A90 #define CNL_AUX_ANAOVRD1(pw) _MMIO(_PICK(_CNL_AUX_REG_IDX(pw), \ _CNL_AUX_ANAOVRD1_B, \ _CNL_AUX_ANAOVRD1_C, \ - _CNL_AUX_ANAOVRD1_D)) + _CNL_AUX_ANAOVRD1_D, \ + _CNL_AUX_ANAOVRD1_F)) #define CNL_AUX_ANAOVRD1_ENABLE (1<<16) #define CNL_AUX_ANAOVRD1_LDO_BYPASS (1<<23) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index a274e930f045..294b85adc413 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -395,7 +395,7 @@ static void hsw_power_well_enable(struct drm_i915_private *dev_priv, /* Display WA #1178: cnl */ if (IS_CANNONLAKE(dev_priv) && (id == CNL_DISP_PW_AUX_B || id == CNL_DISP_PW_AUX_C || - id == CNL_DISP_PW_AUX_D)) { + id == CNL_DISP_PW_AUX_D || id == CNL_DISP_PW_AUX_F)) { val = I915_READ(CNL_AUX_ANAOVRD1(id)); val |= CNL_AUX_ANAOVRD1_ENABLE | CNL_AUX_ANAOVRD1_LDO_BYPASS; I915_WRITE(CNL_AUX_ANAOVRD1(id), val); From 8f942ed00efe9f6626031521c439070cca47b364 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 29 Jan 2018 15:22:17 -0800 Subject: [PATCH 110/158] drm/i915/cnl: Fix _CNL_PORT_TX_DW2_LN0_F definition. This was wrong since its introduction on commit '04416108ccea ("drm/i915/cnl: Add registers related to voltage swing sequences.")' But since no Port F was needed so far we don't need to propagate fixes back there. Cc: Lucas De Marchi Cc: Manasi Navare Signed-off-by: Rodrigo Vivi Reviewed-by: Dhinakaran Pandiyan Link: https://patchwork.freedesktop.org/patch/msgid/20180129232223.766-4-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d8e283cef448..f66f48ffbdd6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1964,7 +1964,7 @@ enum i915_power_well_id { #define _CNL_PORT_TX_DW2_LN0_B 0x162648 #define _CNL_PORT_TX_DW2_LN0_C 0x162C48 #define _CNL_PORT_TX_DW2_LN0_D 0x162E48 -#define _CNL_PORT_TX_DW2_LN0_F 0x162A48 +#define _CNL_PORT_TX_DW2_LN0_F 0x162848 #define CNL_PORT_TX_DW2_GRP(port) _MMIO_PORT6(port, \ _CNL_PORT_TX_DW2_GRP_AE, \ _CNL_PORT_TX_DW2_GRP_B, \ From 376faf8a3b2ff497b1f1583ab4b23bc650711764 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 29 Jan 2018 15:22:18 -0800 Subject: [PATCH 111/158] drm/i915: Fix DPLCLKA_CFGCR0 bits for Port F. Since when it got introduced with commit '555e38d27317 ("drm/i915/cnl: DDI - PLL mapping")' the support for Port F was wrong, because Port F bits are far from bits used for A to E. Since Port F is not used so far we don't need to propagate Fixes back there. v2: Reuse _SHIFT definition to avoid complicated duplication (DK). Cc: Dhinakaran Pandiyan Cc: Lucas De Marchi Cc: Manasi Navare Signed-off-by: Rodrigo Vivi Reviewed-by: Dhinakaran Pandiyan Link: https://patchwork.freedesktop.org/patch/msgid/20180129232223.766-5-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f66f48ffbdd6..596348632ed0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8759,10 +8759,12 @@ enum skl_power_gate { * CNL Clocks */ #define DPCLKA_CFGCR0 _MMIO(0x6C200) -#define DPCLKA_CFGCR0_DDI_CLK_OFF(port) (1 << ((port)+10)) -#define DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port) (3 << ((port)*2)) -#define DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port) ((port)*2) -#define DPCLKA_CFGCR0_DDI_CLK_SEL(pll, port) ((pll) << ((port)*2)) +#define DPCLKA_CFGCR0_DDI_CLK_OFF(port) (1 << ((port) == PORT_F ? 23 : \ + (port)+10)) +#define DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port) ((port) == PORT_F ? 21 : \ + (port)*2) +#define DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port) (3 << DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port)) +#define DPCLKA_CFGCR0_DDI_CLK_SEL(pll, port) ((pll) << DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port)) /* CNL PLL */ #define DPLL0_ENABLE 0x46010 From 3a2a59ccb11c93e778f83548b6963e4d061f5810 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 29 Jan 2018 15:22:19 -0800 Subject: [PATCH 112/158] drm/i915/cnl: Add right GMBUS pin number for HDMI on Port F. On CNP Pin 3 is for misc of Port F usage depending on the configuration. For CNL that uses Port F, pin 3 is the one. v2: Make it more generic and update commit message. Cc: Anusha Srivatsa Cc: Lucas De Marchi Cc: Manasi Navare Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180129232223.766-6-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 303c6d5acbde..a8f05f7d9226 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1935,6 +1935,9 @@ static u8 cnp_port_to_ddc_pin(struct drm_i915_private *dev_priv, case PORT_D: ddc_pin = GMBUS_PIN_4_CNP; break; + case PORT_F: + ddc_pin = GMBUS_PIN_3_BXT; + break; default: MISSING_CASE(port); ddc_pin = GMBUS_PIN_1_BXT; From 7533eb4f89f70f9efb81171bcfa528f51d3d2618 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 29 Jan 2018 15:22:20 -0800 Subject: [PATCH 113/158] drm/i915: For HPD connected port use hpd_pin instead of port. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's try to simplify this mapping to hpd_pin -> bit instead using port. So for CNL with port F where we have this port using hdp_pin and bits of other ports we don't need to duplicated the mapping. But for now this is only a re-org with no functional change expected. v2: Add missing lines and nuke @port reference from code documentation. (Ville) Cc: Lucas De Marchi Suggested-by: Ville Syrjälä Cc: Ville Syrjälä Signed-off-by: Rodrigo Vivi Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180129232223.766-7-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 150 ++++++++++++++-------------- drivers/gpu/drm/i915/intel_drv.h | 3 +- drivers/gpu/drm/i915/intel_lspcon.c | 3 +- 3 files changed, 77 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ba0bbce742a5..f00a00a703e5 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4461,173 +4461,174 @@ edp_detect(struct intel_dp *intel_dp) return status; } -static bool ibx_digital_port_connected(struct drm_i915_private *dev_priv, - struct intel_digital_port *port) +static bool ibx_digital_port_connected(struct intel_encoder *encoder) { + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u32 bit; - switch (port->base.port) { - case PORT_B: + switch (encoder->hpd_pin) { + case HPD_PORT_B: bit = SDE_PORTB_HOTPLUG; break; - case PORT_C: + case HPD_PORT_C: bit = SDE_PORTC_HOTPLUG; break; - case PORT_D: + case HPD_PORT_D: bit = SDE_PORTD_HOTPLUG; break; default: - MISSING_CASE(port->base.port); + MISSING_CASE(encoder->hpd_pin); return false; } return I915_READ(SDEISR) & bit; } -static bool cpt_digital_port_connected(struct drm_i915_private *dev_priv, - struct intel_digital_port *port) +static bool cpt_digital_port_connected(struct intel_encoder *encoder) { + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u32 bit; - switch (port->base.port) { - case PORT_B: + switch (encoder->hpd_pin) { + case HPD_PORT_B: bit = SDE_PORTB_HOTPLUG_CPT; break; - case PORT_C: + case HPD_PORT_C: bit = SDE_PORTC_HOTPLUG_CPT; break; - case PORT_D: + case HPD_PORT_D: bit = SDE_PORTD_HOTPLUG_CPT; break; default: - MISSING_CASE(port->base.port); + MISSING_CASE(encoder->hpd_pin); return false; } return I915_READ(SDEISR) & bit; } -static bool spt_digital_port_connected(struct drm_i915_private *dev_priv, - struct intel_digital_port *port) +static bool spt_digital_port_connected(struct intel_encoder *encoder) { + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u32 bit; - switch (port->base.port) { - case PORT_A: + switch (encoder->hpd_pin) { + case HPD_PORT_A: bit = SDE_PORTA_HOTPLUG_SPT; break; - case PORT_E: + case HPD_PORT_E: bit = SDE_PORTE_HOTPLUG_SPT; break; default: - return cpt_digital_port_connected(dev_priv, port); + return cpt_digital_port_connected(encoder); } return I915_READ(SDEISR) & bit; } -static bool g4x_digital_port_connected(struct drm_i915_private *dev_priv, - struct intel_digital_port *port) +static bool g4x_digital_port_connected(struct intel_encoder *encoder) { + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u32 bit; - switch (port->base.port) { - case PORT_B: + switch (encoder->hpd_pin) { + case HPD_PORT_B: bit = PORTB_HOTPLUG_LIVE_STATUS_G4X; break; - case PORT_C: + case HPD_PORT_C: bit = PORTC_HOTPLUG_LIVE_STATUS_G4X; break; - case PORT_D: + case HPD_PORT_D: bit = PORTD_HOTPLUG_LIVE_STATUS_G4X; break; default: - MISSING_CASE(port->base.port); + MISSING_CASE(encoder->hpd_pin); return false; } return I915_READ(PORT_HOTPLUG_STAT) & bit; } -static bool gm45_digital_port_connected(struct drm_i915_private *dev_priv, - struct intel_digital_port *port) +static bool gm45_digital_port_connected(struct intel_encoder *encoder) { + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u32 bit; - switch (port->base.port) { - case PORT_B: + switch (encoder->hpd_pin) { + case HPD_PORT_B: bit = PORTB_HOTPLUG_LIVE_STATUS_GM45; break; - case PORT_C: + case HPD_PORT_C: bit = PORTC_HOTPLUG_LIVE_STATUS_GM45; break; - case PORT_D: + case HPD_PORT_D: bit = PORTD_HOTPLUG_LIVE_STATUS_GM45; break; default: - MISSING_CASE(port->base.port); + MISSING_CASE(encoder->hpd_pin); return false; } return I915_READ(PORT_HOTPLUG_STAT) & bit; } -static bool ilk_digital_port_connected(struct drm_i915_private *dev_priv, - struct intel_digital_port *port) +static bool ilk_digital_port_connected(struct intel_encoder *encoder) { - if (port->base.port == PORT_A) + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (encoder->hpd_pin == HPD_PORT_A) return I915_READ(DEISR) & DE_DP_A_HOTPLUG; else - return ibx_digital_port_connected(dev_priv, port); + return ibx_digital_port_connected(encoder); } -static bool snb_digital_port_connected(struct drm_i915_private *dev_priv, - struct intel_digital_port *port) +static bool snb_digital_port_connected(struct intel_encoder *encoder) { - if (port->base.port == PORT_A) + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (encoder->hpd_pin == HPD_PORT_A) return I915_READ(DEISR) & DE_DP_A_HOTPLUG; else - return cpt_digital_port_connected(dev_priv, port); + return cpt_digital_port_connected(encoder); } -static bool ivb_digital_port_connected(struct drm_i915_private *dev_priv, - struct intel_digital_port *port) +static bool ivb_digital_port_connected(struct intel_encoder *encoder) { - if (port->base.port == PORT_A) + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (encoder->hpd_pin == HPD_PORT_A) return I915_READ(DEISR) & DE_DP_A_HOTPLUG_IVB; else - return cpt_digital_port_connected(dev_priv, port); + return cpt_digital_port_connected(encoder); } -static bool bdw_digital_port_connected(struct drm_i915_private *dev_priv, - struct intel_digital_port *port) +static bool bdw_digital_port_connected(struct intel_encoder *encoder) { - if (port->base.port == PORT_A) + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (encoder->hpd_pin == HPD_PORT_A) return I915_READ(GEN8_DE_PORT_ISR) & GEN8_PORT_DP_A_HOTPLUG; else - return cpt_digital_port_connected(dev_priv, port); + return cpt_digital_port_connected(encoder); } -static bool bxt_digital_port_connected(struct drm_i915_private *dev_priv, - struct intel_digital_port *intel_dig_port) +static bool bxt_digital_port_connected(struct intel_encoder *encoder) { - struct intel_encoder *intel_encoder = &intel_dig_port->base; - enum port port; + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u32 bit; - port = intel_hpd_pin_to_port(intel_encoder->hpd_pin); - switch (port) { - case PORT_A: + switch (encoder->hpd_pin) { + case HPD_PORT_A: bit = BXT_DE_PORT_HP_DDIA; break; - case PORT_B: + case HPD_PORT_B: bit = BXT_DE_PORT_HP_DDIB; break; - case PORT_C: + case HPD_PORT_C: bit = BXT_DE_PORT_HP_DDIC; break; default: - MISSING_CASE(port); + MISSING_CASE(encoder->hpd_pin); return false; } @@ -4636,33 +4637,33 @@ static bool bxt_digital_port_connected(struct drm_i915_private *dev_priv, /* * intel_digital_port_connected - is the specified port connected? - * @dev_priv: i915 private structure - * @port: the port to test + * @encoder: intel_encoder * - * Return %true if @port is connected, %false otherwise. + * Return %true if port is connected, %false otherwise. */ -bool intel_digital_port_connected(struct drm_i915_private *dev_priv, - struct intel_digital_port *port) +bool intel_digital_port_connected(struct intel_encoder *encoder) { + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + if (HAS_GMCH_DISPLAY(dev_priv)) { if (IS_GM45(dev_priv)) - return gm45_digital_port_connected(dev_priv, port); + return gm45_digital_port_connected(encoder); else - return g4x_digital_port_connected(dev_priv, port); + return g4x_digital_port_connected(encoder); } if (IS_GEN5(dev_priv)) - return ilk_digital_port_connected(dev_priv, port); + return ilk_digital_port_connected(encoder); else if (IS_GEN6(dev_priv)) - return snb_digital_port_connected(dev_priv, port); + return snb_digital_port_connected(encoder); else if (IS_GEN7(dev_priv)) - return ivb_digital_port_connected(dev_priv, port); + return ivb_digital_port_connected(encoder); else if (IS_GEN8(dev_priv)) - return bdw_digital_port_connected(dev_priv, port); + return bdw_digital_port_connected(encoder); else if (IS_GEN9_LP(dev_priv)) - return bxt_digital_port_connected(dev_priv, port); + return bxt_digital_port_connected(encoder); else - return spt_digital_port_connected(dev_priv, port); + return spt_digital_port_connected(encoder); } static struct edid * @@ -4721,8 +4722,7 @@ intel_dp_long_pulse(struct intel_connector *connector) /* Can't disconnect eDP, but you can close the lid... */ if (intel_dp_is_edp(intel_dp)) status = edp_detect(intel_dp); - else if (intel_digital_port_connected(dev_priv, - dp_to_dig_port(intel_dp))) + else if (intel_digital_port_connected(&dp_to_dig_port(intel_dp)->base)) status = intel_dp_detect_dpcd(intel_dp); else status = connector_status_disconnected; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1695b2a76c13..71355fdec94a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1591,8 +1591,7 @@ static inline unsigned int intel_dp_unused_lane_mask(int lane_count) bool intel_dp_read_dpcd(struct intel_dp *intel_dp); int intel_dp_link_required(int pixel_clock, int bpp); int intel_dp_max_data_rate(int max_link_clock, int max_lanes); -bool intel_digital_port_connected(struct drm_i915_private *dev_priv, - struct intel_digital_port *port); +bool intel_digital_port_connected(struct intel_encoder *encoder); /* intel_dp_aux_backlight.c */ int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector); diff --git a/drivers/gpu/drm/i915/intel_lspcon.c b/drivers/gpu/drm/i915/intel_lspcon.c index dcbc786479f9..8ae8f42f430a 100644 --- a/drivers/gpu/drm/i915/intel_lspcon.c +++ b/drivers/gpu/drm/i915/intel_lspcon.c @@ -167,11 +167,10 @@ static void lspcon_resume_in_pcon_wa(struct intel_lspcon *lspcon) { struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); unsigned long start = jiffies; while (1) { - if (intel_digital_port_connected(dev_priv, dig_port)) { + if (intel_digital_port_connected(&dig_port->base)) { DRM_DEBUG_KMS("LSPCON recovering in PCON mode after %u ms\n", jiffies_to_msecs(jiffies - start)); return; From cf53902f48c3c7a34c6955f79c8800d1746de52c Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 29 Jan 2018 15:22:21 -0800 Subject: [PATCH 114/158] drm/i915/cnl: Add HPD support for Port F. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On CNP boards that are using DDI F, bit 25 (SDE_PORTE_HOTPLUG_SPT) is representing the Digital Port F hotplug line when the Digital Port F hotplug detect input is enabled. v2: Reuse all existent structure instead of adding a new HPD_PORT_F pointing to pin of port E. v3: Use IS_CNL_WITH_PORT_F so we can start upstreaming this right now. If that SKU ever get a proper name we come back and update it. v4: Rebase on top of digital connected port using encoder instead of port. v5: Moved IS_CNL_WITH_PORT_F definition to the PCI IDs patch. Cc: Lucas De Marchi Cc: Manasi Navare Cc: Dhinakaran Pandiyan Cc: Ville Syrjälä Signed-off-by: Rodrigo Vivi Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180129232223.766-8-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 6 +++-- drivers/gpu/drm/i915/i915_irq.c | 35 +++++++++++++++------------- drivers/gpu/drm/i915/intel_dp.c | 4 +++- drivers/gpu/drm/i915/intel_hdmi.c | 2 +- drivers/gpu/drm/i915/intel_hotplug.c | 19 +++++++++++---- 5 files changed, 42 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d29f95d8999a..2d855faac708 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2958,8 +2958,10 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, void intel_hpd_init(struct drm_i915_private *dev_priv); void intel_hpd_init_work(struct drm_i915_private *dev_priv); void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); -enum port intel_hpd_pin_to_port(enum hpd_pin pin); -enum hpd_pin intel_hpd_pin(enum port port); +enum port intel_hpd_pin_to_port(struct drm_i915_private *dev_priv, + enum hpd_pin pin); +enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv, + enum port port); bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin); void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 79fadb50ab69..252feff2892d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1574,10 +1574,11 @@ static bool i9xx_port_hotplug_long_detect(enum port port, u32 val) * * Note that the caller is expected to zero out the masks initially. */ -static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask, - u32 hotplug_trigger, u32 dig_hotplug_reg, - const u32 hpd[HPD_NUM_PINS], - bool long_pulse_detect(enum port port, u32 val)) +static void intel_get_hpd_pins(struct drm_i915_private *dev_priv, + u32 *pin_mask, u32 *long_mask, + u32 hotplug_trigger, u32 dig_hotplug_reg, + const u32 hpd[HPD_NUM_PINS], + bool long_pulse_detect(enum port port, u32 val)) { enum port port; int i; @@ -1588,7 +1589,7 @@ static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask, *pin_mask |= BIT(i); - port = intel_hpd_pin_to_port(i); + port = intel_hpd_pin_to_port(dev_priv, i); if (port == PORT_NONE) continue; @@ -1976,8 +1977,9 @@ static void i9xx_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; if (hotplug_trigger) { - intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, - hotplug_trigger, hpd_status_g4x, + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + hotplug_trigger, hotplug_trigger, + hpd_status_g4x, i9xx_port_hotplug_long_detect); intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); @@ -1989,8 +1991,9 @@ static void i9xx_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; if (hotplug_trigger) { - intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, - hotplug_trigger, hpd_status_i915, + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + hotplug_trigger, hotplug_trigger, + hpd_status_i915, i9xx_port_hotplug_long_detect); intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); } @@ -2191,7 +2194,7 @@ static void ibx_hpd_irq_handler(struct drm_i915_private *dev_priv, if (!hotplug_trigger) return; - intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, hpd, pch_port_hotplug_long_detect); @@ -2333,8 +2336,8 @@ static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); - intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, - dig_hotplug_reg, hpd_spt, + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + hotplug_trigger, dig_hotplug_reg, hpd_spt, spt_port_hotplug_long_detect); } @@ -2344,8 +2347,8 @@ static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG2); I915_WRITE(PCH_PORT_HOTPLUG2, dig_hotplug_reg); - intel_get_hpd_pins(&pin_mask, &long_mask, hotplug2_trigger, - dig_hotplug_reg, hpd_spt, + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + hotplug2_trigger, dig_hotplug_reg, hpd_spt, spt_port_hotplug2_long_detect); } @@ -2365,7 +2368,7 @@ static void ilk_hpd_irq_handler(struct drm_i915_private *dev_priv, dig_hotplug_reg = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL); I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, dig_hotplug_reg); - intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, hpd, ilk_port_hotplug_long_detect); @@ -2542,7 +2545,7 @@ static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv, dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); - intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, hpd, bxt_port_hotplug_long_detect); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f00a00a703e5..1b37a40d2686 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5981,8 +5981,10 @@ intel_dp_init_connector_port_info(struct intel_digital_port *intel_dig_port) { struct intel_encoder *encoder = &intel_dig_port->base; struct intel_dp *intel_dp = &intel_dig_port->dp; + struct intel_encoder *intel_encoder = &intel_dig_port->base; + struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); - encoder->hpd_pin = intel_hpd_pin(encoder->port); + encoder->hpd_pin = intel_hpd_pin_default(dev_priv, encoder->port); switch (encoder->port) { case PORT_A: diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index a8f05f7d9226..2df18a85c3b4 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -2091,7 +2091,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, if (WARN_ON(port == PORT_A)) return; - intel_encoder->hpd_pin = intel_hpd_pin(port); + intel_encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port); if (HAS_DDI(dev_priv)) intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 875d5d218d5c..fe28c1ea84a5 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -78,12 +78,14 @@ /** * intel_hpd_port - return port hard associated with certain pin. + * @dev_priv: private driver data pointer * @pin: the hpd pin to get associated port * * Return port that is associatade with @pin and PORT_NONE if no port is * hard associated with that @pin. */ -enum port intel_hpd_pin_to_port(enum hpd_pin pin) +enum port intel_hpd_pin_to_port(struct drm_i915_private *dev_priv, + enum hpd_pin pin) { switch (pin) { case HPD_PORT_A: @@ -95,6 +97,8 @@ enum port intel_hpd_pin_to_port(enum hpd_pin pin) case HPD_PORT_D: return PORT_D; case HPD_PORT_E: + if (IS_CNL_WITH_PORT_F(dev_priv)) + return PORT_F; return PORT_E; default: return PORT_NONE; /* no port for this pin */ @@ -102,13 +106,17 @@ enum port intel_hpd_pin_to_port(enum hpd_pin pin) } /** - * intel_hpd_pin - return pin hard associated with certain port. + * intel_hpd_pin_default - return default pin associated with certain port. + * @dev_priv: private driver data pointer * @port: the hpd port to get associated pin * + * It is only valid and used by digital port encoder. + * * Return pin that is associatade with @port and HDP_NONE if no pin is * hard associated with that @port. */ -enum hpd_pin intel_hpd_pin(enum port port) +enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv, + enum port port) { switch (port) { case PORT_A: @@ -121,6 +129,9 @@ enum hpd_pin intel_hpd_pin(enum port port) return HPD_PORT_D; case PORT_E: return HPD_PORT_E; + case PORT_F: + if (IS_CNL_WITH_PORT_F(dev_priv)) + return HPD_PORT_E; default: MISSING_CASE(port); return HPD_NONE; @@ -417,7 +428,7 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, if (!(BIT(i) & pin_mask)) continue; - port = intel_hpd_pin_to_port(i); + port = intel_hpd_pin_to_port(dev_priv, i); is_dig_port = port != PORT_NONE && dev_priv->hotplug.irq_port[port]; From 9787e835fa98bbcd9abf90eff90c6f603d25d416 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 29 Jan 2018 15:22:22 -0800 Subject: [PATCH 115/158] drm/i915/cnl: Enable DDI-F on Cannonlake. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now let's finish the Port-F support by adding the proper port F detection, irq and power well support. v2: Rebase v3: Use BIT_ULL v4: Cover missed case on ddi init. v5: Update commit message. v6: Rebase on top of display headers rework. v7: Squash power-well handling related to DDI F to this patch to avoid warns as pointed out by DK. v8: Introduce DDI_F_LANES to PG2. (DK) v9: Squash in the PORT_F case for enabling DP MST encoder. (DK) Cc: Dhinakaran Pandiyan Cc: Manasi Navare Cc: Ville Syrjälä Signed-off-by: Rodrigo Vivi Reviewed-by: David Weinehall Reviewed-by: Dhinakaran Pandiyan Link: https://patchwork.freedesktop.org/patch/msgid/20180129232223.766-9-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_ddi.c | 4 ++++ drivers/gpu/drm/i915/intel_display.c | 6 +++++- drivers/gpu/drm/i915/intel_display.h | 2 ++ drivers/gpu/drm/i915/intel_dp.c | 3 ++- drivers/gpu/drm/i915/intel_runtime_pm.c | 20 +++++++++++++++++--- 6 files changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 596348632ed0..cf286980dacc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1304,6 +1304,7 @@ enum i915_power_well_id { SKL_DISP_PW_DDI_B, SKL_DISP_PW_DDI_C, SKL_DISP_PW_DDI_D, + CNL_DISP_PW_DDI_F = 6, GLK_DISP_PW_AUX_A = 8, GLK_DISP_PW_AUX_B, @@ -8860,6 +8861,7 @@ enum skl_power_gate { #define SFUSE_STRAP_RAW_FREQUENCY (1<<8) #define SFUSE_STRAP_DISPLAY_DISABLED (1<<7) #define SFUSE_STRAP_CRT_DISABLED (1<<6) +#define SFUSE_STRAP_DDIF_DETECTED (1<<3) #define SFUSE_STRAP_DDIB_DETECTED (1<<2) #define SFUSE_STRAP_DDIC_DETECTED (1<<1) #define SFUSE_STRAP_DDID_DETECTED (1<<0) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 2756a69b6207..d9b52fe82932 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2910,6 +2910,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) intel_dig_port->ddi_io_power_domain = POWER_DOMAIN_PORT_DDI_E_IO; break; + case PORT_F: + intel_dig_port->ddi_io_power_domain = + POWER_DOMAIN_PORT_DDI_F_IO; + break; default: MISSING_CASE(port); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f246ae26ee18..217badde15fa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5671,6 +5671,8 @@ enum intel_display_power_domain intel_port_to_power_domain(enum port port) return POWER_DOMAIN_PORT_DDI_D_LANES; case PORT_E: return POWER_DOMAIN_PORT_DDI_E_LANES; + case PORT_F: + return POWER_DOMAIN_PORT_DDI_F_LANES; default: MISSING_CASE(port); return POWER_DOMAIN_PORT_OTHER; @@ -13624,7 +13626,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) if (found || IS_GEN9_BC(dev_priv)) intel_ddi_init(dev_priv, PORT_A); - /* DDI B, C and D detection is indicated by the SFUSE_STRAP + /* DDI B, C, D, and F detection is indicated by the SFUSE_STRAP * register */ found = I915_READ(SFUSE_STRAP); @@ -13634,6 +13636,8 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) intel_ddi_init(dev_priv, PORT_C); if (found & SFUSE_STRAP_DDID_DETECTED) intel_ddi_init(dev_priv, PORT_D); + if (found & SFUSE_STRAP_DDIF_DETECTED) + intel_ddi_init(dev_priv, PORT_F); /* * On SKL we don't have a way to detect DDI-E so we rely on VBT. */ diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h index 30fa2041a45f..c4042e342f50 100644 --- a/drivers/gpu/drm/i915/intel_display.h +++ b/drivers/gpu/drm/i915/intel_display.h @@ -157,11 +157,13 @@ enum intel_display_power_domain { POWER_DOMAIN_PORT_DDI_C_LANES, POWER_DOMAIN_PORT_DDI_D_LANES, POWER_DOMAIN_PORT_DDI_E_LANES, + POWER_DOMAIN_PORT_DDI_F_LANES, POWER_DOMAIN_PORT_DDI_A_IO, POWER_DOMAIN_PORT_DDI_B_IO, POWER_DOMAIN_PORT_DDI_C_IO, POWER_DOMAIN_PORT_DDI_D_IO, POWER_DOMAIN_PORT_DDI_E_IO, + POWER_DOMAIN_PORT_DDI_F_IO, POWER_DOMAIN_PORT_DSI, POWER_DOMAIN_PORT_CRT, POWER_DOMAIN_PORT_OTHER, diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1b37a40d2686..9732b022fb50 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -6132,7 +6132,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, /* init MST on ports that can support it */ if (HAS_DP_MST(dev_priv) && !intel_dp_is_edp(intel_dp) && - (port == PORT_B || port == PORT_C || port == PORT_D)) + (port == PORT_B || port == PORT_C || + port == PORT_D || port == PORT_F)) intel_dp_mst_encoder_init(intel_dig_port, intel_connector->base.base.id); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 294b85adc413..70e659772a7a 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -94,6 +94,8 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) return "PORT_DDI_D_LANES"; case POWER_DOMAIN_PORT_DDI_E_LANES: return "PORT_DDI_E_LANES"; + case POWER_DOMAIN_PORT_DDI_F_LANES: + return "PORT_DDI_F_LANES"; case POWER_DOMAIN_PORT_DDI_A_IO: return "PORT_DDI_A_IO"; case POWER_DOMAIN_PORT_DDI_B_IO: @@ -104,6 +106,8 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) return "PORT_DDI_D_IO"; case POWER_DOMAIN_PORT_DDI_E_IO: return "PORT_DDI_E_IO"; + case POWER_DOMAIN_PORT_DDI_F_IO: + return "PORT_DDI_F_IO"; case POWER_DOMAIN_PORT_DSI: return "PORT_DSI"; case POWER_DOMAIN_PORT_CRT: @@ -1827,6 +1831,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, BIT_ULL(POWER_DOMAIN_PORT_DDI_B_LANES) | \ BIT_ULL(POWER_DOMAIN_PORT_DDI_C_LANES) | \ BIT_ULL(POWER_DOMAIN_PORT_DDI_D_LANES) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_F_LANES) | \ BIT_ULL(POWER_DOMAIN_AUX_B) | \ BIT_ULL(POWER_DOMAIN_AUX_C) | \ BIT_ULL(POWER_DOMAIN_AUX_D) | \ @@ -1861,6 +1866,9 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, #define CNL_DISPLAY_AUX_F_POWER_DOMAINS ( \ BIT_ULL(POWER_DOMAIN_AUX_F) | \ BIT_ULL(POWER_DOMAIN_INIT)) +#define CNL_DISPLAY_DDI_F_IO_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_F_IO) | \ + BIT_ULL(POWER_DOMAIN_INIT)) #define CNL_DISPLAY_DC_OFF_POWER_DOMAINS ( \ CNL_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ BIT_ULL(POWER_DOMAIN_GT_IRQ) | \ @@ -2411,6 +2419,12 @@ static struct i915_power_well cnl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_DDI_D, }, + { + .name = "DDI F IO power well", + .domains = CNL_DISPLAY_DDI_F_IO_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = CNL_DISP_PW_DDI_F, + }, { .name = "AUX F", .domains = CNL_DISPLAY_AUX_F_POWER_DOMAINS, @@ -2534,13 +2548,13 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) set_power_wells(power_domains, cnl_power_wells); /* - * Aux IO is getting enabled for all ports + * DDI and Aux IO are getting enabled for all ports * regardless the presence or use. So, in order to avoid - * timeouts, lets remove it from the list + * timeouts, lets remove them from the list * for the SKUs without port F. */ if (!IS_CNL_WITH_PORT_F(dev_priv)) - power_domains->power_well_count -= 1; + power_domains->power_well_count -= 2; } else if (IS_BROXTON(dev_priv)) { set_power_wells(power_domains, bxt_power_wells); From 53ddb3cdb063d7be74aa22ed831cad8aa5ee0863 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 29 Jan 2018 15:22:23 -0800 Subject: [PATCH 116/158] drm/i915/cnl: Fix DP max rate for Cannonlake with port F. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On CNL SKUs that uses port F, max DP rate is 8.1G for all ports when we have the elevated voltage (higher than 0.85V). v2: Make commit message more generic. v3: Move conditions to a helper to get easier to read. (Ville). v4: Add a mention to the numerical voltage on commit message per Manasi request. v5: Thanks CI! "error: control reaches end of non-void function" Cc: Ville Syrjälä Cc: Lucas De Marchi Cc: Manasi Navare Signed-off-by: Rodrigo Vivi Reviewed-by: Manasi Navare Link: https://patchwork.freedesktop.org/patch/msgid/20180129232223.766-10-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9732b022fb50..78cece041ca0 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -218,15 +218,36 @@ intel_dp_downstream_max_dotclock(struct intel_dp *intel_dp) return max_dotclk; } +static int cnl_adjusted_max_rate(struct intel_dp *intel_dp, int size) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum port port = dig_port->base.port; + + u32 voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; + + /* Low voltage SKUs are limited to max of 5.4G */ + if (voltage == VOLTAGE_INFO_0_85V) + return size - 2; + + /* For this SKU 8.1G is supported in all ports */ + if (IS_CNL_WITH_PORT_F(dev_priv)) + return size; + + /* For other SKUs, max rate on ports A and B is 5.4G */ + if (port == PORT_A || port == PORT_D) + return size - 2; + + return size; +} + static void intel_dp_set_source_rates(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum port port = dig_port->base.port; const int *source_rates; int size; - u32 voltage; /* This should only be done once */ WARN_ON(intel_dp->source_rates || intel_dp->num_source_rates); @@ -236,11 +257,7 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) size = ARRAY_SIZE(bxt_rates); } else if (IS_CANNONLAKE(dev_priv)) { source_rates = cnl_rates; - size = ARRAY_SIZE(cnl_rates); - voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; - if (port == PORT_A || port == PORT_D || - voltage == VOLTAGE_INFO_0_85V) - size -= 2; + size = cnl_adjusted_max_rate(intel_dp, ARRAY_SIZE(cnl_rates)); } else if (IS_GEN9_BC(dev_priv)) { source_rates = skl_rates; size = ARRAY_SIZE(skl_rates); From 889230489b6b138ba97ba2f13fc9644a3d16d0d2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Jan 2018 14:41:04 +0000 Subject: [PATCH 117/158] drm/i915: Always run hangcheck while the GPU is busy Previously, we relied on only running the hangcheck while somebody was waiting on the GPU, in order to minimise the amount of time hangcheck had to run. (If nobody was watching the GPU, nobody would notice if the GPU wasn't responding -- eventually somebody would care and so kick hangcheck into action.) However, this falls apart from around commit 4680816be336 ("drm/i915: Wait first for submission, before waiting for request completion"), as not all waiters declare themselves to hangcheck and so we could switch off hangcheck and miss GPU hangs even when waiting under the struct_mutex. If we enable hangcheck from the first request submission, and let it run until the GPU is idle again, we forgo all the complexity involved with only enabling around waiters. We just have to remember to be careful that we do not declare a GPU hang when idly waiting for the next request to be come ready, as we will run hangcheck continuously even when the engines are stalled waiting for external events. This should be true already as we should only be tracking requests submitted to hardware for execution as an indicator that the engine is busy. Fixes: 4680816be336 ("drm/i915: Wait first for submission, before waiting for request completion" Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104840 Signed-off-by: Chris Wilson Cc: Chris Wilson Cc: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180129144104.3921-1-chris@chris-wilson.co.uk Reviewed-by: Mika Kuoppala --- drivers/gpu/drm/i915/i915_gem.c | 7 +++---- drivers/gpu/drm/i915/i915_gem_request.c | 2 ++ drivers/gpu/drm/i915/intel_breadcrumbs.c | 11 ----------- drivers/gpu/drm/i915/intel_hangcheck.c | 7 +------ 4 files changed, 6 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 062b21408698..63308ec016a3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3322,16 +3322,15 @@ i915_gem_retire_work_handler(struct work_struct *work) mutex_unlock(&dev->struct_mutex); } - /* Keep the retire handler running until we are finally idle. + /* + * Keep the retire handler running until we are finally idle. * We do not need to do this test under locking as in the worst-case * we queue the retire worker once too often. */ - if (READ_ONCE(dev_priv->gt.awake)) { - i915_queue_hangcheck(dev_priv); + if (READ_ONCE(dev_priv->gt.awake)) queue_delayed_work(dev_priv->wq, &dev_priv->gt.retire_work, round_jiffies_up_relative(HZ)); - } } static void shrink_caches(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c index 0a890ef4c420..cf2f3895b70e 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.c +++ b/drivers/gpu/drm/i915/i915_gem_request.c @@ -285,6 +285,8 @@ static void mark_busy(struct drm_i915_private *i915) intel_engines_unpark(i915); + i915_queue_hangcheck(i915); + queue_delayed_work(i915->wq, &i915->gt.retire_work, round_jiffies_up_relative(HZ)); diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c index 86acac010bb8..62b2a20bc24e 100644 --- a/drivers/gpu/drm/i915/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c @@ -149,17 +149,6 @@ static void intel_breadcrumbs_fake_irq(struct timer_list *t) return; mod_timer(&b->fake_irq, jiffies + 1); - - /* Ensure that even if the GPU hangs, we get woken up. - * - * However, note that if no one is waiting, we never notice - * a gpu hang. Eventually, we will have to wait for a resource - * held by the GPU and so trigger a hangcheck. In the most - * pathological case, this will be upon memory starvation! To - * prevent this, we also queue the hangcheck from the retire - * worker. - */ - i915_queue_hangcheck(engine->i915); } static void irq_enable(struct intel_engine_cs *engine) diff --git a/drivers/gpu/drm/i915/intel_hangcheck.c b/drivers/gpu/drm/i915/intel_hangcheck.c index 31f01d64c021..348a4f7ffb67 100644 --- a/drivers/gpu/drm/i915/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/intel_hangcheck.c @@ -411,7 +411,6 @@ static void i915_hangcheck_elapsed(struct work_struct *work) struct intel_engine_cs *engine; enum intel_engine_id id; unsigned int hung = 0, stuck = 0; - int busy_count = 0; if (!i915_modparams.enable_hangcheck) return; @@ -429,7 +428,6 @@ static void i915_hangcheck_elapsed(struct work_struct *work) intel_uncore_arm_unclaimed_mmio_detection(dev_priv); for_each_engine(engine, dev_priv, id) { - const bool busy = intel_engine_has_waiter(engine); struct intel_engine_hangcheck hc; semaphore_clear_deadlocks(dev_priv); @@ -443,16 +441,13 @@ static void i915_hangcheck_elapsed(struct work_struct *work) if (hc.action != ENGINE_DEAD) stuck |= intel_engine_flag(engine); } - - busy_count += busy; } if (hung) hangcheck_declare_hang(dev_priv, hung, stuck); /* Reset timer in case GPU hangs without another request being added */ - if (busy_count) - i915_queue_hangcheck(dev_priv); + i915_queue_hangcheck(dev_priv); } void intel_engine_init_hangcheck(struct intel_engine_cs *engine) From b1852d362f31ac0c233e7c7b040f7c58bd381267 Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Wed, 31 Jan 2018 11:44:37 +0530 Subject: [PATCH 118/158] drm/i915/guc: Fix return from guc_log_relay_file_create guc_log_relay_file_create will return -EEXIST if we invoke relay_late_setup_files multiple times as part of i915_guc_log_control. However this is to be not cosidered as fail and need to return 0. This was mistakenly introduced in the below commit. Fix it. Fixes: 70deeaddc6e6 "drm/i915/guc: Fix lockdep due to log relay channel handling under struct_mutex" Signed-off-by: Sagar Arun Kamble Cc: Chris Wilson Cc: Michal Wajdeczko Link: https://patchwork.freedesktop.org/patch/msgid/1517379279-12967-1-git-send-email-sagar.a.kamble@intel.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_guc_log.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 86a33214cbfc..3fbe93ac81dc 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -185,6 +185,8 @@ static int guc_log_relay_file_create(struct intel_guc *guc) goto out_unlock; } + ret = 0; + out_unlock: mutex_unlock(&guc->log.runtime.relay_lock); return ret; From 5b364bec5cbfd6c23505952a40150b053ec551d1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 30 Jan 2018 16:44:57 +0000 Subject: [PATCH 119/158] drm/i915: Flush ggtt writes through the old fenced vma before changing fences This is a precautionary measure as I have no evidence to suggest we've hit a bug here (I was hoping this might explain gdg's odd behaviour, but alas), but given that we have a function to flush the ggtt writes it seems prudent to use it prior to changing the fence register. Due to the intrinsic nature of the GTT often operating as an independent mmio path, we should not just rely on the write to the fence acting as a full flush for GTT writes. Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20180130164457.14037-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_fence_reg.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_fence_reg.c b/drivers/gpu/drm/i915/i915_gem_fence_reg.c index 012250f25255..b8338d75c6f3 100644 --- a/drivers/gpu/drm/i915/i915_gem_fence_reg.c +++ b/drivers/gpu/drm/i915/i915_gem_fence_reg.c @@ -230,10 +230,14 @@ static int fence_update(struct drm_i915_fence_reg *fence, } if (fence->vma) { - ret = i915_gem_active_retire(&fence->vma->last_fence, - &fence->vma->obj->base.dev->struct_mutex); + struct i915_vma *old = fence->vma; + + ret = i915_gem_active_retire(&old->last_fence, + &old->obj->base.dev->struct_mutex); if (ret) return ret; + + i915_vma_flush_writes(old); } if (fence->vma && fence->vma != vma) { From 9a9e3dfd6f8bff68434b9c5e1a3aa88f83a612ad Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Tue, 30 Jan 2018 11:49:10 -0200 Subject: [PATCH 120/158] drm/i915/icl: Don't allocate fixed bypass path blocks for ICL GEN9 onwards bypass path allocation of 4 blocks was needed, as per hardware design. ICL doesn't require bypass path allocation of 4 DDB blocks, handling the same in this patch. v2 (from Paulo): - No need for a comment that says what the code already says. Reviewed-by: Paulo Zanoni Reviewed-by: James Ausmus Signed-off-by: Mahesh Kumar Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180130134918.32283-2-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0b92ea1dbd40..11aac65d1543 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3778,7 +3778,8 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev, ddb_size = INTEL_INFO(dev_priv)->ddb_size; WARN_ON(ddb_size == 0); - ddb_size -= 4; /* 4 blocks for bypass path allocation */ + if (INTEL_GEN(dev_priv) < 11) + ddb_size -= 4; /* 4 blocks for bypass path allocation */ /* * If the state doesn't change the active CRTC's, then there's From df8ee19087d24ca00c4f76b3a28c793b661b4b1e Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Tue, 30 Jan 2018 11:49:11 -0200 Subject: [PATCH 121/158] drm/i915/icl: Do not fix dbuf block size to 512 GEN9/10 had fixed DBuf block size of 512. Dbuf block size is not a fixed number anymore in GEN11, it varies according to bits per pixel and tiling. If 8bpp & Yf-tile surface, block size = 256 else block size = 512 This patch addresses the same. v2 (from Paulo): - Make it compile. - Fix a few coding style issues. v3: - Rebase on top of upstream patches v4 (from Paulo): - Bikeshed if statements (James). Reviewed-by: Paulo Zanoni Reviewed-by: James Ausmus Signed-off-by: Mahesh Kumar Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180130134918.32283-3-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2d855faac708..21403be6ee0c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1461,6 +1461,7 @@ struct skl_wm_params { uint_fixed_16_16_t plane_blocks_per_line; uint_fixed_16_16_t y_tile_minimum; uint32_t linetime_us; + uint32_t dbuf_block_size; }; /* diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 11aac65d1543..985642cf1c9a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4312,7 +4312,7 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, */ static uint_fixed_16_16_t skl_wm_method1(const struct drm_i915_private *dev_priv, uint32_t pixel_rate, - uint8_t cpp, uint32_t latency) + uint8_t cpp, uint32_t latency, uint32_t dbuf_block_size) { uint32_t wm_intermediate_val; uint_fixed_16_16_t ret; @@ -4321,7 +4321,7 @@ skl_wm_method1(const struct drm_i915_private *dev_priv, uint32_t pixel_rate, return FP_16_16_MAX; wm_intermediate_val = latency * pixel_rate * cpp; - ret = div_fixed16(wm_intermediate_val, 1000 * 512); + ret = div_fixed16(wm_intermediate_val, 1000 * dbuf_block_size); if (INTEL_GEN(dev_priv) >= 10) ret = add_fixed16_u32(ret, 1); @@ -4431,6 +4431,12 @@ skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv, wp->plane_pixel_rate = skl_adjusted_plane_pixel_rate(cstate, intel_pstate); + if (INTEL_GEN(dev_priv) >= 11 && + fb->modifier == I915_FORMAT_MOD_Yf_TILED && wp->cpp == 8) + wp->dbuf_block_size = 256; + else + wp->dbuf_block_size = 512; + if (drm_rotation_90_or_270(pstate->rotation)) { switch (wp->cpp) { @@ -4457,7 +4463,8 @@ skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv, wp->plane_bytes_per_line = wp->width * wp->cpp; if (wp->y_tiled) { interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line * - wp->y_min_scanlines, 512); + wp->y_min_scanlines, + wp->dbuf_block_size); if (INTEL_GEN(dev_priv) >= 10) interm_pbpl++; @@ -4465,10 +4472,12 @@ skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv, wp->plane_blocks_per_line = div_fixed16(interm_pbpl, wp->y_min_scanlines); } else if (wp->x_tiled && IS_GEN9(dev_priv)) { - interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line, 512); + interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line, + wp->dbuf_block_size); wp->plane_blocks_per_line = u32_to_fixed16(interm_pbpl); } else { - interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line, 512) + 1; + interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line, + wp->dbuf_block_size) + 1; wp->plane_blocks_per_line = u32_to_fixed16(interm_pbpl); } @@ -4515,7 +4524,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, latency += 15; method1 = skl_wm_method1(dev_priv, wp->plane_pixel_rate, - wp->cpp, latency); + wp->cpp, latency, wp->dbuf_block_size); method2 = skl_wm_method2(wp->plane_pixel_rate, cstate->base.adjusted_mode.crtc_htotal, latency, @@ -4525,7 +4534,8 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, selected_result = max_fixed16(method2, wp->y_tile_minimum); } else { if ((wp->cpp * cstate->base.adjusted_mode.crtc_htotal / - 512 < 1) && (wp->plane_bytes_per_line / 512 < 1)) + wp->dbuf_block_size < 1) && + (wp->plane_bytes_per_line / wp->dbuf_block_size < 1)) selected_result = method2; else if (ddb_allocation >= fixed16_to_u32_round_up(wp->plane_blocks_per_line)) From 5b695aff3af5606c4128eba6a64c33c7d74d4f49 Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Tue, 30 Jan 2018 11:49:12 -0200 Subject: [PATCH 122/158] drm/i915/icl: Fail flip if ddb allocated are less than min display buffer needed ICL require DDB allocation of plane to be more than "minimum display buffer needed" for each level in order to enable WM level. This patch implements and consider the same while allocating DDB and enabling WM. Changes Since V1: - rebase Changes Since V2: - Remove extra parentheses - Use FP16.16 only when absolutely necessary (Paulo) Changes Since V3: - Rebase Changes since v4 (from Paulo): - Coding style issue. Changes since v5 (from Paulo): - Do the final checks according to BSpec. Reviewed-by: Paulo Zanoni Signed-off-by: Mahesh Kumar Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180130134918.32283-4-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_pm.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 985642cf1c9a..24421603e605 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4507,6 +4507,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, struct intel_atomic_state *state = to_intel_atomic_state(cstate->base.state); bool apply_memory_bw_wa = skl_needs_memory_bw_wa(state); + uint32_t min_disp_buf_needed; if (latency == 0 || !intel_wm_plane_visible(cstate, intel_pstate)) { @@ -4565,7 +4566,31 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, } } - if (res_blocks >= ddb_allocation || res_lines > 31) { + if (INTEL_GEN(dev_priv) >= 11) { + if (wp->y_tiled) { + uint32_t extra_lines; + uint_fixed_16_16_t fp_min_disp_buf_needed; + + if (res_lines % wp->y_min_scanlines == 0) + extra_lines = wp->y_min_scanlines; + else + extra_lines = wp->y_min_scanlines * 2 - + res_lines % wp->y_min_scanlines; + + fp_min_disp_buf_needed = mul_u32_fixed16(res_lines + + extra_lines, + wp->plane_blocks_per_line); + min_disp_buf_needed = fixed16_to_u32_round_up( + fp_min_disp_buf_needed); + } else { + min_disp_buf_needed = DIV_ROUND_UP(res_blocks * 11, 10); + } + } else { + min_disp_buf_needed = res_blocks; + } + + if (res_blocks >= ddb_allocation || res_lines > 31 || + min_disp_buf_needed >= ddb_allocation) { *enabled = false; /* From 234059da0f336fff315746ea34d4cf04a36d7c01 Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Tue, 30 Jan 2018 11:49:13 -0200 Subject: [PATCH 123/158] drm/i915/icl: NV12 y-plane ddb is not in same plane We don't have planar pixel format support implemented for ICL yet. ICL require 2 display planes to be allocated for Planar formats unlike previous GEN. So ICL/GEN11 doesn't require to write Y-plane ddb data in NV12_BUF_CFG register and PLANE_NV12_BUF_CFG register is removed in ICL. This patch removes the PLANE_NV12_BUF_CFG write for ICL. Changes Since V1: - Improve commit message as per Paulo's comment Reviewed-by: Paulo Zanoni Reviewed-by: James Ausmus Signed-off-by: Mahesh Kumar Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180130134918.32283-5-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_pm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 24421603e605..766f4fdd633b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4826,8 +4826,10 @@ static void skl_write_plane_wm(struct intel_crtc *intel_crtc, skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id), &ddb->plane[pipe][plane_id]); - skl_ddb_entry_write(dev_priv, PLANE_NV12_BUF_CFG(pipe, plane_id), - &ddb->y_plane[pipe][plane_id]); + if (INTEL_GEN(dev_priv) < 11) + skl_ddb_entry_write(dev_priv, + PLANE_NV12_BUF_CFG(pipe, plane_id), + &ddb->y_plane[pipe][plane_id]); } static void skl_write_cursor_wm(struct intel_crtc *intel_crtc, From 7800549716f48ea585be9694633ec02bbc8c32a3 Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Tue, 30 Jan 2018 11:49:14 -0200 Subject: [PATCH 124/158] drm/i915/icl: Introduce MBus related registers This patch introduce MBus control registers and their bit-fields MBUS_ABOX_CTL MBUS_BBOX_CTL MBUS_DBOX_CTL MBUS_UBOX_CTL Changes Since V1: - Use function like macros (Paulo) - fix copy-paste error (Paulo) Reviewed-by: Paulo Zanoni Reviewed-by: James Ausmus Signed-off-by: Mahesh Kumar Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180130134918.32283-6-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index cf286980dacc..54468b9c4dc5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2650,6 +2650,31 @@ enum i915_power_well_id { #define LM_FIFO_WATERMARK 0x0000001F #define MI_ARB_STATE _MMIO(0x20e4) /* 915+ only */ +#define MBUS_ABOX_CTL _MMIO(0x45038) +#define MBUS_ABOX_BW_CREDIT_MASK (3 << 20) +#define MBUS_ABOX_BW_CREDIT(x) ((x) << 20) +#define MBUS_ABOX_B_CREDIT_MASK (0xF << 16) +#define MBUS_ABOX_B_CREDIT(x) ((x) << 16) +#define MBUS_ABOX_BT_CREDIT_POOL2_MASK (0x1F << 8) +#define MBUS_ABOX_BT_CREDIT_POOL2(x) ((x) << 8) +#define MBUS_ABOX_BT_CREDIT_POOL1_MASK (0x1F << 0) +#define MBUS_ABOX_BT_CREDIT_POOL1(x) ((x) << 0) + +#define _PIPEA_MBUS_DBOX_CTL 0x7003C +#define _PIPEB_MBUS_DBOX_CTL 0x7103C +#define PIPE_MBUS_DBOX_CTL(pipe) _MMIO_PIPE(pipe, _PIPEA_MBUS_DBOX_CTL, \ + _PIPEB_MBUS_DBOX_CTL) +#define MBUS_DBOX_BW_CREDIT_MASK (3 << 14) +#define MBUS_DBOX_BW_CREDIT(x) ((x) << 14) +#define MBUS_DBOX_B_CREDIT_MASK (0x1F << 8) +#define MBUS_DBOX_B_CREDIT(x) ((x) << 8) +#define MBUS_DBOX_A_CREDIT_MASK (0xF << 0) +#define MBUS_DBOX_A_CREDIT(x) ((x) << 0) + +#define MBUS_UBOX_CTL _MMIO(0x4503C) +#define MBUS_BBOX_CTL_S1 _MMIO(0x45040) +#define MBUS_BBOX_CTL_S2 _MMIO(0x45044) + /* Make render/texture TLB fetches lower priorty than associated data * fetches. This is not turned on by default */ From 4357ce07e6bff1809f25eaae485fac4989296816 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 30 Jan 2018 11:49:15 -0200 Subject: [PATCH 125/158] drm/i915/gen11: fix the SAGV block time for gen11 It's 10us for gen 11. Reviewed-by: Mahesh Kumar Reviewed-by: James Ausmus Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180130134918.32283-7-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_pm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 766f4fdd633b..6dc4677e6c3f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3694,11 +3694,18 @@ bool intel_can_enable_sagv(struct drm_atomic_state *state) struct intel_crtc_state *cstate; enum pipe pipe; int level, latency; - int sagv_block_time_us = IS_GEN9(dev_priv) ? 30 : 20; + int sagv_block_time_us; if (!intel_has_sagv(dev_priv)) return false; + if (IS_GEN9(dev_priv)) + sagv_block_time_us = 30; + else if (IS_GEN10(dev_priv)) + sagv_block_time_us = 20; + else + sagv_block_time_us = 10; + /* * SKL+ workaround: bspec recommends we disable the SAGV when we have * more then one pipe enabled From b597277643fef8f2eab35a6c812b6f98094a0de1 Mon Sep 17 00:00:00 2001 From: James Ausmus Date: Tue, 30 Jan 2018 11:49:16 -0200 Subject: [PATCH 126/158] drm/i915/icl: Handle expanded PLANE_CTL_FORMAT field ICL+ adds changes the PLANE_CTL_FORMAT field from [27:24] to [27:23], however, all existing PLANE_CTL_FORMAT_* definitions still map to the correct values. Add an ICL_PLANE_CTL_FORMAT_MASK definition, and use that for masking for the conversion to fourcc. v2: No changes v3: Change new definition name, drop comment (Rodrigo) Cc: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: James Ausmus Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180130134918.32283-8-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 6 ++++++ drivers/gpu/drm/i915/intel_display.c | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 54468b9c4dc5..82815b69dfbf 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6349,6 +6349,11 @@ enum { #define _PLANE_CTL_3_A 0x70380 #define PLANE_CTL_ENABLE (1 << 31) #define PLANE_CTL_PIPE_GAMMA_ENABLE (1 << 30) /* Pre-GLK */ +/* + * ICL+ uses the same PLANE_CTL_FORMAT bits, but the field definition + * expanded to include bit 23 as well. However, the shift-24 based values + * correctly map to the same formats in ICL, as long as bit 23 is set to 0 + */ #define PLANE_CTL_FORMAT_MASK (0xf << 24) #define PLANE_CTL_FORMAT_YUV422 ( 0 << 24) #define PLANE_CTL_FORMAT_NV12 ( 1 << 24) @@ -6358,6 +6363,7 @@ enum { #define PLANE_CTL_FORMAT_AYUV ( 8 << 24) #define PLANE_CTL_FORMAT_INDEXED ( 12 << 24) #define PLANE_CTL_FORMAT_RGB_565 ( 14 << 24) +#define ICL_PLANE_CTL_FORMAT_MASK (0x1f << 23) #define PLANE_CTL_PIPE_CSC_ENABLE (1 << 23) /* Pre-GLK */ #define PLANE_CTL_KEY_ENABLE_MASK (0x3 << 21) #define PLANE_CTL_KEY_ENABLE_SOURCE ( 1 << 21) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 217badde15fa..e79b9242eb66 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8527,7 +8527,10 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc, val = I915_READ(PLANE_CTL(pipe, plane_id)); - pixel_format = val & PLANE_CTL_FORMAT_MASK; + if (INTEL_GEN(dev_priv) >= 11) + pixel_format = val & ICL_PLANE_CTL_FORMAT_MASK; + else + pixel_format = val & PLANE_CTL_FORMAT_MASK; if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { alpha = I915_READ(PLANE_COLOR_CTL(pipe, plane_id)); From 225701fc20ef9c0219a1119a9495c39c30797a4b Mon Sep 17 00:00:00 2001 From: Kelvin Gardiner Date: Tue, 30 Jan 2018 11:49:17 -0200 Subject: [PATCH 127/158] drm/i915/icl: Set graphics mode register for gen11 This patch clears a single bit. The bit is 0 by default but expected not to be set. Explicitly clearing the bit in this patch is intended to indicate some thinking has occurred, and that we want this bit cleared and we are not just excepting the default value. We also stop setting GFX_RUN_LIST_ENABLE, which is correct since that bit is gone. v2 (from Paulo): fix indentation. v3: Changed GEN check to >= 11. Corrected author name. v4 (from Paulo): improve commit message (Daniele). Reviewed-by: Daniele Ceraolo Spurio Signed-off-by: Kelvin Gardiner Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180130134918.32283-9-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_lrc.c | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 82815b69dfbf..1489dd3b3ec2 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2592,6 +2592,8 @@ enum i915_power_well_id { #define GFX_FORWARD_VBLANK_ALWAYS (1<<5) #define GFX_FORWARD_VBLANK_COND (2<<5) +#define GEN11_GFX_DISABLE_LEGACY_MODE (1<<3) + #define VLV_DISPLAY_BASE 0x180000 #define VLV_MIPI_BASE VLV_DISPLAY_BASE #define BXT_MIPI_BASE 0x60000 diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 2fa328d512fc..40dbeaee9dfa 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1443,8 +1443,22 @@ static void enable_execlists(struct intel_engine_cs *engine) struct drm_i915_private *dev_priv = engine->i915; I915_WRITE(RING_HWSTAM(engine->mmio_base), 0xffffffff); - I915_WRITE(RING_MODE_GEN7(engine), - _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); + + /* + * Make sure we're not enabling the new 12-deep CSB + * FIFO as that requires a slightly updated handling + * in the ctx switch irq. Since we're currently only + * using only 2 elements of the enhanced execlists the + * deeper FIFO it's not needed and it's not worth adding + * more statements to the irq handler to support it. + */ + if (INTEL_GEN(dev_priv) >= 11) + I915_WRITE(RING_MODE_GEN7(engine), + _MASKED_BIT_DISABLE(GEN11_GFX_DISABLE_LEGACY_MODE)); + else + I915_WRITE(RING_MODE_GEN7(engine), + _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); + I915_WRITE(RING_HWS_PGA(engine->mmio_base), engine->status_page.ggtt_offset); POSTING_READ(RING_HWS_PGA(engine->mmio_base)); From 164daaf23c97d949ff6642584c1770b1f9b8974a Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 30 Jan 2018 11:49:18 -0200 Subject: [PATCH 128/158] drm/i915/icl: allow the reg_read ioctl to read the RCS TIMESTAMP register This enables the Mesa driver to advertise support for ARB_timer_query, and thus an OpenGL version higher than 3.2. Based on the CNL patch by Nanley Chery. v2: Rebase. Cc: Anuj Phogat Cc: Nanley Chery Cc: Rodrigo Vivi Requested-by: Anuj Phogat Tested-by: Anuj Phogat Reviewed-by: Rodrigo Vivi Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180130134918.32283-10-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_uncore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 94e1fb3a2936..4075010ac088 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1452,7 +1452,7 @@ static const struct reg_whitelist { } reg_read_whitelist[] = { { .offset_ldw = RING_TIMESTAMP(RENDER_RING_BASE), .offset_udw = RING_TIMESTAMP_UDW(RENDER_RING_BASE), - .gen_mask = INTEL_GEN_MASK(4, 10), + .gen_mask = INTEL_GEN_MASK(4, 11), .size = 8 } }; From b715a2f0c7714a399e7f8e951cc8dea9cd4eeb4b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 31 Jan 2018 21:44:39 +0000 Subject: [PATCH 129/158] drm/i915/ppgtt: Pin page directories before allocation Commit e2b763caa6eb ("drm/i915: Remove bitmap tracking for used-pdpes") believed that because it did not insert its freshly allocated page directory into the pd tree, it was safe from the shrinker. I failed to heed the lesson learnt from commit dd19674bacba ("drm/i915: Remove bitmap tracking for used-ptes") that we need to pin all the levels in the tree before hitting the shrinker or else the shrinker may free an upper layer as we proceed to allocate the tree. Thus leaving dangling pointers everywhere and a GPF should we hit direct reclaim at just the wrong moment. CPU: 0 PID: 7374 Comm: chromium Tainted: P O 4.14.13-1-ARCH #1 Hardware name: Apple Inc. MacBookPro12,1/Mac-E43C1C25D4880AD6, BIOS MBP121.88Z.0167.B33.1706181928 06/18/2017 task: ffff994f696c2c40 task.stack: ffffb1a789d4c000 RIP: 0010:gen8_ppgtt_set_pde.isra.40+0x48/0x70 [i915] RSP: 0018:ffffb1a789d4f940 EFLAGS: 00010206 RAX: 81c1788cc4f68138 RBX: ffff994f54db8000 RCX: ffff994f696c2c40 RDX: 000000023bc73003 RSI: ffff994d598b6b80 RDI: ffff994f54db8000 RBP: ffff994d598b6b80 R08: 0000000000000000 R09: 0000000000000000 R10: ffffb1a789d4f550 R11: ffff994eaf3c3208 R12: 0000000000000027 R13: 0000000000005000 R14: 0000000004e8f000 R15: ffff994f54dba000 FS: 00007f585886aa00(0000) GS:ffff994faec00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000004ac8e8 CR3: 00000002552c8004 CR4: 00000000003606f0 Call Trace: gen8_ppgtt_alloc_pdp+0x178/0x320 [i915] gen8_ppgtt_alloc_4lvl+0x5f/0x150 [i915] ppgtt_bind_vma+0x30/0x70 [i915] i915_vma_bind+0x68/0xd0 [i915] __i915_vma_do_pin+0x2d6/0x3a0 [i915] eb_lookup_vmas+0x7a2/0xb50 [i915] i915_gem_do_execbuffer+0x4d7/0x10e0 [i915] ? sock_wfree+0x34/0x60 ? unix_stream_read_generic+0x1f9/0x7e0 ? import_iovec+0x37/0xd0 ? i915_gem_execbuffer2+0x5d/0x390 [i915] i915_gem_execbuffer2+0x1b7/0x390 [i915] ? i915_gem_execbuffer+0x2d0/0x2d0 [i915] drm_ioctl_kernel+0x59/0xb0 [drm] drm_ioctl+0x2d5/0x370 [drm] ? i915_gem_execbuffer+0x2d0/0x2d0 [i915] ? __seccomp_filter+0x3b/0x260 do_vfs_ioctl+0xa1/0x610 ? syscall_trace_enter+0xdb/0x2b0 SyS_ioctl+0x74/0x80 do_syscall_64+0x55/0x110 entry_SYSCALL64_slow_path+0x25/0x25 RIP: 0033:0x7f584fa82d27 RSP: 002b:00007ffee14a7828 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 000003b0126a1030 RCX: 00007f584fa82d27 RDX: 00007ffee14a7870 RSI: 0000000040406469 RDI: 0000000000000080 RBP: 00007ffee14a7870 R08: 0000000000000002 R09: 0000000000000077 R10: 00007f5839f2b780 R11: 0000000000000246 R12: 0000000040406469 R13: 0000000000000080 R14: 00007f5842b00040 R15: 0000000000000000 Code: 01 00 83 81 58 0a 00 00 01 48 2b 05 13 9d fd c9 48 c1 f8 06 48 c1 e0 0c 48 8d 04 d0 48 8b 56 08 48 03 05 0c 9d fd c9 48 83 ca 03 <48> 89 10 83 a9 58 0a 00 00 01 65 ff 0d 37 03 fb 3e 74 02 f3 c3 RIP: gen8_ppgtt_set_pde.isra.40+0x48/0x70 [i915] RSP: ffffb1a789d4f940 Reported-by: Eric Blau Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104773 Fixes: e2b763caa6eb ("drm/i915: Remove bitmap tracking for used-pdpes") References: dd19674bacba ("drm/i915: Remove bitmap tracking for used-ptes") Testcase: igt/drv_selftest/live_gtt (igt_ppgtt_shrink_boom) Signed-off-by: Chris Wilson Cc: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20180131214440.7141-1-chris@chris-wilson.co.uk Reviewed-by: Matthew Auld --- drivers/gpu/drm/i915/i915_gem_gtt.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b65426c0457d..955ce7bee448 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1356,15 +1356,18 @@ static int gen8_ppgtt_alloc_pd(struct i915_address_space *vm, int count = gen8_pte_count(start, length); if (pt == vm->scratch_pt) { + pd->used_pdes++; + pt = alloc_pt(vm); - if (IS_ERR(pt)) + if (IS_ERR(pt)) { + pd->used_pdes--; goto unwind; + } if (count < GEN8_PTES || intel_vgpu_active(vm->i915)) gen8_initialize_pt(vm, pt); gen8_ppgtt_set_pde(vm, pd, pt, pde); - pd->used_pdes++; GEM_BUG_ON(pd->used_pdes > I915_PDES); } @@ -1388,13 +1391,16 @@ static int gen8_ppgtt_alloc_pdp(struct i915_address_space *vm, gen8_for_each_pdpe(pd, pdp, start, length, pdpe) { if (pd == vm->scratch_pd) { + pdp->used_pdpes++; + pd = alloc_pd(vm); - if (IS_ERR(pd)) + if (IS_ERR(pd)) { + pdp->used_pdpes--; goto unwind; + } gen8_initialize_pd(vm, pd); gen8_ppgtt_set_pdpe(vm, pdp, pd, pdpe); - pdp->used_pdpes++; GEM_BUG_ON(pdp->used_pdpes > i915_pdpes_per_pdp(vm)); mark_tlbs_dirty(i915_vm_to_ppgtt(vm)); From fe215c8bc42695621bbeee92ed5ebe7c5a2f4f86 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Wed, 31 Jan 2018 21:44:40 +0000 Subject: [PATCH 130/158] drm/i915/selftests: add missing gtt shrinker test Try to catch a bug we've seen in the wild where the shrinker purges the pd/pdp from under us while allocating our paging structures. References: https://bugs.freedesktop.org/show_bug.cgi?id=104773 Signed-off-by: Matthew Auld Cc: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180131191453.12676-1-matthew.auld@intel.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180131214440.7141-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index bb7cf998fc65..d8064276431c 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -885,6 +885,84 @@ static int shrink_hole(struct drm_i915_private *i915, return err; } +static int shrink_boom(struct drm_i915_private *i915, + struct i915_address_space *vm, + u64 hole_start, u64 hole_end, + unsigned long end_time) +{ + unsigned int sizes[] = { SZ_2M, SZ_1G }; + struct drm_i915_gem_object *purge; + struct drm_i915_gem_object *explode; + int err; + int i; + + /* + * Catch the case which shrink_hole seems to miss. The setup here + * requires invoking the shrinker as we do the alloc_pt/alloc_pd, while + * ensuring that all vma assiocated with the respective pd/pdp are + * unpinned at the time. + */ + + for (i = 0; i < ARRAY_SIZE(sizes); ++i) { + unsigned int flags = PIN_USER | PIN_OFFSET_FIXED; + unsigned int size = sizes[i]; + struct i915_vma *vma; + + purge = fake_dma_object(i915, size); + if (IS_ERR(purge)) + return PTR_ERR(purge); + + vma = i915_vma_instance(purge, vm, NULL); + if (IS_ERR(vma)) { + err = PTR_ERR(vma); + goto err_purge; + } + + err = i915_vma_pin(vma, 0, 0, flags); + if (err) + goto err_purge; + + /* Should now be ripe for purging */ + i915_vma_unpin(vma); + + explode = fake_dma_object(i915, size); + if (IS_ERR(explode)) { + err = PTR_ERR(purge); + goto err_purge; + } + + vm->fault_attr.probability = 100; + vm->fault_attr.interval = 1; + atomic_set(&vm->fault_attr.times, -1); + + vma = i915_vma_instance(explode, vm, NULL); + if (IS_ERR(vma)) { + err = PTR_ERR(vma); + goto err_explode; + } + + err = i915_vma_pin(vma, 0, 0, flags | size); + if (err) + goto err_explode; + + i915_vma_unpin(vma); + + i915_gem_object_put(purge); + i915_gem_object_put(explode); + + memset(&vm->fault_attr, 0, sizeof(vm->fault_attr)); + } + + return 0; + +err_explode: + i915_gem_object_put(explode); +err_purge: + i915_gem_object_put(purge); + memset(&vm->fault_attr, 0, sizeof(vm->fault_attr)); + return err; +} + static int exercise_ppgtt(struct drm_i915_private *dev_priv, int (*func)(struct drm_i915_private *i915, struct i915_address_space *vm, @@ -953,6 +1031,11 @@ static int igt_ppgtt_shrink(void *arg) return exercise_ppgtt(arg, shrink_hole); } +static int igt_ppgtt_shrink_boom(void *arg) +{ + return exercise_ppgtt(arg, shrink_boom); +} + static int sort_holes(void *priv, struct list_head *A, struct list_head *B) { struct drm_mm_node *a = list_entry(A, typeof(*a), hole_stack); @@ -1577,6 +1660,7 @@ int i915_gem_gtt_live_selftests(struct drm_i915_private *i915) SUBTEST(igt_ppgtt_pot), SUBTEST(igt_ppgtt_fill), SUBTEST(igt_ppgtt_shrink), + SUBTEST(igt_ppgtt_shrink_boom), SUBTEST(igt_ggtt_lowlevel), SUBTEST(igt_ggtt_drunk), SUBTEST(igt_ggtt_walk), From bf67ce62a0758f6001355530a47cd37d3dca3de6 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Wed, 31 Jan 2018 17:32:37 +0000 Subject: [PATCH 131/158] drm/i915/guc: Don't forget to free GuC error log We're freeing GuC error log in uc_fini_hw() that matches corresponding uc_init_hw() but we missed the point that this log object is copied on error path and in case of failure in uc_init_hw() we will leak this object as uc_fini_hw() is never called. If we free this log object as part of the late uC cleanup, where we also release other firmware objects, we can avoid this BUG: [70841.001413] BUG drm_i915_gem_object (Tainted: G U W ): Objects remaining in drm_i915_gem_object on __kmem_cache_shutdown() [70841.001436] INFO: Slab 0x00000000c94e41af objects=21 used=1 fp=0x000000001d60c40a flags=0x8000000000008100 [70841.001466] Call Trace: [70841.001471] dump_stack+0x5e/0x8e [70841.001476] slab_err+0x99/0xb0 [70841.001483] ? __slab_alloc.isra.24.constprop.29+0x62/0x70 [70841.001491] ? __kmalloc+0x1f5/0x320 [70841.001497] __kmem_cache_shutdown+0x18b/0x400 [70841.001505] shutdown_cache+0x13/0x1c0 [70841.001511] kmem_cache_destroy+0x1c2/0x240 [70841.001517] ? __mutex_unlock_slowpath+0x38/0x270 [70841.001559] i915_gem_load_cleanup+0xbc/0x130 [i915] [70841.001595] i915_driver_cleanup_early+0x11/0x60 [i915] [70841.001630] i915_driver_load+0x708/0x1720 [i915] [70841.001638] ? trace_hardirqs_on_caller+0xe2/0x1c0 [70841.001673] i915_pci_probe+0x2d/0x90 [i915] [70841.001680] pci_device_probe+0x9c/0x120 [70841.001687] driver_probe_device+0x2a9/0x490 [70841.001694] __driver_attach+0xd9/0xe0 [70841.001700] ? driver_probe_device+0x490/0x490 [70841.001705] bus_for_each_dev+0x57/0x90 [70841.001712] bus_add_driver+0x1eb/0x260 [70841.001717] ? 0xffffffffa0685000 [70841.001723] driver_register+0x52/0xc0 [70841.001728] ? 0xffffffffa0685000 [70841.001733] do_one_initcall+0x39/0x170 [70841.001739] ? rcu_read_lock_sched_held+0x6f/0x80 [70841.001746] ? kmem_cache_alloc_trace+0x27b/0x2e0 [70841.001753] do_init_module+0x56/0x1ec [70841.001759] load_module+0x219e/0x2550 [70841.001766] ? vfs_read+0x121/0x140 [70841.001774] ? SyS_finit_module+0xa5/0xe0 [70841.001779] SyS_finit_module+0xa5/0xe0 [70841.001788] entry_SYSCALL_64_fastpath+0x22/0x8f [70841.001806] INFO: Object 0x00000000eab7ed96 @offset=6208 [70841.001850] INFO: Allocated in i915_gem_object_create.part.32+0x1f/0x260 [i915] age=38 cpu=0 pid=2708 [70841.001861] kmem_cache_alloc+0x23d/0x2d0 [70841.001897] i915_gem_object_create.part.32+0x1f/0x260 [i915] [70841.001937] intel_guc_allocate_vma+0x15/0x100 [i915] [70841.001977] intel_guc_log_create+0x34/0x1c0 [i915] [70841.002014] intel_guc_init+0x5a/0x100 [i915] [70841.002051] intel_uc_init+0x3e/0xb0 [i915] [70841.002089] i915_gem_init+0x18e/0x540 [i915] [70841.002123] i915_driver_load+0xa7a/0x1720 [i915] [70841.002159] i915_pci_probe+0x2d/0x90 [i915] [70841.002165] pci_device_probe+0x9c/0x120 [70841.002171] driver_probe_device+0x2a9/0x490 [70841.002177] __driver_attach+0xd9/0xe0 [70841.002182] bus_for_each_dev+0x57/0x90 [70841.002188] bus_add_driver+0x1eb/0x260 [70841.002193] driver_register+0x52/0xc0 [70841.002198] do_one_initcall+0x39/0x170 [70841.002462] kmem_cache_destroy drm_i915_gem_object: Slab cache still has objects [70841.002491] Call Trace: [70841.002497] dump_stack+0x5e/0x8e [70841.002503] kmem_cache_destroy+0x1e0/0x240 [70841.002509] ? __mutex_unlock_slowpath+0x38/0x270 [70841.002551] i915_gem_load_cleanup+0xbc/0x130 [i915] [70841.002586] i915_driver_cleanup_early+0x11/0x60 [i915] [70841.002621] i915_driver_load+0x708/0x1720 [i915] [70841.002629] ? trace_hardirqs_on_caller+0xe2/0x1c0 [70841.002664] i915_pci_probe+0x2d/0x90 [i915] [70841.002671] pci_device_probe+0x9c/0x120 [70841.002678] driver_probe_device+0x2a9/0x490 [70841.002684] __driver_attach+0xd9/0xe0 [70841.002690] ? driver_probe_device+0x490/0x490 [70841.002696] bus_for_each_dev+0x57/0x90 [70841.002702] bus_add_driver+0x1eb/0x260 [70841.002708] ? 0xffffffffa0685000 [70841.002713] driver_register+0x52/0xc0 [70841.002719] ? 0xffffffffa0685000 [70841.002724] do_one_initcall+0x39/0x170 [70841.002731] ? rcu_read_lock_sched_held+0x6f/0x80 [70841.002737] ? kmem_cache_alloc_trace+0x27b/0x2e0 [70841.002745] do_init_module+0x56/0x1ec [70841.002751] load_module+0x219e/0x2550 [70841.002758] ? vfs_read+0x121/0x140 [70841.002766] ? SyS_finit_module+0xa5/0xe0 [70841.002772] SyS_finit_module+0xa5/0xe0 [70841.002781] entry_SYSCALL_64_fastpath+0x22/0x8f Signed-off-by: Michal Wajdeczko Cc: Chris Wilson Cc: Sagar Arun Kamble Cc: Michal Winiarski Cc: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20180131173241.19704-2-michal.wajdeczko@intel.com Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_uc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index e3f3509d6692..9f1bac6398fb 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -27,6 +27,8 @@ #include "intel_guc.h" #include "i915_drv.h" +static void guc_free_load_err_log(struct intel_guc *guc); + /* Reset GuC providing us with fresh state for both GuC and HuC. */ static int __intel_uc_reset_hw(struct drm_i915_private *dev_priv) @@ -183,6 +185,8 @@ void intel_uc_fini_fw(struct drm_i915_private *dev_priv) if (USES_HUC(dev_priv)) intel_uc_fw_fini(&dev_priv->huc.fw); + + guc_free_load_err_log(&dev_priv->guc); } /** @@ -428,8 +432,6 @@ void intel_uc_fini_hw(struct drm_i915_private *dev_priv) { struct intel_guc *guc = &dev_priv->guc; - guc_free_load_err_log(guc); - if (!USES_GUC(dev_priv)) return; From 28647b52ec0e20f84eb1b5e13095134e2b371759 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Wed, 31 Jan 2018 17:32:39 +0000 Subject: [PATCH 132/158] drm/i915/guc: Don't try to create log runtime if there is no log In case of GuC initialization failure we may continue with driver load, but we wrongly assume that GuC is fully functional. This leads to the BUG as we attempt to access non-existing log vma. [26386.121085] BUG: unable to handle kernel NULL pointer dereference at 00000000000000a0 [26386.121225] IP: guc_log_runtime_create+0x23/0xe0 [i915] [26386.121763] Call Trace: [26386.121870] guc_log_late_setup+0xfd/0x140 [i915] [26386.121969] i915_driver_load+0x7ab/0x1730 [i915] [26386.122069] i915_pci_probe+0x2d/0x90 [i915] [26386.122089] pci_device_probe+0x9c/0x120 [26386.122107] driver_probe_device+0x2a9/0x490 [26386.122126] __driver_attach+0xd9/0xe0 [26386.122143] ? driver_probe_device+0x490/0x490 [26386.122158] bus_for_each_dev+0x57/0x90 [26386.122175] bus_add_driver+0x1eb/0x260 [26386.122190] ? 0xffffffffa069a000 [26386.122206] driver_register+0x52/0xc0 [26386.122220] ? 0xffffffffa069a000 [26386.122234] do_one_initcall+0x39/0x170 [26386.122252] ? kmem_cache_alloc_trace+0x1fd/0x2e0 [26386.122273] do_init_module+0x56/0x1ec [26386.122289] load_module+0x219e/0x2550 [26386.122309] ? vfs_read+0x121/0x140 [26386.122331] ? SyS_finit_module+0xa5/0xe0 [26386.122346] SyS_finit_module+0xa5/0xe0 [26386.122371] entry_SYSCALL_64_fastpath+0x22/0x8f Signed-off-by: Michal Wajdeczko Cc: Chris Wilson Cc: Michal Winiarski Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Link: https://patchwork.freedesktop.org/patch/msgid/20180131173241.19704-4-michal.wajdeczko@intel.com Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_guc_log.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 3fbe93ac81dc..7b5074e2120c 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -397,6 +397,9 @@ static int guc_log_runtime_create(struct intel_guc *guc) lockdep_assert_held(&dev_priv->drm.struct_mutex); + if (!guc->log.vma) + return -ENODEV; + GEM_BUG_ON(guc_log_has_runtime(guc)); ret = i915_gem_object_set_to_wc_domain(guc->log.vma->obj, true); From e76019a81921e87a4d9e7b3d86102bc708a6c227 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 30 Jan 2018 16:29:38 +0200 Subject: [PATCH 133/158] drm/i915/bxt, glk: Increase PCODE timeouts during CDCLK freq changing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we see sporadic timeouts during CDCLK changing both on BXT and GLK as reported by the Bugzilla: ticket. It's easy to reproduce this by changing the frequency in a tight loop after blanking the display. The upper bound for the completion time is 800us based on my tests, so increase it from the current 500us to 2ms; with that I couldn't trigger the problem either on BXT or GLK. Note that timeouts happened during both the change notification and the voltage level setting PCODE request. (For the latter one BSpec doesn't require us to wait for completion before further HW programming.) This issue is similar to commit 2c7d0602c815 ("drm/i915/gen9: Fix PCODE polling during CDCLK change notification") but there the PCODE request does complete (as shown by the mbox busy flag), only the reply we get from PCODE indicates a failure. So there we keep resending the request until a success reply, here we just have to increase the timeout for the one PCODE request we send. v2: - s/snb_pcode_request/sandybridge_pcode_write_timeout/ (Ville) Cc: Chris Wilson Cc: Ville Syrjälä Cc: # v4.4+ Acked-by: Chris Wilson (v1) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103326 Reviewed-by: Ville Syrjälä Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20180130142939.17983-1-imre.deak@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 6 +++++- drivers/gpu/drm/i915/intel_cdclk.c | 22 +++++++++++++++++----- drivers/gpu/drm/i915/intel_pm.c | 6 +++--- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 21403be6ee0c..8cd4d6f3a160 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3728,7 +3728,11 @@ extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e, struct intel_display_error_state *error); int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val); -int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u32 mbox, u32 val); +int sandybridge_pcode_write_timeout(struct drm_i915_private *dev_priv, u32 mbox, + u32 val, int timeout_us); +#define sandybridge_pcode_write(dev_priv, mbox, val) \ + sandybridge_pcode_write_timeout(dev_priv, mbox, val, 500) + int skl_pcode_request(struct drm_i915_private *dev_priv, u32 mbox, u32 request, u32 reply_mask, u32 reply, int timeout_base_ms); diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index c4392ea34a3d..a423b674fcec 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -1370,10 +1370,15 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, break; } - /* Inform power controller of upcoming frequency change */ + /* + * Inform power controller of upcoming frequency change. BSpec + * requires us to wait up to 150usec, but that leads to timeouts; + * the 2ms used here is based on experiment. + */ mutex_lock(&dev_priv->pcu_lock); - ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, - 0x80000000); + ret = sandybridge_pcode_write_timeout(dev_priv, + HSW_PCODE_DE_WRITE_FREQ_REQ, + 0x80000000, 2000); mutex_unlock(&dev_priv->pcu_lock); if (ret) { @@ -1404,8 +1409,15 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, I915_WRITE(CDCLK_CTL, val); mutex_lock(&dev_priv->pcu_lock); - ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, - cdclk_state->voltage_level); + /* + * The timeout isn't specified, the 2ms used here is based on + * experiment. + * FIXME: Waiting for the request completion could be delayed until + * the next PCODE request based on BSpec. + */ + ret = sandybridge_pcode_write_timeout(dev_priv, + HSW_PCODE_DE_WRITE_FREQ_REQ, + cdclk_state->voltage_level, 2000); mutex_unlock(&dev_priv->pcu_lock); if (ret) { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6dc4677e6c3f..3cc2e6fdd98a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -9214,8 +9214,8 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val return 0; } -int sandybridge_pcode_write(struct drm_i915_private *dev_priv, - u32 mbox, u32 val) +int sandybridge_pcode_write_timeout(struct drm_i915_private *dev_priv, + u32 mbox, u32 val, int timeout_us) { int status; @@ -9238,7 +9238,7 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, if (__intel_wait_for_register_fw(dev_priv, GEN6_PCODE_MAILBOX, GEN6_PCODE_READY, 0, - 500, 0, NULL)) { + timeout_us, 0, NULL)) { DRM_ERROR("timeout waiting for pcode write of 0x%08x to mbox %x to finish for %ps\n", val, mbox, __builtin_return_address(0)); return -ETIMEDOUT; From 006bb4ccac3901d790b56ed4729cd4080a77a895 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 30 Jan 2018 16:29:39 +0200 Subject: [PATCH 134/158] drm/i915/bxt, glk: Avoid long atomic poll during CDCLK change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no requirement for doing the PCODE request polling atomically, so do that only for a short time switching to sleeping poll afterwards. The specification requires a 150usec timeout for the change notification, so let's use that for the atomic poll. Do the extra 2ms poll - needed as a workaround on BXT/GLK - in sleeping mode. v2: - rebase on v2 of patchset dropping the sandybridge_pcode_read/write refactoring (Chris) Cc: Chris Wilson Cc: Ville Syrjälä Signed-off-by: Imre Deak Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180130142939.17983-2-imre.deak@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 5 +++-- drivers/gpu/drm/i915/intel_cdclk.c | 4 ++-- drivers/gpu/drm/i915/intel_pm.c | 6 ++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8cd4d6f3a160..c67385ed0f66 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3729,9 +3729,10 @@ extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e, int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val); int sandybridge_pcode_write_timeout(struct drm_i915_private *dev_priv, u32 mbox, - u32 val, int timeout_us); + u32 val, int fast_timeout_us, + int slow_timeout_ms); #define sandybridge_pcode_write(dev_priv, mbox, val) \ - sandybridge_pcode_write_timeout(dev_priv, mbox, val, 500) + sandybridge_pcode_write_timeout(dev_priv, mbox, val, 500, 0) int skl_pcode_request(struct drm_i915_private *dev_priv, u32 mbox, u32 request, u32 reply_mask, u32 reply, int timeout_base_ms); diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index a423b674fcec..ee788d5be5e3 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -1378,7 +1378,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, mutex_lock(&dev_priv->pcu_lock); ret = sandybridge_pcode_write_timeout(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, - 0x80000000, 2000); + 0x80000000, 150, 2); mutex_unlock(&dev_priv->pcu_lock); if (ret) { @@ -1417,7 +1417,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, */ ret = sandybridge_pcode_write_timeout(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, - cdclk_state->voltage_level, 2000); + cdclk_state->voltage_level, 150, 2); mutex_unlock(&dev_priv->pcu_lock); if (ret) { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3cc2e6fdd98a..eb68abf6a8e9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -9215,7 +9215,8 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val } int sandybridge_pcode_write_timeout(struct drm_i915_private *dev_priv, - u32 mbox, u32 val, int timeout_us) + u32 mbox, u32 val, + int fast_timeout_us, int slow_timeout_ms) { int status; @@ -9238,7 +9239,8 @@ int sandybridge_pcode_write_timeout(struct drm_i915_private *dev_priv, if (__intel_wait_for_register_fw(dev_priv, GEN6_PCODE_MAILBOX, GEN6_PCODE_READY, 0, - timeout_us, 0, NULL)) { + fast_timeout_us, slow_timeout_ms, + NULL)) { DRM_ERROR("timeout waiting for pcode write of 0x%08x to mbox %x to finish for %ps\n", val, mbox, __builtin_return_address(0)); return -ETIMEDOUT; From 10ebb736960cd90eeec7239da2c2b3e8c8a24ef6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 1 Feb 2018 13:03:41 +0200 Subject: [PATCH 135/158] drm/i915/dp: abstract rate array length limiting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will be useful later on. Also move the functions around to not need forward declarations in subsequent patches. No functional changes. Cc: Ville Syrjälä Cc: Rodrigo Vivi Cc: Dhinakaran Pandiyan Reviewed-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/40f37f08cad33234cd86337d39e823ac6e55805f.1517482774.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 38 +++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 78cece041ca0..1d4eced394cf 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -155,6 +155,28 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) intel_dp->num_sink_rates = i; } +/* Get length of rates array potentially limited by max_rate. */ +static int intel_dp_rate_limit_len(const int *rates, int len, int max_rate) +{ + int i; + + /* Limit results by potentially reduced max rate */ + for (i = 0; i < len; i++) { + if (rates[len - i - 1] <= max_rate) + return len - i; + } + + return 0; +} + +/* Get length of common rates array potentially limited by max_rate. */ +static int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp, + int max_rate) +{ + return intel_dp_rate_limit_len(intel_dp->common_rates, + intel_dp->num_common_rates, max_rate); +} + /* Theoretical max between source and sink */ static int intel_dp_max_common_rate(struct intel_dp *intel_dp) { @@ -326,22 +348,6 @@ static void intel_dp_set_common_rates(struct intel_dp *intel_dp) } } -/* get length of common rates potentially limited by max_rate */ -static int intel_dp_common_len_rate_limit(struct intel_dp *intel_dp, - int max_rate) -{ - const int *common_rates = intel_dp->common_rates; - int i, common_len = intel_dp->num_common_rates; - - /* Limit results by potentially reduced max rate */ - for (i = 0; i < common_len; i++) { - if (common_rates[common_len - i - 1] <= max_rate) - return common_len - i; - } - - return 0; -} - static bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate, uint8_t lane_count) { From 4ba285d4154ab587cc00bf9bd04bb8c7b19b595a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 1 Feb 2018 13:03:42 +0200 Subject: [PATCH 136/158] drm/i915/dp: clean up source rate limiting for cnl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the limiting rate based instead of messing with the array size. Cc: Ville Syrjälä Cc: Rodrigo Vivi Cc: Dhinakaran Pandiyan Reviewed-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/cb03b9419191a7d6359bf371aacb2d3725c746de.1517482774.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1d4eced394cf..bee510514826 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -240,7 +240,7 @@ intel_dp_downstream_max_dotclock(struct intel_dp *intel_dp) return max_dotclk; } -static int cnl_adjusted_max_rate(struct intel_dp *intel_dp, int size) +static int cnl_max_source_rate(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); @@ -250,17 +250,17 @@ static int cnl_adjusted_max_rate(struct intel_dp *intel_dp, int size) /* Low voltage SKUs are limited to max of 5.4G */ if (voltage == VOLTAGE_INFO_0_85V) - return size - 2; + return 540000; /* For this SKU 8.1G is supported in all ports */ if (IS_CNL_WITH_PORT_F(dev_priv)) - return size; + return 810000; /* For other SKUs, max rate on ports A and B is 5.4G */ if (port == PORT_A || port == PORT_D) - return size - 2; + return 540000; - return size; + return 810000; } static void @@ -269,7 +269,7 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); const int *source_rates; - int size; + int size, max_rate = 0; /* This should only be done once */ WARN_ON(intel_dp->source_rates || intel_dp->num_source_rates); @@ -279,7 +279,8 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) size = ARRAY_SIZE(bxt_rates); } else if (IS_CANNONLAKE(dev_priv)) { source_rates = cnl_rates; - size = cnl_adjusted_max_rate(intel_dp, ARRAY_SIZE(cnl_rates)); + size = ARRAY_SIZE(cnl_rates); + max_rate = cnl_max_source_rate(intel_dp); } else if (IS_GEN9_BC(dev_priv)) { source_rates = skl_rates; size = ARRAY_SIZE(skl_rates); @@ -292,6 +293,9 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) size = ARRAY_SIZE(default_rates) - 1; } + if (max_rate) + size = intel_dp_rate_limit_len(source_rates, size, max_rate); + intel_dp->source_rates = source_rates; intel_dp->num_source_rates = size; } From 99b91bda84060bac061d1649fad0e3bddcf67ce6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 1 Feb 2018 13:03:43 +0200 Subject: [PATCH 137/158] drm/i915/dp: limit DP link rate based on VBT on CNL+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have the max DP link rate info available in VBT since BDB version 216, included in child device config since commit c4fb60b9aba9 ("drm/i915/bios: add DP max link rate to VBT child device struct"). Parse it and use it. Cc: Ville Syrjälä Cc: Rodrigo Vivi Cc: Dhinakaran Pandiyan Reviewed-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/a8b1364d1f2394fba3062b6ad11b474744ea4366.1517482774.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_bios.c | 21 +++++++++++++++++++++ drivers/gpu/drm/i915/intel_dp.c | 9 ++++++++- drivers/gpu/drm/i915/intel_vbt_defs.h | 5 +++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c67385ed0f66..d1d8b1b8de46 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1282,6 +1282,7 @@ struct ddi_vbt_port_info { uint8_t dp_boost_level; uint8_t hdmi_boost_level; + int dp_max_link_rate; /* 0 for not limited by VBT */ }; enum psr_lines_to_wait { diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index cf3f8f1ba6f7..4e74aa2f16bc 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1274,6 +1274,27 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, DRM_DEBUG_KMS("VBT HDMI boost level for port %c: %d\n", port_name(port), info->hdmi_boost_level); } + + /* DP max link rate for CNL+ */ + if (bdb_version >= 216) { + switch (child->dp_max_link_rate) { + default: + case VBT_DP_MAX_LINK_RATE_HBR3: + info->dp_max_link_rate = 810000; + break; + case VBT_DP_MAX_LINK_RATE_HBR2: + info->dp_max_link_rate = 540000; + break; + case VBT_DP_MAX_LINK_RATE_HBR: + info->dp_max_link_rate = 270000; + break; + case VBT_DP_MAX_LINK_RATE_LBR: + info->dp_max_link_rate = 162000; + break; + } + DRM_DEBUG_KMS("VBT DP max link rate for port %c: %d\n", + port_name(port), info->dp_max_link_rate); + } } static void parse_ddi_ports(struct drm_i915_private *dev_priv, u8 bdb_version) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index bee510514826..8503d182921b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -268,8 +268,10 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + const struct ddi_vbt_port_info *info = + &dev_priv->vbt.ddi_port_info[dig_port->base.port]; const int *source_rates; - int size, max_rate = 0; + int size, max_rate = 0, vbt_max_rate = info->dp_max_link_rate; /* This should only be done once */ WARN_ON(intel_dp->source_rates || intel_dp->num_source_rates); @@ -293,6 +295,11 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) size = ARRAY_SIZE(default_rates) - 1; } + if (max_rate && vbt_max_rate) + max_rate = min(max_rate, vbt_max_rate); + else if (vbt_max_rate) + max_rate = vbt_max_rate; + if (max_rate) size = intel_dp_rate_limit_len(source_rates, size, max_rate); diff --git a/drivers/gpu/drm/i915/intel_vbt_defs.h b/drivers/gpu/drm/i915/intel_vbt_defs.h index 3d3feee9b5dd..458468237b5f 100644 --- a/drivers/gpu/drm/i915/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/intel_vbt_defs.h @@ -320,6 +320,11 @@ enum vbt_gmbus_ddi { DDC_BUS_DDI_F, }; +#define VBT_DP_MAX_LINK_RATE_HBR3 0 +#define VBT_DP_MAX_LINK_RATE_HBR2 1 +#define VBT_DP_MAX_LINK_RATE_HBR 2 +#define VBT_DP_MAX_LINK_RATE_LBR 3 + /* * The child device config, aka the display device data structure, provides a * description of a port and its configuration on the platform. From fae919f07610c52ad93915b54c5baeb111c6ea0d Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 1 Feb 2018 17:32:48 +0000 Subject: [PATCH 138/158] drm/i915: Enable inject_load_failure only in DEBUG config We're using i915_inject_load_failure() to inject dummy faults during driver load, but since this is debug utility we shouldn't expose it in default config as it consumes both code and data. add/remove: 0/1 grow/shrink: 0/2 up/down: 0/-302 (-302) Function old new delta __i915_inject_load_failure 61 - -61 i915_gem_init 1331 1268 -63 i915_driver_load 5923 5745 -178 Total: Before=1177454, After=1177152, chg -0.03% add/remove: 0/1 grow/shrink: 0/0 up/down: 0/-4 (-4) Data old new delta i915_load_fail_count 4 - -4 Total: Before=56762, After=56758, chg -0.01% add/remove: 4/8 grow/shrink: 0/1 up/down: 245/-591 (-346) RO Data old new delta __param_str_inject_load_failure 20 - -20 __UNIQUE_ID_inject_load_failuretype200 34 - -34 __param_inject_load_failure 40 - -40 __func__ 4998 4896 -102 __UNIQUE_ID_inject_load_failure201 150 - -150 Total: Before=119095, After=118749, chg -0.29% Signed-off-by: Michal Wajdeczko Cc: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180201173248.3912-1-michal.wajdeczko@intel.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 6 ++++++ drivers/gpu/drm/i915/i915_drv.h | 4 ++++ drivers/gpu/drm/i915/i915_params.c | 2 ++ 3 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 1ec12add34b2..6e7e933fea32 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -55,6 +55,7 @@ static struct drm_driver driver; +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) static unsigned int i915_load_fail_count; bool __i915_inject_load_failure(const char *func, int line) @@ -70,6 +71,7 @@ bool __i915_inject_load_failure(const char *func, int line) return false; } +#endif #define FDO_BUG_URL "https://bugs.freedesktop.org/enter_bug.cgi?product=DRI" #define FDO_BUG_MSG "Please file a bug at " FDO_BUG_URL " against DRM/Intel " \ @@ -107,8 +109,12 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level, static bool i915_error_injected(struct drm_i915_private *dev_priv) { +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) return i915_modparams.inject_load_failure && i915_load_fail_count == i915_modparams.inject_load_failure; +#else + return false; +#endif } #define i915_load_error(dev_priv, fmt, ...) \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d1d8b1b8de46..5ed220e28402 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -104,9 +104,13 @@ #define I915_STATE_WARN_ON(x) \ I915_STATE_WARN((x), "%s", "WARN_ON(" __stringify(x) ")") +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) bool __i915_inject_load_failure(const char *func, int line); #define i915_inject_load_failure() \ __i915_inject_load_failure(__func__, __LINE__) +#else +#define i915_inject_load_failure() false +#endif typedef struct { uint32_t val; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 0b553a8e48fb..08108ce5be21 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -167,8 +167,10 @@ i915_param_named_unsafe(huc_firmware_path, charp, 0400, i915_param_named_unsafe(enable_dp_mst, bool, 0600, "Enable multi-stream transport (MST) for new DisplayPort sinks. (default: true)"); +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) i915_param_named_unsafe(inject_load_failure, uint, 0400, "Force an error after a number of failure check points (0:disabled (default), N:force failure at the Nth failure check point)"); +#endif i915_param_named(enable_dpcd_backlight, bool, 0600, "Enable support for DPCD backlight control (default:false)"); From d67c0ac19f9a3d900fbdf84924cb4d3aea934310 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 2 Feb 2018 15:04:16 +0200 Subject: [PATCH 139/158] drm/i915: reduce indent in pch detection Save some horizontal space. Reviewed-by: David Weinehall Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180202130416.18233-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 183 ++++++++++++++++---------------- 1 file changed, 93 insertions(+), 90 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 6e7e933fea32..e9f1daf258fe 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -182,100 +182,103 @@ static void intel_detect_pch(struct drm_i915_private *dev_priv) * of only checking the first one. */ while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) { - if (pch->vendor == PCI_VENDOR_ID_INTEL) { - unsigned short id = pch->device & INTEL_PCH_DEVICE_ID_MASK; + unsigned short id; - dev_priv->pch_id = id; + if (pch->vendor != PCI_VENDOR_ID_INTEL) + continue; - if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) { - dev_priv->pch_type = PCH_IBX; - DRM_DEBUG_KMS("Found Ibex Peak PCH\n"); - WARN_ON(!IS_GEN5(dev_priv)); - } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) { - dev_priv->pch_type = PCH_CPT; - DRM_DEBUG_KMS("Found CougarPoint PCH\n"); - WARN_ON(!IS_GEN6(dev_priv) && - !IS_IVYBRIDGE(dev_priv)); - } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) { - /* PantherPoint is CPT compatible */ - dev_priv->pch_type = PCH_CPT; - DRM_DEBUG_KMS("Found PantherPoint PCH\n"); - WARN_ON(!IS_GEN6(dev_priv) && - !IS_IVYBRIDGE(dev_priv)); - } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { - dev_priv->pch_type = PCH_LPT; - DRM_DEBUG_KMS("Found LynxPoint PCH\n"); - WARN_ON(!IS_HASWELL(dev_priv) && - !IS_BROADWELL(dev_priv)); - WARN_ON(IS_HSW_ULT(dev_priv) || - IS_BDW_ULT(dev_priv)); - } else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { - dev_priv->pch_type = PCH_LPT; - DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); - WARN_ON(!IS_HASWELL(dev_priv) && - !IS_BROADWELL(dev_priv)); - WARN_ON(!IS_HSW_ULT(dev_priv) && - !IS_BDW_ULT(dev_priv)); - } else if (id == INTEL_PCH_WPT_DEVICE_ID_TYPE) { - /* WildcatPoint is LPT compatible */ - dev_priv->pch_type = PCH_LPT; - DRM_DEBUG_KMS("Found WildcatPoint PCH\n"); - WARN_ON(!IS_HASWELL(dev_priv) && - !IS_BROADWELL(dev_priv)); - WARN_ON(IS_HSW_ULT(dev_priv) || - IS_BDW_ULT(dev_priv)); - } else if (id == INTEL_PCH_WPT_LP_DEVICE_ID_TYPE) { - /* WildcatPoint is LPT compatible */ - dev_priv->pch_type = PCH_LPT; - DRM_DEBUG_KMS("Found WildcatPoint LP PCH\n"); - WARN_ON(!IS_HASWELL(dev_priv) && - !IS_BROADWELL(dev_priv)); - WARN_ON(!IS_HSW_ULT(dev_priv) && - !IS_BDW_ULT(dev_priv)); - } else if (id == INTEL_PCH_SPT_DEVICE_ID_TYPE) { - dev_priv->pch_type = PCH_SPT; - DRM_DEBUG_KMS("Found SunrisePoint PCH\n"); - WARN_ON(!IS_SKYLAKE(dev_priv) && - !IS_KABYLAKE(dev_priv)); - } else if (id == INTEL_PCH_SPT_LP_DEVICE_ID_TYPE) { - dev_priv->pch_type = PCH_SPT; - DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n"); - WARN_ON(!IS_SKYLAKE(dev_priv) && - !IS_KABYLAKE(dev_priv)); - } else if (id == INTEL_PCH_KBP_DEVICE_ID_TYPE) { - dev_priv->pch_type = PCH_KBP; - DRM_DEBUG_KMS("Found Kaby Lake PCH (KBP)\n"); - WARN_ON(!IS_SKYLAKE(dev_priv) && - !IS_KABYLAKE(dev_priv) && - !IS_COFFEELAKE(dev_priv)); - } else if (id == INTEL_PCH_CNP_DEVICE_ID_TYPE) { - dev_priv->pch_type = PCH_CNP; - DRM_DEBUG_KMS("Found Cannon Lake PCH (CNP)\n"); - WARN_ON(!IS_CANNONLAKE(dev_priv) && - !IS_COFFEELAKE(dev_priv)); - } else if (id == INTEL_PCH_CNP_LP_DEVICE_ID_TYPE) { - dev_priv->pch_type = PCH_CNP; - DRM_DEBUG_KMS("Found Cannon Lake LP PCH (CNP-LP)\n"); - WARN_ON(!IS_CANNONLAKE(dev_priv) && - !IS_COFFEELAKE(dev_priv)); - } else if (id == INTEL_PCH_ICP_DEVICE_ID_TYPE) { - dev_priv->pch_type = PCH_ICP; - DRM_DEBUG_KMS("Found Ice Lake PCH\n"); - WARN_ON(!IS_ICELAKE(dev_priv)); - } else if (id == INTEL_PCH_P2X_DEVICE_ID_TYPE || - id == INTEL_PCH_P3X_DEVICE_ID_TYPE || - (id == INTEL_PCH_QEMU_DEVICE_ID_TYPE && - pch->subsystem_vendor == - PCI_SUBVENDOR_ID_REDHAT_QUMRANET && - pch->subsystem_device == - PCI_SUBDEVICE_ID_QEMU)) { - dev_priv->pch_type = - intel_virt_detect_pch(dev_priv); - } else - continue; + id = pch->device & INTEL_PCH_DEVICE_ID_MASK; - break; + dev_priv->pch_id = id; + + if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_IBX; + DRM_DEBUG_KMS("Found Ibex Peak PCH\n"); + WARN_ON(!IS_GEN5(dev_priv)); + } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_CPT; + DRM_DEBUG_KMS("Found CougarPoint PCH\n"); + WARN_ON(!IS_GEN6(dev_priv) && + !IS_IVYBRIDGE(dev_priv)); + } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) { + /* PantherPoint is CPT compatible */ + dev_priv->pch_type = PCH_CPT; + DRM_DEBUG_KMS("Found PantherPoint PCH\n"); + WARN_ON(!IS_GEN6(dev_priv) && + !IS_IVYBRIDGE(dev_priv)); + } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_LPT; + DRM_DEBUG_KMS("Found LynxPoint PCH\n"); + WARN_ON(!IS_HASWELL(dev_priv) && + !IS_BROADWELL(dev_priv)); + WARN_ON(IS_HSW_ULT(dev_priv) || + IS_BDW_ULT(dev_priv)); + } else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_LPT; + DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); + WARN_ON(!IS_HASWELL(dev_priv) && + !IS_BROADWELL(dev_priv)); + WARN_ON(!IS_HSW_ULT(dev_priv) && + !IS_BDW_ULT(dev_priv)); + } else if (id == INTEL_PCH_WPT_DEVICE_ID_TYPE) { + /* WildcatPoint is LPT compatible */ + dev_priv->pch_type = PCH_LPT; + DRM_DEBUG_KMS("Found WildcatPoint PCH\n"); + WARN_ON(!IS_HASWELL(dev_priv) && + !IS_BROADWELL(dev_priv)); + WARN_ON(IS_HSW_ULT(dev_priv) || + IS_BDW_ULT(dev_priv)); + } else if (id == INTEL_PCH_WPT_LP_DEVICE_ID_TYPE) { + /* WildcatPoint is LPT compatible */ + dev_priv->pch_type = PCH_LPT; + DRM_DEBUG_KMS("Found WildcatPoint LP PCH\n"); + WARN_ON(!IS_HASWELL(dev_priv) && + !IS_BROADWELL(dev_priv)); + WARN_ON(!IS_HSW_ULT(dev_priv) && + !IS_BDW_ULT(dev_priv)); + } else if (id == INTEL_PCH_SPT_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_SPT; + DRM_DEBUG_KMS("Found SunrisePoint PCH\n"); + WARN_ON(!IS_SKYLAKE(dev_priv) && + !IS_KABYLAKE(dev_priv)); + } else if (id == INTEL_PCH_SPT_LP_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_SPT; + DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n"); + WARN_ON(!IS_SKYLAKE(dev_priv) && + !IS_KABYLAKE(dev_priv)); + } else if (id == INTEL_PCH_KBP_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_KBP; + DRM_DEBUG_KMS("Found Kaby Lake PCH (KBP)\n"); + WARN_ON(!IS_SKYLAKE(dev_priv) && + !IS_KABYLAKE(dev_priv) && + !IS_COFFEELAKE(dev_priv)); + } else if (id == INTEL_PCH_CNP_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_CNP; + DRM_DEBUG_KMS("Found Cannon Lake PCH (CNP)\n"); + WARN_ON(!IS_CANNONLAKE(dev_priv) && + !IS_COFFEELAKE(dev_priv)); + } else if (id == INTEL_PCH_CNP_LP_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_CNP; + DRM_DEBUG_KMS("Found Cannon Lake LP PCH (CNP-LP)\n"); + WARN_ON(!IS_CANNONLAKE(dev_priv) && + !IS_COFFEELAKE(dev_priv)); + } else if (id == INTEL_PCH_ICP_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_ICP; + DRM_DEBUG_KMS("Found Ice Lake PCH\n"); + WARN_ON(!IS_ICELAKE(dev_priv)); + } else if (id == INTEL_PCH_P2X_DEVICE_ID_TYPE || + id == INTEL_PCH_P3X_DEVICE_ID_TYPE || + (id == INTEL_PCH_QEMU_DEVICE_ID_TYPE && + pch->subsystem_vendor == + PCI_SUBVENDOR_ID_REDHAT_QUMRANET && + pch->subsystem_device == + PCI_SUBDEVICE_ID_QEMU)) { + dev_priv->pch_type = intel_virt_detect_pch(dev_priv); + } else { + continue; } + + break; } if (!pch) DRM_DEBUG_KMS("No PCH found.\n"); From 274de876065a34ca1ff093bfacb62e440a4491be Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 2 Feb 2018 14:54:55 +0000 Subject: [PATCH 140/158] drm/i915/execlists: Flush GTIIR on clearing CS interrupts during reset Be paranoid and flush the GTIIR after clearing the CS interrupt to be sure it has taken before we re-enable the interrupt handler. We still see early interrupts following reset, the tasklet handling the mmio read before it has been written by the CS. This hopefully reduces the frequency to 0... References: https://bugs.freedesktop.org/show_bug.cgi?id=104262 Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Michel Thierry Cc: Tvrtko Ursulin Acked-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180202145455.29876-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 40dbeaee9dfa..deeedfc9fe44 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1527,6 +1527,7 @@ static int gen9_init_render_ring(struct intel_engine_cs *engine) static void reset_irq(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; + int i; /* * Clear any pending interrupt state. @@ -1535,10 +1536,14 @@ static void reset_irq(struct intel_engine_cs *engine) * buffered, and if we only reset it once there may still be * an interrupt pending. */ - I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]), - GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift); - I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]), - GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift); + for (i = 0; i < 2; i++) { + I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]), + GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift); + POSTING_READ(GEN8_GT_IIR(gtiir[engine->id])); + } + GEM_BUG_ON(I915_READ(GEN8_GT_IIR(gtiir[engine->id])) & + (GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift)); + clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); } From 55ef72f24fae5d41febe6b6ebf7304f9a2cb9471 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 2 Feb 2018 15:34:48 +0000 Subject: [PATCH 141/158] drm/i915: Remove spurious DRM_ERROR for cancelled interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As we ourselves cancel interrupts during reset by clearing the GTIIR, it is possible for the master IIR to indicate a pending IRQ for which we have already cleared from the GTIIR. In this case, the DRM_ERROR are intended and should not be flagged as an error. Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Cc: Tvrtko Ursulin Cc: Ville Syrjälä Cc: Imre Deak Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180202153448.23908-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_irq.c | 35 +++++++++------------------------ 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 252feff2892d..b886bd459acc 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1413,37 +1413,25 @@ gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir, int test_shift) tasklet_hi_schedule(&execlists->tasklet); } -static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv, - u32 master_ctl, - u32 gt_iir[4]) +static void gen8_gt_irq_ack(struct drm_i915_private *dev_priv, + u32 master_ctl, u32 gt_iir[4]) { - irqreturn_t ret = IRQ_NONE; - if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) { gt_iir[0] = I915_READ_FW(GEN8_GT_IIR(0)); - if (gt_iir[0]) { + if (gt_iir[0]) I915_WRITE_FW(GEN8_GT_IIR(0), gt_iir[0]); - ret = IRQ_HANDLED; - } else - DRM_ERROR("The master control interrupt lied (GT0)!\n"); } if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) { gt_iir[1] = I915_READ_FW(GEN8_GT_IIR(1)); - if (gt_iir[1]) { + if (gt_iir[1]) I915_WRITE_FW(GEN8_GT_IIR(1), gt_iir[1]); - ret = IRQ_HANDLED; - } else - DRM_ERROR("The master control interrupt lied (GT1)!\n"); } if (master_ctl & GEN8_GT_VECS_IRQ) { gt_iir[3] = I915_READ_FW(GEN8_GT_IIR(3)); - if (gt_iir[3]) { + if (gt_iir[3]) I915_WRITE_FW(GEN8_GT_IIR(3), gt_iir[3]); - ret = IRQ_HANDLED; - } else - DRM_ERROR("The master control interrupt lied (GT3)!\n"); } if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) { @@ -1453,12 +1441,8 @@ static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv, I915_WRITE_FW(GEN8_GT_IIR(2), gt_iir[2] & (dev_priv->pm_rps_events | dev_priv->pm_guc_events)); - ret = IRQ_HANDLED; - } else - DRM_ERROR("The master control interrupt lied (PM)!\n"); + } } - - return ret; } static void gen8_gt_irq_handler(struct drm_i915_private *dev_priv, @@ -2695,7 +2679,6 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) struct drm_i915_private *dev_priv = to_i915(dev); u32 master_ctl; u32 gt_iir[4] = {}; - irqreturn_t ret; if (!intel_irqs_enabled(dev_priv)) return IRQ_NONE; @@ -2711,16 +2694,16 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) disable_rpm_wakeref_asserts(dev_priv); /* Find, clear, then process each source of interrupt */ - ret = gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir); + gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir); gen8_gt_irq_handler(dev_priv, gt_iir); - ret |= gen8_de_irq_handler(dev_priv, master_ctl); + gen8_de_irq_handler(dev_priv, master_ctl); I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL); POSTING_READ_FW(GEN8_MASTER_IRQ); enable_rpm_wakeref_asserts(dev_priv); - return ret; + return IRQ_HANDLED; } struct wedge_me { From 302e55d7be959502058878e9edb1d369a73598d4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 Feb 2018 09:41:39 +0000 Subject: [PATCH 142/158] drm/i915: Report if an unbannable context is involved in a GPU hang Since unbannable contexts are special and supposed not to be causing GPU hangs in the first place, make it clear when they are implicated in said hang. In practice, most unbannable contexts are those created by igt for the express purpose of throwing untold thousands of hangs at the GPU and wish to keep doing so to finish the test. Normally they are cleaned up, but it's when they or the other unbannable kernel contexts stay stuck in an erroneous state that we need to worry and so need highlighting. Suggested-by: Mika Kuoppala Signed-off-by: Chris Wilson Cc: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180205094139.10671-1-chris@chris-wilson.co.uk Reviewed-by: Mika Kuoppala --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gpu_error.c | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5ed220e28402..a241620f22ad 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -555,6 +555,7 @@ struct i915_gpu_state { int ban_score; int active; int guilty; + bool bannable; } context; struct drm_i915_error_object { diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index a81351d9e3a6..67c902412193 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -396,6 +396,11 @@ static void error_print_instdone(struct drm_i915_error_state_buf *m, ee->instdone.row[slice][subslice]); } +static const char *bannable(const struct drm_i915_error_context *ctx) +{ + return ctx->bannable ? "" : " (unbannable)"; +} + static void error_print_request(struct drm_i915_error_state_buf *m, const char *prefix, const struct drm_i915_error_request *erq) @@ -414,9 +419,10 @@ static void error_print_context(struct drm_i915_error_state_buf *m, const char *header, const struct drm_i915_error_context *ctx) { - err_printf(m, "%s%s[%d] user_handle %d hw_id %d, prio %d, ban score %d guilty %d active %d\n", + err_printf(m, "%s%s[%d] user_handle %d hw_id %d, prio %d, ban score %d%s guilty %d active %d\n", header, ctx->comm, ctx->pid, ctx->handle, ctx->hw_id, - ctx->priority, ctx->ban_score, ctx->guilty, ctx->active); + ctx->priority, ctx->ban_score, bannable(ctx), + ctx->guilty, ctx->active); } static void error_print_engine(struct drm_i915_error_state_buf *m, @@ -644,11 +650,12 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, for (i = 0; i < ARRAY_SIZE(error->engine); i++) { if (error->engine[i].hangcheck_stalled && error->engine[i].context.pid) { - err_printf(m, "Active process (on ring %s): %s [%d], score %d\n", + err_printf(m, "Active process (on ring %s): %s [%d], score %d%s\n", engine_name(m->i915, i), error->engine[i].context.comm, error->engine[i].context.pid, - error->engine[i].context.ban_score); + error->engine[i].context.ban_score, + bannable(&error->engine[i].context)); } } err_printf(m, "Reset count: %u\n", error->reset_count); @@ -736,12 +743,13 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, if (obj) { err_puts(m, dev_priv->engine[i]->name); if (ee->context.pid) - err_printf(m, " (submitted by %s [%d], ctx %d [%d], score %d)", + err_printf(m, " (submitted by %s [%d], ctx %d [%d], score %d%s)", ee->context.comm, ee->context.pid, ee->context.handle, ee->context.hw_id, - ee->context.ban_score); + ee->context.ban_score, + bannable(&ee->context)); err_printf(m, " --- gtt_offset = 0x%08x %08x\n", upper_32_bits(obj->gtt_offset), lower_32_bits(obj->gtt_offset)); @@ -1383,6 +1391,7 @@ static void record_context(struct drm_i915_error_context *e, e->hw_id = ctx->hw_id; e->priority = ctx->priority; e->ban_score = atomic_read(&ctx->ban_score); + e->bannable = i915_gem_context_is_bannable(ctx); e->guilty = atomic_read(&ctx->guilty_count); e->active = atomic_read(&ctx->active_count); } From 9e519bc8b98c4a07e1f8c42fcde23f3c2d2d7b0e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 Feb 2018 10:06:18 +0000 Subject: [PATCH 143/158] drm/i915: Add some newlines to intel_engine_dump() headers The headers should be on a separate line for consistency, so add the missing trailing newline in a few intel_engine_dump() callers. Reported-by: Mika Kuoppala Signed-off-by: Chris Wilson Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180205100618.11001-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/intel_hangcheck.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 63308ec016a3..6a866810b529 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3644,7 +3644,7 @@ static int wait_for_engines(struct drm_i915_private *i915) for_each_engine(engine, i915, id) intel_engine_dump(engine, &p, - "%s", engine->name); + "%s\n", engine->name); } i915_gem_set_wedged(i915); diff --git a/drivers/gpu/drm/i915/intel_hangcheck.c b/drivers/gpu/drm/i915/intel_hangcheck.c index 348a4f7ffb67..42e45ae87393 100644 --- a/drivers/gpu/drm/i915/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/intel_hangcheck.c @@ -359,7 +359,7 @@ static void hangcheck_accumulate_sample(struct intel_engine_cs *engine, case ENGINE_DEAD: if (drm_debug & DRM_UT_DRIVER) { struct drm_printer p = drm_debug_printer("hangcheck"); - intel_engine_dump(engine, &p, "%s", engine->name); + intel_engine_dump(engine, &p, "%s\n", engine->name); } break; From 4a3d1e0f9d42c7c16b0498641fbbe879a19ff1f6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 25 Jan 2018 22:41:22 +0000 Subject: [PATCH 144/158] drm/i915: Always update the no_fbc_reason when disabling Provide the reason why we call intel_fbc_deactivate() so that debugging issues with FBC being delayed is clearer. Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180125224122.27480-1-chris@chris-wilson.co.uk Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/intel_fbc.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index a8a8a80497a8..80682a418a70 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -492,7 +492,8 @@ static void intel_fbc_schedule_activation(struct intel_crtc *crtc) schedule_work(&work->work); } -static void intel_fbc_deactivate(struct drm_i915_private *dev_priv) +static void intel_fbc_deactivate(struct drm_i915_private *dev_priv, + const char *reason) { struct intel_fbc *fbc = &dev_priv->fbc; @@ -505,6 +506,8 @@ static void intel_fbc_deactivate(struct drm_i915_private *dev_priv) if (fbc->active) intel_fbc_hw_deactivate(dev_priv); + + fbc->no_fbc_reason = reason; } static bool multiple_pipes_ok(struct intel_crtc *crtc, @@ -923,6 +926,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc, { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct intel_fbc *fbc = &dev_priv->fbc; + const char *reason = "update pending"; if (!fbc_supported(dev_priv)) return; @@ -930,7 +934,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc, mutex_lock(&fbc->lock); if (!multiple_pipes_ok(crtc, plane_state)) { - fbc->no_fbc_reason = "more than one pipe active"; + reason = "more than one pipe active"; goto deactivate; } @@ -940,7 +944,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc, intel_fbc_update_state_cache(crtc, crtc_state, plane_state); deactivate: - intel_fbc_deactivate(dev_priv); + intel_fbc_deactivate(dev_priv, reason); unlock: mutex_unlock(&fbc->lock); } @@ -973,9 +977,8 @@ static void __intel_fbc_post_update(struct intel_crtc *crtc) intel_fbc_reg_params_equal(&old_params, &fbc->params)) return; - intel_fbc_deactivate(dev_priv); + intel_fbc_deactivate(dev_priv, "FBC enabled (active or scheduled)"); intel_fbc_schedule_activation(crtc); - fbc->no_fbc_reason = "FBC enabled (active or scheduled)"; } void intel_fbc_post_update(struct intel_crtc *crtc) @@ -1016,7 +1019,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, fbc->busy_bits |= intel_fbc_get_frontbuffer_bit(fbc) & frontbuffer_bits; if (fbc->enabled && fbc->busy_bits) - intel_fbc_deactivate(dev_priv); + intel_fbc_deactivate(dev_priv, "frontbuffer write"); mutex_unlock(&fbc->lock); } @@ -1246,7 +1249,7 @@ static void intel_fbc_underrun_work_fn(struct work_struct *work) DRM_DEBUG_KMS("Disabling FBC due to FIFO underrun.\n"); fbc->underrun_detected = true; - intel_fbc_deactivate(dev_priv); + intel_fbc_deactivate(dev_priv, "FIFO underrun"); out: mutex_unlock(&fbc->lock); } From 559e040f1f083b6478011f2961db230da8047119 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 Feb 2018 09:21:59 +0000 Subject: [PATCH 145/158] drm/i915: Show the GPU state when declaring wedged Dump each engine state when i915_gem_set_wedged() is called to give us some more clues as to why we had to terminate the GPU. Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180205092201.19476-5-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6a866810b529..dffbe8f7765f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3199,6 +3199,13 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) struct intel_engine_cs *engine; enum intel_engine_id id; + if (drm_debug & DRM_UT_DRIVER) { + struct drm_printer p = drm_debug_printer(__func__); + + for_each_engine(engine, i915, id) + intel_engine_dump(engine, &p, "%s\n", engine->name); + } + /* * First, stop submission to hw, but do not yet complete requests by * rolling the global seqno forward (since this would complete requests From 073988d1023276277a3fe148a7a87c8ef3860a98 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 Feb 2018 09:22:00 +0000 Subject: [PATCH 146/158] drm/i915/execlists: Remove the startup spam Execlists is now enabled by default and included in the list of capabilities printed out to dmesg and beyond. We do not need to mention it again, every time we restart the engine, so kill the spam. Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180205092201.19476-6-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index deeedfc9fe44..afc41dbc872e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1477,7 +1477,6 @@ static int gen8_init_common_ring(struct intel_engine_cs *engine) intel_engine_init_hangcheck(engine); enable_execlists(engine); - DRM_DEBUG_DRIVER("Execlists enabled for %s\n", engine->name); GEM_BUG_ON(engine->id >= ARRAY_SIZE(gtiir)); From 24eae08d442eb6e9046a6d07abaa3e419bf429d8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 Feb 2018 09:22:01 +0000 Subject: [PATCH 147/158] drm/i915: Remove unbannable context spam from reset During testing, we trigger a lot of resets on an unbannable context leading to massive amounts of irrelevant debug spam. Remove the ban_score accounting and message for the unbannable context so that we improve the signal:noise in the log messages for when the unexpected occurs. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180205092201.19476-7-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index dffbe8f7765f..f3cc40a7aa5c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2823,24 +2823,23 @@ i915_gem_object_pwrite_gtt(struct drm_i915_gem_object *obj, return 0; } -static bool ban_context(const struct i915_gem_context *ctx, - unsigned int score) -{ - return (i915_gem_context_is_bannable(ctx) && - score >= CONTEXT_SCORE_BAN_THRESHOLD); -} - static void i915_gem_context_mark_guilty(struct i915_gem_context *ctx) { - unsigned int score; bool banned; atomic_inc(&ctx->guilty_count); - score = atomic_add_return(CONTEXT_SCORE_GUILTY, &ctx->ban_score); - banned = ban_context(ctx, score); - DRM_DEBUG_DRIVER("context %s marked guilty (score %d) banned? %s\n", - ctx->name, score, yesno(banned)); + banned = false; + if (i915_gem_context_is_bannable(ctx)) { + unsigned int score; + + score = atomic_add_return(CONTEXT_SCORE_GUILTY, + &ctx->ban_score); + banned = score >= CONTEXT_SCORE_BAN_THRESHOLD; + + DRM_DEBUG_DRIVER("context %s marked guilty (score %d) banned? %s\n", + ctx->name, score, yesno(banned)); + } if (!banned) return; From b7a3f33bd5abfb0b693831d3b5230851f508e330 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 3 Feb 2018 10:19:14 +0000 Subject: [PATCH 148/158] drm/i915/breadcrumbs: Drop request reference for the signaler thread If we remember to cancel the signaler on a request when retiring it (after we know that the request has been signaled), we do not need to carry an additional request in the signaler itself. This prevents an issue whereby the signaler threads may be delayed and hold on to thousands of request references, causing severe memory fragmentation and premature oom (most noticeable on 32b snb due to the limited GFP_KERNEL and frequent use of inter-engine fences). v2: Rename first_signal(), document reads outside of locks. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180203101914.24880-1-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/i915_gem_request.c | 6 +- drivers/gpu/drm/i915/intel_breadcrumbs.c | 150 ++++++++++++----------- 2 files changed, 86 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c index cf2f3895b70e..8efa9e7a9e46 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.c +++ b/drivers/gpu/drm/i915/i915_gem_request.c @@ -445,7 +445,10 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request) spin_lock_irq(&request->lock); if (request->waitboost) atomic_dec(&request->i915->gt_pm.rps.num_waiters); - dma_fence_signal_locked(&request->fence); + if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &request->fence.flags)) + dma_fence_signal_locked(&request->fence); + if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &request->fence.flags)) + intel_engine_cancel_signaling(request); spin_unlock_irq(&request->lock); i915_priotree_fini(request->i915, &request->priotree); @@ -744,6 +747,7 @@ i915_gem_request_alloc(struct intel_engine_cs *engine, /* No zalloc, must clear what we need by hand */ req->global_seqno = 0; + req->signaling.wait.seqno = 0; req->file_priv = NULL; req->batch = NULL; req->capture_list = NULL; diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c index 62b2a20bc24e..efbc627a2a25 100644 --- a/drivers/gpu/drm/i915/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c @@ -224,7 +224,7 @@ void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine) struct intel_wait *wait, *n; if (!b->irq_armed) - goto wakeup_signaler; + return; /* * We only disarm the irq when we are idle (all requests completed), @@ -249,14 +249,6 @@ void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine) b->waiters = RB_ROOT; spin_unlock_irq(&b->rb_lock); - - /* - * The signaling thread may be asleep holding a reference to a request, - * that had its signaling cancelled prior to being preempted. We need - * to kick the signaler, just in case, to release any such reference. - */ -wakeup_signaler: - wake_up_process(b->signaler); } static bool use_fake_irq(const struct intel_breadcrumbs *b) @@ -633,6 +625,63 @@ static void signaler_set_rtpriority(void) sched_setscheduler_nocheck(current, SCHED_FIFO, ¶m); } +static void __intel_engine_remove_signal(struct intel_engine_cs *engine, + struct drm_i915_gem_request *request) +{ + struct intel_breadcrumbs *b = &engine->breadcrumbs; + + lockdep_assert_held(&b->rb_lock); + + /* + * Wake up all other completed waiters and select the + * next bottom-half for the next user interrupt. + */ + __intel_engine_remove_wait(engine, &request->signaling.wait); + + /* + * Find the next oldest signal. Note that as we have + * not been holding the lock, another client may + * have installed an even older signal than the one + * we just completed - so double check we are still + * the oldest before picking the next one. + */ + if (request->signaling.wait.seqno) { + if (request == rcu_access_pointer(b->first_signal)) { + struct rb_node *rb = rb_next(&request->signaling.node); + rcu_assign_pointer(b->first_signal, + rb ? to_signaler(rb) : NULL); + } + + rb_erase(&request->signaling.node, &b->signals); + request->signaling.wait.seqno = 0; + } +} + +static struct drm_i915_gem_request * +get_first_signal_rcu(struct intel_breadcrumbs *b) +{ + /* + * See the big warnings for i915_gem_active_get_rcu() and similarly + * for dma_fence_get_rcu_safe() that explain the intricacies involved + * here with defeating CPU/compiler speculation and enforcing + * the required memory barriers. + */ + do { + struct drm_i915_gem_request *request; + + request = rcu_dereference(b->first_signal); + if (request) + request = i915_gem_request_get_rcu(request); + + barrier(); + + if (!request || request == rcu_access_pointer(b->first_signal)) + return rcu_pointer_handoff(request); + + i915_gem_request_put(request); + } while (1); +} + static int intel_breadcrumbs_signaler(void *arg) { struct intel_engine_cs *engine = arg; @@ -656,41 +705,21 @@ static int intel_breadcrumbs_signaler(void *arg) * a new client. */ rcu_read_lock(); - request = rcu_dereference(b->first_signal); - if (request) - request = i915_gem_request_get_rcu(request); + request = get_first_signal_rcu(b); rcu_read_unlock(); if (signal_complete(request)) { - local_bh_disable(); - dma_fence_signal(&request->fence); - local_bh_enable(); /* kick start the tasklets */ - - spin_lock_irq(&b->rb_lock); - - /* Wake up all other completed waiters and select the - * next bottom-half for the next user interrupt. - */ - __intel_engine_remove_wait(engine, - &request->signaling.wait); - - /* Find the next oldest signal. Note that as we have - * not been holding the lock, another client may - * have installed an even older signal than the one - * we just completed - so double check we are still - * the oldest before picking the next one. - */ - if (request == rcu_access_pointer(b->first_signal)) { - struct rb_node *rb = - rb_next(&request->signaling.node); - rcu_assign_pointer(b->first_signal, - rb ? to_signaler(rb) : NULL); + if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, + &request->fence.flags)) { + local_bh_disable(); + dma_fence_signal(&request->fence); + local_bh_enable(); /* kick start the tasklets */ } - rb_erase(&request->signaling.node, &b->signals); - RB_CLEAR_NODE(&request->signaling.node); - spin_unlock_irq(&b->rb_lock); - - i915_gem_request_put(request); + if (READ_ONCE(request->signaling.wait.seqno)) { + spin_lock_irq(&b->rb_lock); + __intel_engine_remove_signal(engine, request); + spin_unlock_irq(&b->rb_lock); + } /* If the engine is saturated we may be continually * processing completed requests. This angers the @@ -701,19 +730,17 @@ static int intel_breadcrumbs_signaler(void *arg) */ do_schedule = need_resched(); } + i915_gem_request_put(request); if (unlikely(do_schedule)) { if (kthread_should_park()) kthread_parkme(); - if (unlikely(kthread_should_stop())) { - i915_gem_request_put(request); + if (unlikely(kthread_should_stop())) break; - } schedule(); } - i915_gem_request_put(request); } while (1); __set_current_state(TASK_RUNNING); @@ -742,12 +769,12 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request, if (!seqno) return; + spin_lock(&b->rb_lock); + + GEM_BUG_ON(request->signaling.wait.seqno); request->signaling.wait.tsk = b->signaler; request->signaling.wait.request = request; request->signaling.wait.seqno = seqno; - i915_gem_request_get(request); - - spin_lock(&b->rb_lock); /* First add ourselves into the list of waiters, but register our * bottom-half as the signaller thread. As per usual, only the oldest @@ -786,7 +813,7 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request, rcu_assign_pointer(b->first_signal, request); } else { __intel_engine_remove_wait(engine, &request->signaling.wait); - i915_gem_request_put(request); + request->signaling.wait.seqno = 0; wakeup = false; } @@ -798,32 +825,17 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request, void intel_engine_cancel_signaling(struct drm_i915_gem_request *request) { - struct intel_engine_cs *engine = request->engine; - struct intel_breadcrumbs *b = &engine->breadcrumbs; - GEM_BUG_ON(!irqs_disabled()); lockdep_assert_held(&request->lock); - GEM_BUG_ON(!request->signaling.wait.seqno); - spin_lock(&b->rb_lock); + if (READ_ONCE(request->signaling.wait.seqno)) { + struct intel_engine_cs *engine = request->engine; + struct intel_breadcrumbs *b = &engine->breadcrumbs; - if (!RB_EMPTY_NODE(&request->signaling.node)) { - if (request == rcu_access_pointer(b->first_signal)) { - struct rb_node *rb = - rb_next(&request->signaling.node); - rcu_assign_pointer(b->first_signal, - rb ? to_signaler(rb) : NULL); - } - rb_erase(&request->signaling.node, &b->signals); - RB_CLEAR_NODE(&request->signaling.node); - i915_gem_request_put(request); + spin_lock(&b->rb_lock); + __intel_engine_remove_signal(engine, request); + spin_unlock(&b->rb_lock); } - - __intel_engine_remove_wait(engine, &request->signaling.wait); - - spin_unlock(&b->rb_lock); - - request->signaling.wait.seqno = 0; } int intel_engine_init_breadcrumbs(struct intel_engine_cs *engine) From a8b66f2c2f3e03b70a5e72cb5034f8aff669bf34 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 Feb 2018 15:24:28 +0000 Subject: [PATCH 149/158] drm/i915/selftests: Flush old resets between engines When injecting rapid resets, we must be careful to at least wait for the previous reset to have taken effect and the engine restarted. If we perform a second reset before that has happened, we will notice that the engine hasn't recovered and declare it lost, wedging the device and failing. In practice, since we wait for each hanging batch to start before injecting the reset, this too-fast-reset condition can only be triggered when moving onto the next engine in the test, so we need only wait for the existing reset to complete before switching engines. v2: Wrap up the wait inside a safety net to bail out in case of angry hw. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Michel Thierry Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180205152431.12163-1-chris@chris-wilson.co.uk --- .../gpu/drm/i915/selftests/intel_hangcheck.c | 66 ++++++++++++++++++- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index d1f91a533afa..a42c539c1efe 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -244,6 +244,58 @@ static u32 hws_seqno(const struct hang *h, return READ_ONCE(h->seqno[rq->fence.context % (PAGE_SIZE/sizeof(u32))]); } +struct wedge_me { + struct delayed_work work; + struct drm_i915_private *i915; + const void *symbol; +}; + +static void wedge_me(struct work_struct *work) +{ + struct wedge_me *w = container_of(work, typeof(*w), work.work); + + pr_err("%pS timed out, cancelling all further testing.\n", + w->symbol); + i915_gem_set_wedged(w->i915); +} + +static void __init_wedge(struct wedge_me *w, + struct drm_i915_private *i915, + long timeout, + const void *symbol) +{ + w->i915 = i915; + w->symbol = symbol; + + INIT_DELAYED_WORK_ONSTACK(&w->work, wedge_me); + schedule_delayed_work(&w->work, timeout); +} + +static void __fini_wedge(struct wedge_me *w) +{ + cancel_delayed_work_sync(&w->work); + destroy_delayed_work_on_stack(&w->work); + w->i915 = NULL; +} + +#define wedge_on_timeout(W, DEV, TIMEOUT) \ + for (__init_wedge((W), (DEV), (TIMEOUT), __builtin_return_address(0)); \ + (W)->i915; \ + __fini_wedge((W))) + +static noinline int +flush_test(struct drm_i915_private *i915, unsigned int flags) +{ + struct wedge_me w; + + cond_resched(); + + wedge_on_timeout(&w, i915, HZ) + i915_gem_wait_for_idle(i915, flags); + + return i915_terminally_wedged(&i915->gpu_error) ? -EIO : 0; +} + static void hang_fini(struct hang *h) { *h->batch = MI_BATCH_BUFFER_END; @@ -255,7 +307,7 @@ static void hang_fini(struct hang *h) i915_gem_object_unpin_map(h->hws); i915_gem_object_put(h->hws); - i915_gem_wait_for_idle(h->i915, I915_WAIT_LOCKED); + flush_test(h->i915, I915_WAIT_LOCKED); } static bool wait_for_hang(struct hang *h, struct drm_i915_gem_request *rq) @@ -487,7 +539,9 @@ static int __igt_reset_engine(struct drm_i915_private *i915, bool active) if (err) break; - cond_resched(); + err = flush_test(i915, 0); + if (err) + break; } if (i915_terminally_wedged(&i915->gpu_error)) @@ -726,7 +780,9 @@ unwind: if (err) break; - cond_resched(); + err = flush_test(i915, 0); + if (err) + break; } if (i915_terminally_wedged(&i915->gpu_error)) @@ -952,6 +1008,10 @@ static int igt_reset_queue(void *arg) i915_gem_chipset_flush(i915); i915_gem_request_put(prev); + + err = flush_test(i915, I915_WAIT_LOCKED); + if (err) + break; } fini: From 8ec21a7c4b52165211b47932c665ab2e9ca488ee Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 Feb 2018 15:24:29 +0000 Subject: [PATCH 150/158] drm/i915/selftests: Use a sacrificial context for hang testing Avoid injecting hangs in to the i915->kernel_context in case the GPU reset leaves corruption in the context image in its wake (leading to continual failures and system hangs after the selftests are ostensibly complete). Use a sacrificial kernel_context instead. v2: Closing a context is tricky; export a function (for selftests) from i915_gem_context.c to get it right. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Michel Thierry Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180205152431.12163-2-chris@chris-wilson.co.uk --- .../gpu/drm/i915/selftests/intel_hangcheck.c | 39 +++++++++++-------- drivers/gpu/drm/i915/selftests/mock_context.c | 11 ++++++ drivers/gpu/drm/i915/selftests/mock_context.h | 3 ++ 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index a42c539c1efe..d1d2c2456f69 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -33,6 +33,7 @@ struct hang { struct drm_i915_private *i915; struct drm_i915_gem_object *hws; struct drm_i915_gem_object *obj; + struct i915_gem_context *ctx; u32 *seqno; u32 *batch; }; @@ -45,9 +46,15 @@ static int hang_init(struct hang *h, struct drm_i915_private *i915) memset(h, 0, sizeof(*h)); h->i915 = i915; + h->ctx = kernel_context(i915); + if (IS_ERR(h->ctx)) + return PTR_ERR(h->ctx); + h->hws = i915_gem_object_create_internal(i915, PAGE_SIZE); - if (IS_ERR(h->hws)) - return PTR_ERR(h->hws); + if (IS_ERR(h->hws)) { + err = PTR_ERR(h->hws); + goto err_ctx; + } h->obj = i915_gem_object_create_internal(i915, PAGE_SIZE); if (IS_ERR(h->obj)) { @@ -79,6 +86,8 @@ err_obj: i915_gem_object_put(h->obj); err_hws: i915_gem_object_put(h->hws); +err_ctx: + kernel_context_close(h->ctx); return err; } @@ -196,9 +205,7 @@ unpin_vma: } static struct drm_i915_gem_request * -hang_create_request(struct hang *h, - struct intel_engine_cs *engine, - struct i915_gem_context *ctx) +hang_create_request(struct hang *h, struct intel_engine_cs *engine) { struct drm_i915_gem_request *rq; int err; @@ -225,7 +232,7 @@ hang_create_request(struct hang *h, h->batch = vaddr; } - rq = i915_gem_request_alloc(engine, ctx); + rq = i915_gem_request_alloc(engine, h->ctx); if (IS_ERR(rq)) return rq; @@ -307,6 +314,8 @@ static void hang_fini(struct hang *h) i915_gem_object_unpin_map(h->hws); i915_gem_object_put(h->hws); + kernel_context_close(h->ctx); + flush_test(h->i915, I915_WAIT_LOCKED); } @@ -342,7 +351,7 @@ static int igt_hang_sanitycheck(void *arg) if (!intel_engine_can_store_dword(engine)) continue; - rq = hang_create_request(&h, engine, i915->kernel_context); + rq = hang_create_request(&h, engine); if (IS_ERR(rq)) { err = PTR_ERR(rq); pr_err("Failed to create request for %s, err=%d\n", @@ -479,8 +488,7 @@ static int __igt_reset_engine(struct drm_i915_private *i915, bool active) struct drm_i915_gem_request *rq; mutex_lock(&i915->drm.struct_mutex); - rq = hang_create_request(&h, engine, - i915->kernel_context); + rq = hang_create_request(&h, engine); if (IS_ERR(rq)) { err = PTR_ERR(rq); mutex_unlock(&i915->drm.struct_mutex); @@ -687,8 +695,7 @@ static int __igt_reset_engine_others(struct drm_i915_private *i915, struct drm_i915_gem_request *rq; mutex_lock(&i915->drm.struct_mutex); - rq = hang_create_request(&h, engine, - i915->kernel_context); + rq = hang_create_request(&h, engine); if (IS_ERR(rq)) { err = PTR_ERR(rq); mutex_unlock(&i915->drm.struct_mutex); @@ -843,7 +850,7 @@ static int igt_wait_reset(void *arg) if (err) goto unlock; - rq = hang_create_request(&h, i915->engine[RCS], i915->kernel_context); + rq = hang_create_request(&h, i915->engine[RCS]); if (IS_ERR(rq)) { err = PTR_ERR(rq); goto fini; @@ -922,7 +929,7 @@ static int igt_reset_queue(void *arg) if (!intel_engine_can_store_dword(engine)) continue; - prev = hang_create_request(&h, engine, i915->kernel_context); + prev = hang_create_request(&h, engine); if (IS_ERR(prev)) { err = PTR_ERR(prev); goto fini; @@ -936,9 +943,7 @@ static int igt_reset_queue(void *arg) struct drm_i915_gem_request *rq; unsigned int reset_count; - rq = hang_create_request(&h, - engine, - i915->kernel_context); + rq = hang_create_request(&h, engine); if (IS_ERR(rq)) { err = PTR_ERR(rq); goto fini; @@ -1049,7 +1054,7 @@ static int igt_handle_error(void *arg) if (err) goto err_unlock; - rq = hang_create_request(&h, engine, i915->kernel_context); + rq = hang_create_request(&h, engine); if (IS_ERR(rq)) { err = PTR_ERR(rq); goto err_fini; diff --git a/drivers/gpu/drm/i915/selftests/mock_context.c b/drivers/gpu/drm/i915/selftests/mock_context.c index bbf80d42e793..501becc47c0c 100644 --- a/drivers/gpu/drm/i915/selftests/mock_context.c +++ b/drivers/gpu/drm/i915/selftests/mock_context.c @@ -92,3 +92,14 @@ live_context(struct drm_i915_private *i915, struct drm_file *file) return i915_gem_create_context(i915, file->driver_priv); } + +struct i915_gem_context * +kernel_context(struct drm_i915_private *i915) +{ + return i915_gem_context_create_kernel(i915, I915_PRIORITY_NORMAL); +} + +void kernel_context_close(struct i915_gem_context *ctx) +{ + context_close(ctx); +} diff --git a/drivers/gpu/drm/i915/selftests/mock_context.h b/drivers/gpu/drm/i915/selftests/mock_context.h index 2f432c03d413..29b9d60a158b 100644 --- a/drivers/gpu/drm/i915/selftests/mock_context.h +++ b/drivers/gpu/drm/i915/selftests/mock_context.h @@ -36,4 +36,7 @@ void mock_context_close(struct i915_gem_context *ctx); struct i915_gem_context * live_context(struct drm_i915_private *i915, struct drm_file *file); +struct i915_gem_context *kernel_context(struct drm_i915_private *i915); +void kernel_context_close(struct i915_gem_context *ctx); + #endif /* !__MOCK_CONTEXT_H */ From e840130a25a7fbe1520f32b6113e0fd68af0fb54 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 Feb 2018 15:24:30 +0000 Subject: [PATCH 151/158] drm/i915/execlists: Move the reset bits to a more natural home In preparation for the next patch, we want the engine to appear idle after a reset (if there are no requests in flight). For execlists, this entails clearing the active status on reset, it will be regenerated on restarting the engine after the reset. In the process, note that a couple of other status flags and checks could be moved into the describing function. Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180205152431.12163-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index afc41dbc872e..adf257dfa5e0 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1462,6 +1462,9 @@ static void enable_execlists(struct intel_engine_cs *engine) I915_WRITE(RING_HWS_PGA(engine->mmio_base), engine->status_page.ggtt_offset); POSTING_READ(RING_HWS_PGA(engine->mmio_base)); + + /* Following the reset, we need to reload the CSB read/write pointers */ + engine->execlists.csb_head = -1; } static int gen8_init_common_ring(struct intel_engine_cs *engine) @@ -1478,11 +1481,6 @@ static int gen8_init_common_ring(struct intel_engine_cs *engine) enable_execlists(engine); - GEM_BUG_ON(engine->id >= ARRAY_SIZE(gtiir)); - - execlists->csb_head = -1; - execlists->active = 0; - /* After a GPU reset, we may have requests to replay */ if (execlists->first) tasklet_schedule(&execlists->tasklet); @@ -1528,6 +1526,8 @@ static void reset_irq(struct intel_engine_cs *engine) struct drm_i915_private *dev_priv = engine->i915; int i; + GEM_BUG_ON(engine->id >= ARRAY_SIZE(gtiir)); + /* * Clear any pending interrupt state. * @@ -1576,6 +1576,9 @@ static void reset_common_ring(struct intel_engine_cs *engine, spin_unlock_irqrestore(&engine->timeline->lock, flags); + /* Mark all CS interrupts as complete */ + execlists->active = 0; + /* If the request was innocent, we leave the request in the ELSP * and will try to replay it on restarting. The context image may * have been corrupted by the reset, in which case we may have From 01b8fdc5222007bdfc905941173f82576898a7f7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 Feb 2018 15:24:31 +0000 Subject: [PATCH 152/158] drm/i915: Skip post-reset request emission if the engine is not idle Since commit 7b6da818d86f ("drm/i915: Restore the kernel context after a GPU reset on an idle engine") we submit a request following the engine reset. The intent is that we don't submit a request if the engine is busy (as it will restart active by itself) but we only checked to see if there were remaining requests in flight on the hardware and skipped checking to see if there were any ready requests that would be immediately submitted on restart (the same time as our new request would be). Having convinced the engine to appear idle in the previous patch, we can use intel_engine_is_idle() as a better test to only submit a new request if there are no pending requests. As it happens, this is tripping up igt/drv_selftest/live_hangcheck in CI as we overfill the kernel_context ringbuffer trigger an infinite recursion from within the reset. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104786 References: 7b6da818d86f ("drm/i915: Restore the kernel context after a GPU reset on an idle engine") Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Joonas Lahtinen Cc: Michel Thierry Reviewed-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20180205152431.12163-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f3cc40a7aa5c..1632f18e6a64 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3133,7 +3133,7 @@ void i915_gem_reset(struct drm_i915_private *dev_priv) * an incoherent read by the CS (presumably stale TLB). An * empty request appears sufficient to paper over the glitch. */ - if (list_empty(&engine->timeline->requests)) { + if (intel_engine_is_idle(engine)) { struct drm_i915_gem_request *rq; rq = i915_gem_request_alloc(engine, From 6ec5bd348934887494541bcc9b53d621b1f2962c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 2 Feb 2018 22:42:31 +0200 Subject: [PATCH 153/158] drm/i915: Deprecate I915_SET_COLORKEY_NONE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deprecate the silly I915_SET_COLORKEY_NONE flag. The obvious way to disable colorkey is to just set flags to 0, which is exactly what the intel ddx has been doing all along. Currently when userspace sets the flags to 0, we end up in a funny state where colorkey is disabled, but various colorkey vs. scaling checks still consider colorkey to be enabled, and thus we don't allow plane scaling to kick in. In case there is some other userspace out there that actually uses this flag (unlikely as this is an i915 specific uapi) we'll keep on accepting it. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180202204231.27905-1-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/intel_atomic_plane.c | 1 - drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_sprite.c | 5 ++++- include/uapi/drm/i915_drm.h | 4 +++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 8e6dc159f64d..57ee8b786cd8 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -56,7 +56,6 @@ intel_create_plane_state(struct drm_plane *plane) state->base.plane = plane; state->base.rotation = DRM_MODE_ROTATE_0; - state->ckey.flags = I915_SET_COLORKEY_NONE; return state; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e79b9242eb66..e9bba2ab4904 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4787,7 +4787,7 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, return ret; /* check colorkey */ - if (plane_state->ckey.flags != I915_SET_COLORKEY_NONE) { + if (plane_state->ckey.flags) { DRM_DEBUG_KMS("[PLANE:%d:%s] scaling with color key not allowed", intel_plane->base.base.id, intel_plane->base.name); @@ -12788,7 +12788,7 @@ intel_check_primary_plane(struct intel_plane *plane, if (INTEL_GEN(dev_priv) >= 9) { /* use scaler when colorkey is not required */ - if (state->ckey.flags == I915_SET_COLORKEY_NONE) { + if (!state->ckey.flags) { min_scale = 1; max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state); } diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 630d20eecf3c..32f10621fac8 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -894,7 +894,7 @@ intel_check_sprite_plane(struct intel_plane *plane, /* setup can_scale, min_scale, max_scale */ if (INTEL_GEN(dev_priv) >= 9) { /* use scaler when colorkey is not required */ - if (state->ckey.flags == I915_SET_COLORKEY_NONE) { + if (!state->ckey.flags) { can_scale = 1; min_scale = 1; max_scale = skl_max_scale(crtc, crtc_state); @@ -1070,6 +1070,9 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_modeset_acquire_ctx ctx; int ret = 0; + /* ignore the pointless "none" flag */ + set->flags &= ~I915_SET_COLORKEY_NONE; + /* Make sure we don't try to enable both src & dest simultaneously */ if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) return -EINVAL; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 536ee4febd74..29fa48e4755d 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -1358,7 +1358,9 @@ struct drm_intel_overlay_attrs { * active on a given plane. */ -#define I915_SET_COLORKEY_NONE (1<<0) /* disable color key matching */ +#define I915_SET_COLORKEY_NONE (1<<0) /* Deprecated. Instead set + * flags==0 to disable colorkeying. + */ #define I915_SET_COLORKEY_DESTINATION (1<<1) #define I915_SET_COLORKEY_SOURCE (1<<2) struct drm_intel_sprite_colorkey { From 2f265fad9756a40c09e3f4dcc62d5d7fa73a9fb2 Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Mon, 5 Feb 2018 16:04:37 +0000 Subject: [PATCH 154/158] drm/i915/cmdparser: Check reg_table_count before derefencing. The find_reg function was assuming that there is always at least one table in reg_tables. It is not always true. In case of VCS or VECS, the reg_tables is NULL and reg_table_count is 0, implying that no register-accessing commands are allowed. However, the command tables include commands such as MI_STORE_REGISTER_MEM. When trying to check such command, the find_reg would dereference NULL pointer. Now it will just return NULL meaning that the register was not found and the command will be rejected. Fixes: 76ff480ec963 ("drm/i915/cmdparser: Use binary search for faster register lookup") Signed-off-by: Michal Srb Link: https://patchwork.freedesktop.org/patch/msgid/20180205142916.27092-2-msrb@suse.com Cc: Chris Wilson Cc: Matthew Auld Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180205160438.3267-1-chris@chris-wilson.co.uk register lookup") --- drivers/gpu/drm/i915/i915_cmd_parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index ccb5ba043b63..ab4c8b0ec886 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -1032,7 +1032,7 @@ find_reg(const struct intel_engine_cs *engine, bool is_master, u32 addr) const struct drm_i915_reg_table *table = engine->reg_tables; int count = engine->reg_table_count; - do { + for (; count > 0; ++table, --count) { if (!table->master || is_master) { const struct drm_i915_reg_descriptor *reg; @@ -1040,7 +1040,7 @@ find_reg(const struct intel_engine_cs *engine, bool is_master, u32 addr) if (reg != NULL) return reg; } - } while (table++, --count); + } return NULL; } From 3aec7f871c65eb5f76b4125fda432593c834a6f2 Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Mon, 5 Feb 2018 16:04:38 +0000 Subject: [PATCH 155/158] drm/i915/cmdparser: Do not check past the cmd length. The command MEDIA_VFE_STATE checks bits at offset +2 dwords. However, it is possible to have MEDIA_VFE_STATE command with length = 0 + LENGTH_BIAS = 2. In that case check_cmd will read bits from the following command, or even past the end of the buffer. If the offset ends up outside of the command length, reject the command. Fixes: 351e3db2b363 ("drm/i915: Implement command buffer parsing logic") Signed-off-by: Michal Srb Link: https://patchwork.freedesktop.org/patch/msgid/20180205151745.29292-1-msrb@suse.com Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180205160438.3267-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_cmd_parser.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index ab4c8b0ec886..95478db9998b 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -1212,6 +1212,12 @@ static bool check_cmd(const struct intel_engine_cs *engine, continue; } + if (desc->bits[i].offset >= length) { + DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X, too short to check bitmask (%s)\n", + *cmd, engine->name); + return false; + } + dword = cmd[desc->bits[i].offset] & desc->bits[i].mask; From 4b6ce6810a5dc0af387a238e8c852e0d3822381f Mon Sep 17 00:00:00 2001 From: Rafael Antognolli Date: Mon, 5 Feb 2018 15:33:30 -0800 Subject: [PATCH 156/158] drm/i915/cnl: WaPipeControlBefore3DStateSamplePattern This workaround should prevent a bug that can be hit on a context restore. To avoid the issue, we must emit a PIPE_CONTROL with CS stall (0x7a000004 0x00100000 0x00000000 0x00000000) followed by 12DW's of NOOP(0x0) in the indirect context batch buffer, to ensure the engine is idle prior to programming 3DSTATE_SAMPLE_PATTERN. It's also not clear whether we should add those extra dwords because of the workaround itself, or if that's just padding for the WA BB (and next commands could come right after the PIPE_CONTROL). We keep them for now. References: HSD#1939868 v2: More descriptive changelog and comments. v3: Explain that PIPE_CONTROL is actually 6 dwords, and that we advance 10 more dwords because of that. Signed-off-by: Rafael Antognolli Cc: Chris Wilson Acked-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180205233330.14973-1-rafael.antognolli@intel.com --- drivers/gpu/drm/i915/intel_lrc.c | 38 +++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index adf257dfa5e0..380c0838d8b3 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1328,6 +1328,40 @@ static u32 *gen9_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch) return batch; } +static u32 * +gen10_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch) +{ + int i; + + /* + * WaPipeControlBefore3DStateSamplePattern: cnl + * + * Ensure the engine is idle prior to programming a + * 3DSTATE_SAMPLE_PATTERN during a context restore. + */ + batch = gen8_emit_pipe_control(batch, + PIPE_CONTROL_CS_STALL, + 0); + /* + * WaPipeControlBefore3DStateSamplePattern says we need 4 dwords for + * the PIPE_CONTROL followed by 12 dwords of 0x0, so 16 dwords in + * total. However, a PIPE_CONTROL is 6 dwords long, not 4, which is + * confusing. Since gen8_emit_pipe_control() already advances the + * batch by 6 dwords, we advance the other 10 here, completing a + * cacheline. It's not clear if the workaround requires this padding + * before other commands, or if it's just the regular padding we would + * already have for the workaround bb, so leave it here for now. + */ + for (i = 0; i < 10; i++) + *batch++ = MI_NOOP; + + /* Pad to end of cacheline */ + while ((unsigned long)batch % CACHELINE_BYTES) + *batch++ = MI_NOOP; + + return batch; +} + #define CTX_WA_BB_OBJ_SIZE (PAGE_SIZE) static int lrc_setup_wa_ctx(struct intel_engine_cs *engine) @@ -1381,7 +1415,9 @@ static int intel_init_workaround_bb(struct intel_engine_cs *engine) switch (INTEL_GEN(engine->i915)) { case 10: - return 0; + wa_bb_fn[0] = gen10_init_indirectctx_bb; + wa_bb_fn[1] = NULL; + break; case 9: wa_bb_fn[0] = gen9_init_indirectctx_bb; wa_bb_fn[1] = NULL; From b2f78cda260bc6a1a2d382b1d85a29e69b5b3724 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Mon, 5 Feb 2018 09:34:48 +0000 Subject: [PATCH 157/158] drm/i915/pmu: Fix PMU enable vs execlists tasklet race Commit 99e48bf98dd0 ("drm/i915: Lock out execlist tasklet while peeking inside for busy-stats") added a tasklet_disable call in busy stats enabling, but we failed to understand that the PMU enable callback runs as an hard IRQ (IPI). Consequence of this is that the PMU enable callback can interrupt the execlists tasklet, and will then deadlock when it calls intel_engine_stats_enable->tasklet_disable. To fix this, I realized it is possible to move the engine stats enablement and disablement to PMU event init and destroy hooks. This allows for much simpler implementation since those hooks run in normal context (can sleep). v2: Extract engine_event_destroy. (Chris Wilson) Signed-off-by: Tvrtko Ursulin Fixes: 99e48bf98dd0 ("drm/i915: Lock out execlist tasklet while peeking inside for busy-stats") Testcase: igt/perf_pmu/enable-race-* Cc: Chris Wilson Cc: Tvrtko Ursulin Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: intel-gfx@lists.freedesktop.org Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180205093448.13877-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 98 +++++++++---------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 14 ---- 2 files changed, 34 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index ecb0198bfb7a..1c440460255d 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -285,9 +285,29 @@ static u64 count_interrupts(struct drm_i915_private *i915) return sum; } +static void engine_event_destroy(struct perf_event *event) +{ + struct drm_i915_private *i915 = + container_of(event->pmu, typeof(*i915), pmu.base); + struct intel_engine_cs *engine; + + engine = intel_engine_lookup_user(i915, + engine_event_class(event), + engine_event_instance(event)); + if (WARN_ON_ONCE(!engine)) + return; + + if (engine_event_sample(event) == I915_SAMPLE_BUSY && + intel_engine_supports_stats(engine)) + intel_disable_engine_stats(engine); +} + static void i915_pmu_event_destroy(struct perf_event *event) { WARN_ON(event->parent); + + if (is_engine_event(event)) + engine_event_destroy(event); } static int @@ -340,13 +360,23 @@ static int engine_event_init(struct perf_event *event) struct drm_i915_private *i915 = container_of(event->pmu, typeof(*i915), pmu.base); struct intel_engine_cs *engine; + u8 sample; + int ret; engine = intel_engine_lookup_user(i915, engine_event_class(event), engine_event_instance(event)); if (!engine) return -ENODEV; - return engine_event_status(engine, engine_event_sample(event)); + sample = engine_event_sample(event); + ret = engine_event_status(engine, sample); + if (ret) + return ret; + + if (sample == I915_SAMPLE_BUSY && intel_engine_supports_stats(engine)) + ret = intel_enable_engine_stats(engine); + + return ret; } static int i915_pmu_event_init(struct perf_event *event) @@ -402,7 +432,7 @@ static u64 __i915_pmu_event_read(struct perf_event *event) if (WARN_ON_ONCE(!engine)) { /* Do nothing */ } else if (sample == I915_SAMPLE_BUSY && - engine->pmu.busy_stats) { + intel_engine_supports_stats(engine)) { val = ktime_to_ns(intel_engine_get_busy_time(engine)); } else { val = engine->pmu.sample[sample].cur; @@ -457,12 +487,6 @@ again: local64_add(new - prev, &event->count); } -static bool engine_needs_busy_stats(struct intel_engine_cs *engine) -{ - return intel_engine_supports_stats(engine) && - (engine->pmu.enable & BIT(I915_SAMPLE_BUSY)); -} - static void i915_pmu_enable(struct perf_event *event) { struct drm_i915_private *i915 = @@ -502,21 +526,7 @@ static void i915_pmu_enable(struct perf_event *event) GEM_BUG_ON(sample >= I915_PMU_SAMPLE_BITS); GEM_BUG_ON(engine->pmu.enable_count[sample] == ~0); - if (engine->pmu.enable_count[sample]++ == 0) { - /* - * Enable engine busy stats tracking if needed or - * alternatively cancel the scheduled disable. - * - * If the delayed disable was pending, cancel it and - * in this case do not enable since it already is. - */ - if (engine_needs_busy_stats(engine) && - !engine->pmu.busy_stats) { - engine->pmu.busy_stats = true; - if (!cancel_delayed_work(&engine->pmu.disable_busy_stats)) - intel_enable_engine_stats(engine); - } - } + engine->pmu.enable_count[sample]++; } /* @@ -529,14 +539,6 @@ static void i915_pmu_enable(struct perf_event *event) spin_unlock_irqrestore(&i915->pmu.lock, flags); } -static void __disable_busy_stats(struct work_struct *work) -{ - struct intel_engine_cs *engine = - container_of(work, typeof(*engine), pmu.disable_busy_stats.work); - - intel_disable_engine_stats(engine); -} - static void i915_pmu_disable(struct perf_event *event) { struct drm_i915_private *i915 = @@ -560,26 +562,8 @@ static void i915_pmu_disable(struct perf_event *event) * Decrement the reference count and clear the enabled * bitmask when the last listener on an event goes away. */ - if (--engine->pmu.enable_count[sample] == 0) { + if (--engine->pmu.enable_count[sample] == 0) engine->pmu.enable &= ~BIT(sample); - if (!engine_needs_busy_stats(engine) && - engine->pmu.busy_stats) { - engine->pmu.busy_stats = false; - /* - * We request a delayed disable to handle the - * rapid on/off cycles on events, which can - * happen when tools like perf stat start, in a - * nicer way. - * - * In addition, this also helps with busy stats - * accuracy with background CPU offline/online - * migration events. - */ - queue_delayed_work(system_wq, - &engine->pmu.disable_busy_stats, - round_jiffies_up_relative(HZ)); - } - } } GEM_BUG_ON(bit >= I915_PMU_MASK_BITS); @@ -956,8 +940,6 @@ static void i915_pmu_unregister_cpuhp_state(struct drm_i915_private *i915) void i915_pmu_register(struct drm_i915_private *i915) { - struct intel_engine_cs *engine; - enum intel_engine_id id; int ret; if (INTEL_GEN(i915) <= 2) { @@ -985,10 +967,6 @@ void i915_pmu_register(struct drm_i915_private *i915) hrtimer_init(&i915->pmu.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); i915->pmu.timer.function = i915_sample; - for_each_engine(engine, i915, id) - INIT_DELAYED_WORK(&engine->pmu.disable_busy_stats, - __disable_busy_stats); - ret = perf_pmu_register(&i915->pmu.base, "i915", -1); if (ret) goto err; @@ -1009,9 +987,6 @@ err: void i915_pmu_unregister(struct drm_i915_private *i915) { - struct intel_engine_cs *engine; - enum intel_engine_id id; - if (!i915->pmu.base.event_init) return; @@ -1019,11 +994,6 @@ void i915_pmu_unregister(struct drm_i915_private *i915) hrtimer_cancel(&i915->pmu.timer); - for_each_engine(engine, i915, id) { - GEM_BUG_ON(engine->pmu.busy_stats); - flush_delayed_work(&engine->pmu.disable_busy_stats); - } - i915_pmu_unregister_cpuhp_state(i915); perf_pmu_unregister(&i915->pmu.base); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index c5ff203e42d6..a0e7a6c2a57c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -366,20 +366,6 @@ struct intel_engine_cs { */ #define I915_ENGINE_SAMPLE_MAX (I915_SAMPLE_SEMA + 1) struct i915_pmu_sample sample[I915_ENGINE_SAMPLE_MAX]; - /** - * @busy_stats: Has enablement of engine stats tracking been - * requested. - */ - bool busy_stats; - /** - * @disable_busy_stats: Work item for busy stats disabling. - * - * Same as with @enable_busy_stats action, with the difference - * that we delay it in case there are rapid enable-disable - * actions, which can happen during tool startup (like perf - * stat). - */ - struct delayed_work disable_busy_stats; } pmu; /* From 2f2f2db86d63605b1f57780ead21d4968e9d0bf3 Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Wed, 7 Feb 2018 09:26:04 +0200 Subject: [PATCH 158/158] drm/i915: Update DRIVER_DATE to 20180207 Signed-off-by: Joonas Lahtinen --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a241620f22ad..60079a69c2f9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -83,8 +83,8 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20171222" -#define DRIVER_TIMESTAMP 1513971710 +#define DRIVER_DATE "20180207" +#define DRIVER_TIMESTAMP 1517988364 /* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and * WARN_ON()) for hw state sanity checks to check for unexpected conditions