From fa73055b8442c97b3ba7cd0aa57cd2ad32124201 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 7 Mar 2018 17:13:03 +0000 Subject: drm/i915: Only prune fences after wait-for-all Currently, we only allow ourselves to prune the fences so long as all the waits completed (i.e. all the fences we checked were signaled), and that the reservation snapshot did not change across the wait. However, if we only waited for a subset of the reservation object, i.e. just waiting for the last writer to complete as opposed to all readers as well, then we would erroneously conclude we could prune the fences as indeed although all of our waits were successful, they did not represent the totality of the reservation object. v2: We only need to check the shared fences due to construction (i.e. all of the shared fences will be later than the exclusive fence, if any). Fixes: e54ca9774777 ("drm/i915: Remove completed fences after a wait") Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Cc: Matthew Auld Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20180307171303.29466-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a5bd07338b46..ab88ca53c9a0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -433,20 +433,28 @@ i915_gem_object_wait_reservation(struct reservation_object *resv, dma_fence_put(shared[i]); kfree(shared); + /* + * If both shared fences and an exclusive fence exist, + * then by construction the shared fences must be later + * than the exclusive fence. If we successfully wait for + * all the shared fences, we know that the exclusive fence + * must all be signaled. If all the shared fences are + * signaled, we can prune the array and recover the + * floating references on the fences/requests. + */ prune_fences = count && timeout >= 0; } else { excl = reservation_object_get_excl_rcu(resv); } - if (excl && timeout >= 0) { + if (excl && timeout >= 0) timeout = i915_gem_object_wait_fence(excl, flags, timeout, rps_client); - prune_fences = timeout >= 0; - } dma_fence_put(excl); - /* Oportunistically prune the fences iff we know they have *all* been + /* + * Opportunistically prune the fences iff we know they have *all* been * signaled and that the reservation object has not been changed (i.e. * no new fences have been added). */ -- cgit v1.2.3 From 033b7a230cfa759d1b582fa46bf2cd54db406cf3 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 8 Mar 2018 13:02:02 +0100 Subject: drm/i915: Handle pipe CRC around enabling/disabling pipe. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will get rid of the following error: [ 74.730271] WARNING: CPU: 4 PID: 0 at drivers/gpu/drm/drm_vblank.c:614 drm_calc_vbltimestamp_from_scanoutpos+0x13e/0x2f0 [ 74.730311] Modules linked in: vgem snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic i915 x86_pkg_temp_thermal intel_powerclamp coretemp snd_hda_intel crct10dif_pclmul snd_hda_codec crc32_pclmul snd_hwdep broadcom ghash_clmulni_intel snd_hda_core bcm_phy_lib snd_pcm tg3 lpc_ich mei_me mei prime_numbers [ 74.730353] CPU: 4 PID: 0 Comm: swapper/4 Tainted: G U 4.16.0-rc2-CI-CI_DRM_3822+ #1 [ 74.730355] Hardware name: Dell Inc. XPS 8300 /0Y2MRG, BIOS A06 10/17/2011 [ 74.730359] RIP: 0010:drm_calc_vbltimestamp_from_scanoutpos+0x13e/0x2f0 [ 74.730361] RSP: 0018:ffff88022fb03d10 EFLAGS: 00010086 [ 74.730365] RAX: ffffffffa0291d20 RBX: ffff88021a180000 RCX: 0000000000000001 [ 74.730367] RDX: ffffffff820e7db8 RSI: 0000000000000001 RDI: ffffffff82068cea [ 74.730369] RBP: ffff88022fb03d70 R08: 0000000000000000 R09: ffffffff815d26d0 [ 74.730371] R10: 0000000000000000 R11: ffffffffa0161ca0 R12: 0000000000000001 [ 74.730373] R13: ffff880212448008 R14: ffff880212448330 R15: 0000000000000000 [ 74.730376] FS: 0000000000000000(0000) GS:ffff88022fb00000(0000) knlGS:0000000000000000 [ 74.730378] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 74.730380] CR2: 000055edcbec9000 CR3: 0000000002210001 CR4: 00000000000606e0 [ 74.730382] Call Trace: [ 74.730385] [ 74.730397] drm_get_last_vbltimestamp+0x36/0x50 [ 74.730401] drm_update_vblank_count+0x64/0x240 [ 74.730409] drm_crtc_accurate_vblank_count+0x41/0x90 [ 74.730453] display_pipe_crc_irq_handler+0x176/0x220 [i915] [ 74.730497] i9xx_pipe_crc_irq_handler+0xfe/0x150 [i915] [ 74.730537] ironlake_irq_handler+0x618/0xa30 [i915] [ 74.730548] __handle_irq_event_percpu+0x3c/0x340 [ 74.730556] handle_irq_event_percpu+0x1b/0x50 [ 74.730561] handle_irq_event+0x2f/0x50 [ 74.730566] handle_edge_irq+0xe4/0x1b0 [ 74.730572] handle_irq+0x11/0x20 [ 74.730576] do_IRQ+0x5e/0x120 [ 74.730584] common_interrupt+0x84/0x84 [ 74.730586] [ 74.730591] RIP: 0010:cpuidle_enter_state+0xaa/0x350 [ 74.730593] RSP: 0018:ffffc9000008beb8 EFLAGS: 00000212 ORIG_RAX: ffffffffffffffde [ 74.730597] RAX: ffff880226b80040 RBX: 000000000031fc3e RCX: 0000000000000001 [ 74.730599] RDX: 0000000000000000 RSI: ffffffff8210fb59 RDI: ffffffff820c02e7 [ 74.730601] RBP: 0000000000000004 R08: 00000000000040af R09: 0000000000000018 [ 74.730603] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000004 [ 74.730606] R13: ffffe8ffffd00430 R14: 0000001166120bf4 R15: ffffffff82294460 [ 74.730621] ? cpuidle_enter_state+0xa6/0x350 [ 74.730629] do_idle+0x188/0x1d0 [ 74.730636] cpu_startup_entry+0x14/0x20 [ 74.730641] start_secondary+0x129/0x160 [ 74.730646] secondary_startup_64+0xa5/0xb0 [ 74.730660] Code: e1 48 c7 c2 b8 7d 0e 82 be 01 00 00 00 48 c7 c7 ea 8c 06 82 e8 64 ec ff ff 48 8b 83 c8 07 00 00 48 83 78 28 00 0f 84 e2 fe ff ff <0f> 0b 45 31 ed e9 db fe ff ff 41 b8 d3 4d 62 10 89 c8 6a 03 41 [ 74.730754] ---[ end trace 14b1345705b68565 ]--- Changes since v1: - Don't try to apply CRC workaround when enabling pipe, it should already be enabled. Changes since v2: - Make crc functions for !DEBUGFS case inline. - Pass intel_crtc to crc functions. - Add comments to callsites. Changes since v3: - Cache selected source to pipe_crc->source. - Set pipe_crc->skipped to MIN_INT during disable to close a race condition. Changes since v4: - Handle fallout from setting pipe_crc->source in irq handler. Cc: Marta Löfstedt Reported-by: Marta Löfstedt Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105185 Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20180308120202.52446-1-maarten.lankhorst@linux.intel.com Reviewed-by: Ville Syrjälä --- drivers/gpu/drm/i915/i915_irq.c | 4 +-- drivers/gpu/drm/i915/intel_display.c | 10 +++++++ drivers/gpu/drm/i915/intel_drv.h | 9 ++++++ drivers/gpu/drm/i915/intel_pipe_crc.c | 53 ++++++++++++++++++++++++++++++----- 4 files changed, 67 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 633c18785c1e..babf81cf668b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1627,7 +1627,7 @@ static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv, int head, tail; spin_lock(&pipe_crc->lock); - if (pipe_crc->source) { + if (pipe_crc->source && !crtc->base.crc.opened) { if (!pipe_crc->entries) { spin_unlock(&pipe_crc->lock); DRM_DEBUG_KMS("spurious interrupt\n"); @@ -1667,7 +1667,7 @@ static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv, * On GEN8+ sometimes the second CRC is bonkers as well, so * don't trust that one either. */ - if (pipe_crc->skipped == 0 || + if (pipe_crc->skipped <= 0 || (INTEL_GEN(dev_priv) >= 8 && pipe_crc->skipped == 1)) { pipe_crc->skipped++; spin_unlock(&pipe_crc->lock); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ceed0821b37d..f424fff477f6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12145,6 +12145,9 @@ static void intel_update_crtc(struct drm_crtc *crtc, if (modeset) { update_scanline_offset(intel_crtc); dev_priv->display.crtc_enable(pipe_config, state); + + /* vblanks work again, re-enable pipe CRC. */ + intel_crtc_enable_pipe_crc(intel_crtc); } else { intel_pre_plane_update(to_intel_crtc_state(old_crtc_state), pipe_config); @@ -12325,6 +12328,13 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state) if (old_crtc_state->active) { intel_crtc_disable_planes(crtc, old_crtc_state->plane_mask); + + /* + * We need to disable pipe CRC before disabling the pipe, + * or we race against vblank off. + */ + intel_crtc_disable_pipe_crc(intel_crtc); + dev_priv->display.crtc_disable(to_intel_crtc_state(old_crtc_state), state); intel_crtc->active = false; intel_fbc_disable(intel_crtc); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 37d5412af8f5..83e5ca889d9c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -2136,8 +2136,17 @@ int intel_pipe_crc_create(struct drm_minor *minor); #ifdef CONFIG_DEBUG_FS int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name, size_t *values_cnt); +void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc); +void intel_crtc_enable_pipe_crc(struct intel_crtc *crtc); #else #define intel_crtc_set_crc_source NULL +static inline void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc) +{ +} + +static inline void intel_crtc_enable_pipe_crc(struct intel_crtc *crtc) +{ +} #endif extern const struct file_operations i915_display_crc_ctl_fops; #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_pipe_crc.c b/drivers/gpu/drm/i915/intel_pipe_crc.c index 1f5cd572a7ff..4f367c16e9e5 100644 --- a/drivers/gpu/drm/i915/intel_pipe_crc.c +++ b/drivers/gpu/drm/i915/intel_pipe_crc.c @@ -569,7 +569,8 @@ unlock: static int ivb_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv, enum pipe pipe, enum intel_pipe_crc_source *source, - uint32_t *val) + uint32_t *val, + bool set_wa) { if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) *source = INTEL_PIPE_CRC_SOURCE_PF; @@ -582,7 +583,7 @@ static int ivb_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv, *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_SPRITE_IVB; break; case INTEL_PIPE_CRC_SOURCE_PF: - if ((IS_HASWELL(dev_priv) || + if (set_wa && (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) && pipe == PIPE_A) hsw_pipe_A_crc_wa(dev_priv, true); @@ -600,7 +601,8 @@ static int ivb_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv, static int get_new_crc_ctl_reg(struct drm_i915_private *dev_priv, enum pipe pipe, - enum intel_pipe_crc_source *source, u32 *val) + enum intel_pipe_crc_source *source, u32 *val, + bool set_wa) { if (IS_GEN2(dev_priv)) return i8xx_pipe_crc_ctl_reg(source, val); @@ -611,7 +613,7 @@ static int get_new_crc_ctl_reg(struct drm_i915_private *dev_priv, else if (IS_GEN5(dev_priv) || IS_GEN6(dev_priv)) return ilk_pipe_crc_ctl_reg(source, val); else - return ivb_pipe_crc_ctl_reg(dev_priv, pipe, source, val); + return ivb_pipe_crc_ctl_reg(dev_priv, pipe, source, val, set_wa); } static int pipe_crc_set_source(struct drm_i915_private *dev_priv, @@ -636,7 +638,7 @@ static int pipe_crc_set_source(struct drm_i915_private *dev_priv, return -EIO; } - ret = get_new_crc_ctl_reg(dev_priv, pipe, &source, &val); + ret = get_new_crc_ctl_reg(dev_priv, pipe, &source, &val, true); if (ret != 0) goto out; @@ -916,7 +918,7 @@ int intel_pipe_crc_create(struct drm_minor *minor) int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name, size_t *values_cnt) { - struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(crtc->dev); struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[crtc->index]; enum intel_display_power_domain power_domain; enum intel_pipe_crc_source source; @@ -934,10 +936,11 @@ int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name, return -EIO; } - ret = get_new_crc_ctl_reg(dev_priv, crtc->index, &source, &val); + ret = get_new_crc_ctl_reg(dev_priv, crtc->index, &source, &val, true); if (ret != 0) goto out; + pipe_crc->source = source; I915_WRITE(PIPE_CRC_CTL(crtc->index), val); POSTING_READ(PIPE_CRC_CTL(crtc->index)); @@ -959,3 +962,39 @@ out: return ret; } + +void intel_crtc_enable_pipe_crc(struct intel_crtc *intel_crtc) +{ + struct drm_crtc *crtc = &intel_crtc->base; + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[crtc->index]; + u32 val = 0; + + if (!crtc->crc.opened) + return; + + if (get_new_crc_ctl_reg(dev_priv, crtc->index, &pipe_crc->source, &val, false) < 0) + return; + + /* Don't need pipe_crc->lock here, IRQs are not generated. */ + pipe_crc->skipped = 0; + + I915_WRITE(PIPE_CRC_CTL(crtc->index), val); + POSTING_READ(PIPE_CRC_CTL(crtc->index)); +} + +void intel_crtc_disable_pipe_crc(struct intel_crtc *intel_crtc) +{ + struct drm_crtc *crtc = &intel_crtc->base; + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[crtc->index]; + + /* Swallow crc's until we stop generating them. */ + spin_lock_irq(&pipe_crc->lock); + pipe_crc->skipped = INT_MIN; + spin_unlock_irq(&pipe_crc->lock); + + I915_WRITE(PIPE_CRC_CTL(crtc->index), 0); + POSTING_READ(PIPE_CRC_CTL(crtc->index)); + synchronize_irq(dev_priv->drm.irq); +} -- cgit v1.2.3 From 59cd31f177b34deb834a5c97478502741be1cf2e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 8 Mar 2018 14:26:47 +0000 Subject: drm/i915: Kick the rps worker when changing the boost frequency The boost frequency is only applied from the RPS worker while someone is waiting on a request and requested a boost. As such, when the user wishes to change the frequency, we have to kick the worker in order to re-evaluate whether to apply the boost frequency. v2: Check num_waiters to decide if we should kick the worker to handle boosting. Fixes: 29ecd78d3b79 ("drm/i915: Define a separate variable and control for RPS waitboost frequency") Signed-off-by: Chris Wilson Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180308142648.4016-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_sysfs.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index b33d2158c234..e5e6f6bb2b05 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -304,8 +304,9 @@ static ssize_t gt_boost_freq_mhz_store(struct device *kdev, { struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev); struct intel_rps *rps = &dev_priv->gt_pm.rps; - u32 val; + bool boost = false; ssize_t ret; + u32 val; ret = kstrtou32(buf, 0, &val); if (ret) @@ -317,8 +318,13 @@ static ssize_t gt_boost_freq_mhz_store(struct device *kdev, return -EINVAL; mutex_lock(&dev_priv->pcu_lock); - rps->boost_freq = val; + if (val != rps->boost_freq) { + rps->boost_freq = val; + boost = atomic_read(&rps->num_waiters); + } mutex_unlock(&dev_priv->pcu_lock); + if (boost) + schedule_work(&rps->work); return count; } -- cgit v1.2.3 From d586b5f4cf0792f69644d1aea171f82d029fb5ed Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 8 Mar 2018 14:26:48 +0000 Subject: drm/i915: Index the ring frequency table by HW frequency range When reporting the frequency table stored in the punit, report the full range and not just the user restricted frequency range. In the process keep the code to set the frequency table and read it the same. v3: As we haven't separated the sb_lock from the pcu_lock yet, there's a cycle between the pcu_lock and intel_runtime_pm_get. References: f936ec34dea8 ("drm/i915/skl: Updated the i915_ring_freq_table debugfs function") Signed-off-by: Chris Wilson Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala #v1 Link: https://patchwork.freedesktop.org/patch/msgid/20180308142648.4016-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_debugfs.c | 13 ++++++------- drivers/gpu/drm/i915/intel_pm.c | 9 ++++----- 2 files changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 89f7ff2c652e..d8bc1bb30cb4 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1796,9 +1796,9 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); struct intel_rps *rps = &dev_priv->gt_pm.rps; - int ret = 0; - int gpu_freq, ia_freq; unsigned int max_gpu_freq, min_gpu_freq; + int gpu_freq, ia_freq; + int ret; if (!HAS_LLC(dev_priv)) return -ENODEV; @@ -1809,13 +1809,12 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) if (ret) goto out; + min_gpu_freq = rps->min_freq; + max_gpu_freq = rps->max_freq; if (IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv)) { /* Convert GT frequency to 50 HZ units */ - min_gpu_freq = rps->min_freq_softlimit / GEN9_FREQ_SCALER; - max_gpu_freq = rps->max_freq_softlimit / GEN9_FREQ_SCALER; - } else { - min_gpu_freq = rps->min_freq_softlimit; - max_gpu_freq = rps->max_freq_softlimit; + min_gpu_freq /= GEN9_FREQ_SCALER; + max_gpu_freq /= GEN9_FREQ_SCALER; } seq_puts(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n"); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b8da4dcdd584..dd5ddb77b306 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6918,13 +6918,12 @@ static void gen6_update_ring_freq(struct drm_i915_private *dev_priv) /* convert DDR frequency from units of 266.6MHz to bandwidth */ min_ring_freq = mult_frac(min_ring_freq, 8, 3); + min_gpu_freq = rps->min_freq; + max_gpu_freq = rps->max_freq; if (IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv)) { /* Convert GT frequency to 50 HZ units */ - min_gpu_freq = rps->min_freq / GEN9_FREQ_SCALER; - max_gpu_freq = rps->max_freq / GEN9_FREQ_SCALER; - } else { - min_gpu_freq = rps->min_freq; - max_gpu_freq = rps->max_freq; + min_gpu_freq /= GEN9_FREQ_SCALER; + max_gpu_freq /= GEN9_FREQ_SCALER; } /* -- cgit v1.2.3 From 51f6b0f99cab765477a636443ce63295b76b9bb4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 9 Mar 2018 01:08:08 +0000 Subject: drm/i915: Push irq_shift from gen8_cs_irq_handler() to caller Originally we were inlining gen8_cs_irq_handler() and so expected the compiler to constant-fold away the irq_shift (so we had hardcoded it as opposed to use engine->irq_shift). However, we dropped the inline given the proliferation of gen8_cs_irq_handler()s. If we pull the shifting of the iir into the caller, we can shrink the code still further: add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-34 (-34) Function old new delta gen8_cs_irq_handler 123 118 -5 gen8_gt_irq_handler 261 248 -13 gen11_irq_handler 722 706 -16 v2: Drop gen11_cs_irq_handler now that it is a simple stub around gen8_cs_irq_handler (Daniele) References: 5d3d69d5c119 ("drm/i915: Stop inlining the execlists IRQ handler") Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Tvrtko Ursulin Cc: Daniele Ceraolo Spurio Reviewed-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20180309010808.11921-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_irq.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index babf81cf668b..c8c29d8ecbab 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1399,19 +1399,19 @@ static void snb_gt_irq_handler(struct drm_i915_private *dev_priv, } static void -gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir, int test_shift) +gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir) { struct intel_engine_execlists * const execlists = &engine->execlists; bool tasklet = false; - if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift)) { + if (iir & GT_CONTEXT_SWITCH_INTERRUPT) { if (READ_ONCE(engine->execlists.active)) { __set_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); tasklet = true; } } - if (iir & (GT_RENDER_USER_INTERRUPT << test_shift)) { + if (iir & GT_RENDER_USER_INTERRUPT) { notify_ring(engine); tasklet |= USES_GUC_SUBMISSION(engine->i915); } @@ -1466,21 +1466,21 @@ static void gen8_gt_irq_handler(struct drm_i915_private *i915, { if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) { gen8_cs_irq_handler(i915->engine[RCS], - gt_iir[0], GEN8_RCS_IRQ_SHIFT); + gt_iir[0] >> GEN8_RCS_IRQ_SHIFT); gen8_cs_irq_handler(i915->engine[BCS], - gt_iir[0], GEN8_BCS_IRQ_SHIFT); + gt_iir[0] >> GEN8_BCS_IRQ_SHIFT); } if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) { gen8_cs_irq_handler(i915->engine[VCS], - gt_iir[1], GEN8_VCS1_IRQ_SHIFT); + gt_iir[1] >> GEN8_VCS1_IRQ_SHIFT); gen8_cs_irq_handler(i915->engine[VCS2], - gt_iir[1], GEN8_VCS2_IRQ_SHIFT); + gt_iir[1] >> GEN8_VCS2_IRQ_SHIFT); } if (master_ctl & GEN8_GT_VECS_IRQ) { gen8_cs_irq_handler(i915->engine[VECS], - gt_iir[3], GEN8_VECS_IRQ_SHIFT); + gt_iir[3] >> GEN8_VECS_IRQ_SHIFT); } if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) { @@ -2762,12 +2762,6 @@ static void __fini_wedge(struct wedge_me *w) (W)->i915; \ __fini_wedge((W))) -static __always_inline void -gen11_cs_irq_handler(struct intel_engine_cs * const engine, const u32 iir) -{ - gen8_cs_irq_handler(engine, iir, 0); -} - static void gen11_gt_engine_irq_handler(struct drm_i915_private * const i915, const unsigned int bank, @@ -2781,27 +2775,27 @@ gen11_gt_engine_irq_handler(struct drm_i915_private * const i915, switch (engine_n) { case GEN11_RCS0: - return gen11_cs_irq_handler(engine[RCS], iir); + return gen8_cs_irq_handler(engine[RCS], iir); case GEN11_BCS: - return gen11_cs_irq_handler(engine[BCS], iir); + return gen8_cs_irq_handler(engine[BCS], iir); } case 1: switch (engine_n) { case GEN11_VCS(0): - return gen11_cs_irq_handler(engine[_VCS(0)], iir); + return gen8_cs_irq_handler(engine[_VCS(0)], iir); case GEN11_VCS(1): - return gen11_cs_irq_handler(engine[_VCS(1)], iir); + return gen8_cs_irq_handler(engine[_VCS(1)], iir); case GEN11_VCS(2): - return gen11_cs_irq_handler(engine[_VCS(2)], iir); + return gen8_cs_irq_handler(engine[_VCS(2)], iir); case GEN11_VCS(3): - return gen11_cs_irq_handler(engine[_VCS(3)], iir); + return gen8_cs_irq_handler(engine[_VCS(3)], iir); case GEN11_VECS(0): - return gen11_cs_irq_handler(engine[_VECS(0)], iir); + return gen8_cs_irq_handler(engine[_VECS(0)], iir); case GEN11_VECS(1): - return gen11_cs_irq_handler(engine[_VECS(1)], iir); + return gen8_cs_irq_handler(engine[_VECS(1)], iir); } } } -- cgit v1.2.3 From 1e6aa7e55c28ecd842b8b4599e4273c2429ee061 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 6 Mar 2018 12:41:55 +0200 Subject: drm/i915/icl: do not save DDI A/E sharing bit for ICL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't want to preserve the DDI A 4 lane bit on ICL. Fixes: 3d2011cfa41f ("drm/i915/icl: remove port A/E lane sharing limitation.") Cc: Mahesh Kumar Cc: Paulo Zanoni Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180306104155.3526-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_ddi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index ac8fc2a44ac6..dbcf1a0586f9 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -3080,9 +3080,12 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); intel_encoder->cloneable = 0; - intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) & - (DDI_BUF_PORT_REVERSAL | - DDI_A_4_LANES); + if (INTEL_GEN(dev_priv) >= 11) + intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) & + DDI_BUF_PORT_REVERSAL; + else + intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) & + (DDI_BUF_PORT_REVERSAL | DDI_A_4_LANES); intel_dig_port->dp.output_reg = INVALID_MMIO_REG; intel_dig_port->max_lanes = intel_ddi_max_lanes(intel_dig_port); -- cgit v1.2.3 From 2d4ecace3a7861c6071235a6cc88067b8c3eec4a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 7 Mar 2018 13:42:21 +0000 Subject: drm/i915: Finish the wait-for-wedge by retiring all the inflight requests Before we reset the GPU after marking the device as wedged, we wait for all the remaining requests to be completed (and marked as EIO). Afterwards, we should flush the request lists so the next batch start with the driver in an idle state. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180307134226.25492-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ab88ca53c9a0..c3d650706329 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3281,7 +3281,8 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915) if (!test_bit(I915_WEDGED, &i915->gpu_error.flags)) return true; - /* Before unwedging, make sure that all pending operations + /* + * Before unwedging, make sure that all pending operations * are flushed and errored out - we may have requests waiting upon * third party fences. We marked all inflight requests as EIO, and * every execbuf since returned EIO, for consistency we want all @@ -3299,7 +3300,8 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915) if (!rq) continue; - /* We can't use our normal waiter as we want to + /* + * We can't use our normal waiter as we want to * avoid recursively trying to handle the current * reset. The basic dma_fence_default_wait() installs * a callback for dma_fence_signal(), which is @@ -3314,8 +3316,11 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915) return false; } } + i915_retire_requests(i915); + GEM_BUG_ON(i915->gt.active_requests); - /* Undo nop_submit_request. We prevent all new i915 requests from + /* + * Undo nop_submit_request. We prevent all new i915 requests from * being queued (by disallowing execbuf whilst wedged) so having * waited for all active requests above, we know the system is idle * and do not have to worry about a thread being inside -- cgit v1.2.3 From 36620032ceccb4bf07bbe780a3998e88a585ad69 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 7 Mar 2018 13:42:23 +0000 Subject: drm/i915: Update ring position from request on retiring When wedged, we do not update the ring->tail as we submit the requests causing us to leak the ring->space upon cleaning up the wedged driver. We can just use the value stored in rq->tail, and keep the submission backend details away from set-wedge. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180307134226.25492-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_request.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index d437beac3969..75c8826c8cae 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -358,7 +358,7 @@ static void advance_ring(struct i915_request *request) * is just about to be. Either works, if we miss the last two * noops - they are safe to be replayed on a reset. */ - tail = READ_ONCE(request->ring->tail); + tail = READ_ONCE(request->tail); } else { tail = request->postfix; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 1d599524a759..88eeb64041ae 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1593,6 +1593,7 @@ static noinline int wait_for_space(struct intel_ring *ring, unsigned int bytes) if (intel_ring_update_space(ring) >= bytes) return 0; + GEM_BUG_ON(list_empty(&ring->request_list)); list_for_each_entry(target, &ring->request_list, ring_link) { /* Would completion of this request free enough space? */ if (bytes <= __intel_ring_space(target->postfix, -- cgit v1.2.3 From ef5032a06a73ca5f40ce6975d956aa478536c411 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 7 Mar 2018 13:42:24 +0000 Subject: drm/i915: Include ring->emit in debugging Include ring->emit and ring->space alongside ring->(head,tail) when printing debug information. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180307134226.25492-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++-- drivers/gpu/drm/i915/intel_engine_cs.c | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d8bc1bb30cb4..34d12522a1da 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1922,8 +1922,8 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) static void describe_ctx_ring(struct seq_file *m, struct intel_ring *ring) { - seq_printf(m, " (ringbuffer, space: %d, head: %u, tail: %u)", - ring->space, ring->head, ring->tail); + seq_printf(m, " (ringbuffer, space: %d, head: %u, tail: %u, emit: %u)", + ring->space, ring->head, ring->tail, ring->emit); } static int i915_context_status(struct seq_file *m, void *unused) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 4ba139c27fba..048cd011484c 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1929,12 +1929,16 @@ void intel_engine_dump(struct intel_engine_cs *engine, rq->head, rq->postfix, rq->tail, rq->batch ? upper_32_bits(rq->batch->node.start) : ~0u, rq->batch ? lower_32_bits(rq->batch->node.start) : ~0u); - drm_printf(m, "\t\tring->start: 0x%08x\n", + drm_printf(m, "\t\tring->start: 0x%08x\n", i915_ggtt_offset(rq->ring->vma)); - drm_printf(m, "\t\tring->head: 0x%08x\n", + drm_printf(m, "\t\tring->head: 0x%08x\n", rq->ring->head); - drm_printf(m, "\t\tring->tail: 0x%08x\n", + drm_printf(m, "\t\tring->tail: 0x%08x\n", rq->ring->tail); + drm_printf(m, "\t\tring->emit: 0x%08x\n", + rq->ring->emit); + drm_printf(m, "\t\tring->space: 0x%08x\n", + rq->ring->space); } rcu_read_unlock(); -- cgit v1.2.3 From 47650db02dd52267953df81438c93cf8a0eb0e5e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 7 Mar 2018 13:42:25 +0000 Subject: drm/i915: Wrap engine->schedule in RCU locks for set-wedge protection Similar to the staging around handling of engine->submit_request, we need to stop adding to the execlists->queue prior to calling engine->cancel_requests. cancel_requests will move requests from the queue onto the timeline, so if we add a request onto the queue after that point, it will be lost. Fixes: af7a8ffad9c5 ("drm/i915: Use rcu instead of stop_machine in set_wedged") Signed-off-by: Chris Wilson Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180307134226.25492-5-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 13 +++++++------ drivers/gpu/drm/i915/i915_request.c | 2 ++ 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c3d650706329..50e165b5b60d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -479,10 +479,11 @@ static void __fence_set_priority(struct dma_fence *fence, int prio) rq = to_request(fence); engine = rq->engine; - if (!engine->schedule) - return; - engine->schedule(rq, prio); + rcu_read_lock(); + if (engine->schedule) + engine->schedule(rq, prio); + rcu_read_unlock(); } static void fence_set_priority(struct dma_fence *fence, int prio) @@ -3222,8 +3223,11 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) */ for_each_engine(engine, i915, id) { i915_gem_reset_prepare_engine(engine); + engine->submit_request = nop_submit_request; + engine->schedule = NULL; } + i915->caps.scheduler = 0; /* * Make sure no one is running the old callback before we proceed with @@ -3241,11 +3245,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) * start to complete all requests. */ engine->submit_request = nop_complete_submit_request; - engine->schedule = NULL; } - i915->caps.scheduler = 0; - /* * Make sure no request can slip through without getting completed by * either this call here to intel_engine_init_global_seqno, or the one diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 75c8826c8cae..2f62acd2dc3d 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1081,8 +1081,10 @@ void __i915_request_add(struct i915_request *request, bool flush_caches) * decide whether to preempt the entire chain so that it is ready to * run at the earliest possible convenience. */ + rcu_read_lock(); if (engine->schedule) engine->schedule(request, request->ctx->priority); + rcu_read_unlock(); local_bh_disable(); i915_sw_fence_commit(&request->submit); -- cgit v1.2.3 From 68ad361285a9cc73b259f59adbaafde196c15987 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 7 Mar 2018 13:42:26 +0000 Subject: drm/i915: Only call tasklet_kill() on the first prepare_reset tasklet_kill() will spin waiting for the current tasklet to be executed. However, if tasklet_disable() has been called, then the tasklet is never executed but permanently put back onto the runlist until tasklet_enable() is called. Ergo, we cannot use tasklet_kill() inside a disable/enable pair. This is the case when we call set-wedge from inside i915_reset(), and another request was submitted to us concurrent to the reset. Fixes: 963ddd63c314 ("drm/i915: Suspend submission tasklets around wedging") Signed-off-by: Chris Wilson Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180307134226.25492-6-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 50e165b5b60d..e58b741e2ec0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2948,8 +2948,16 @@ i915_gem_reset_prepare_engine(struct intel_engine_cs *engine) * calling engine->init_hw() and also writing the ELSP. * Turning off the execlists->tasklet until the reset is over * prevents the race. + * + * Note that this needs to be a single atomic operation on the + * tasklet (flush existing tasks, prevent new tasks) to prevent + * a race between reset and set-wedged. It is not, so we do the best + * we can atm and make sure we don't lock the machine up in the more + * common case of recursively being called from set-wedged from inside + * i915_reset. */ - tasklet_kill(&engine->execlists.tasklet); + if (!atomic_read(&engine->execlists.tasklet.count)) + tasklet_kill(&engine->execlists.tasklet); tasklet_disable(&engine->execlists.tasklet); /* -- cgit v1.2.3 From df9471689685857c38d5e095652a1bc867ee11cf Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Thu, 8 Mar 2018 18:24:15 -0500 Subject: drm/i915: Remove unused DP_LINK_CHECK_TIMEOUT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lyude Paul Cc: Manasi Navare Cc: Ville Syrjälä Reviewed-by: Manasi Navare Link: https://patchwork.freedesktop.org/patch/msgid/20180308232421.14049-2-lyude@redhat.com --- drivers/gpu/drm/i915/intel_dp.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9a4a51e79fa1..4dd1b2287dd6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -43,7 +43,6 @@ #include #include "i915_drv.h" -#define DP_LINK_CHECK_TIMEOUT (10 * 1000) #define DP_DPRX_ESI_LEN 14 /* Compliance test status bits */ -- cgit v1.2.3 From 86aa82476cffdfa2cb85c2dc8b198e1675773982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Thu, 8 Mar 2018 16:46:53 +0100 Subject: drm/i915/guc: Tidy guc_log_control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We plan to decouple log runtime (mapping + relay) from verbosity control. Let's tidy the code now to reduce the churn in the following patches. v2: Tidy macros, keep debug messages, use helper var for enable, correct typo (Michał) Fix incorrect input validaction (Sagar) Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Michal Wajdeczko Cc: Sagar Arun Kamble Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180308154707.21716-1-michal.winiarski@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 11 ++--- drivers/gpu/drm/i915/intel_guc_log.c | 80 +++++++++++++++++++++--------------- drivers/gpu/drm/i915/intel_guc_log.h | 3 +- 3 files changed, 53 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 34d12522a1da..c4cc8fef11a0 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2499,13 +2499,10 @@ static int i915_guc_log_control_get(void *data, u64 *val) { struct drm_i915_private *dev_priv = data; - if (!HAS_GUC(dev_priv)) + if (!USES_GUC(dev_priv)) return -ENODEV; - if (!dev_priv->guc.log.vma) - return -EINVAL; - - *val = i915_modparams.guc_log_level; + *val = intel_guc_log_control_get(&dev_priv->guc); return 0; } @@ -2514,10 +2511,10 @@ static int i915_guc_log_control_set(void *data, u64 val) { struct drm_i915_private *dev_priv = data; - if (!HAS_GUC(dev_priv)) + if (!USES_GUC(dev_priv)) return -ENODEV; - return intel_guc_log_control(&dev_priv->guc, val); + return intel_guc_log_control_set(&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 c0c2e7d1c7d7..7e59fb07b06b 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -659,51 +659,63 @@ void intel_guc_log_destroy(struct intel_guc *guc) i915_vma_unpin_and_release(&guc->log.vma); } -int intel_guc_log_control(struct intel_guc *guc, u64 control_val) +int intel_guc_log_control_get(struct intel_guc *guc) +{ + GEM_BUG_ON(!guc->log.vma); + GEM_BUG_ON(i915_modparams.guc_log_level < 0); + + return i915_modparams.guc_log_level; +} + +#define GUC_LOG_LEVEL_DISABLED 0 +#define LOG_LEVEL_TO_ENABLED(x) ((x) > 0) +#define LOG_LEVEL_TO_VERBOSITY(x) ({ \ + typeof(x) _x = (x); \ + LOG_LEVEL_TO_ENABLED(_x) ? _x - 1 : 0; \ +}) +#define VERBOSITY_TO_LOG_LEVEL(x) ((x) + 1) +int intel_guc_log_control_set(struct intel_guc *guc, u64 val) { struct drm_i915_private *dev_priv = guc_to_i915(guc); - bool enable_logging = control_val > 0; - u32 verbosity; + bool enabled = LOG_LEVEL_TO_ENABLED(val); int ret; - if (!guc->log.vma) - return -ENODEV; + BUILD_BUG_ON(GUC_LOG_VERBOSITY_MIN != 0); + GEM_BUG_ON(!guc->log.vma); + GEM_BUG_ON(i915_modparams.guc_log_level < 0); - BUILD_BUG_ON(GUC_LOG_VERBOSITY_MIN); - if (control_val > 1 + GUC_LOG_VERBOSITY_MAX) + /* + * GuC is recognizing log levels starting from 0 to max, we're using 0 + * as indication that logging should be disabled. + */ + if (val < GUC_LOG_LEVEL_DISABLED || + val > VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX)) return -EINVAL; - /* This combination doesn't make sense & won't have any effect */ - if (!enable_logging && !i915_modparams.guc_log_level) - return 0; + mutex_lock(&dev_priv->drm.struct_mutex); - verbosity = enable_logging ? control_val - 1 : 0; + if (i915_modparams.guc_log_level == val) { + ret = 0; + goto out_unlock; + } - 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); + ret = guc_log_control(guc, enabled, LOG_LEVEL_TO_VERBOSITY(val)); 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; + if (ret) { + DRM_DEBUG_DRIVER("guc_log_control action failed %d\n", ret); + goto out_unlock; } - if (enable_logging) { - i915_modparams.guc_log_level = 1 + verbosity; + i915_modparams.guc_log_level = val; - /* - * 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. - */ + mutex_unlock(&dev_priv->drm.struct_mutex); + + if (enabled && !guc_log_has_runtime(guc)) { ret = guc_log_late_setup(guc); - if (ret < 0) { + if (ret) { DRM_DEBUG_DRIVER("GuC log late setup failed %d\n", ret); - return ret; + goto out; } /* GuC logging is currently the only user of Guc2Host interrupts */ @@ -712,7 +724,7 @@ int intel_guc_log_control(struct intel_guc *guc, u64 control_val) gen9_enable_guc_interrupts(dev_priv); intel_runtime_pm_put(dev_priv); mutex_unlock(&dev_priv->drm.struct_mutex); - } else { + } else if (!enabled && guc_log_has_runtime(guc)) { /* * Once logging is disabled, GuC won't generate logs & send an * interrupt. But there could be some data in the log buffer @@ -720,11 +732,13 @@ int intel_guc_log_control(struct intel_guc *guc, u64 control_val) * buffer state and then collect the left over logs. */ guc_flush_logs(guc); - - /* As logging is disabled, update log level to reflect that */ - i915_modparams.guc_log_level = 0; } + return 0; + +out_unlock: + mutex_unlock(&dev_priv->drm.struct_mutex); +out: return ret; } diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index dab0e949567a..141ce9ca22ce 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -64,7 +64,8 @@ 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 intel_guc_log_control(struct intel_guc *guc, u64 control_val); +int intel_guc_log_control_get(struct intel_guc *guc); +int intel_guc_log_control_set(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); -- cgit v1.2.3 From 950724ba88521195b4aefd092c8a0337487be352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Thu, 8 Mar 2018 16:46:54 +0100 Subject: drm/i915/guc: Create common entry points for log register/unregister MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have many functions responsible for allocating different parts of GuC log runtime called from multiple places. Let's stick with keeping everything in guc_log_register instead. v2: Use more generic intel_uc_register name, keep using "misc" suffix (Michał) s/dev_priv/i915 (Sagar) Make guc_log_relay_* static (sparse) Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Michal Wajdeczko Cc: Sagar Arun Kamble Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180308154707.21716-2-michal.winiarski@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 6 +- drivers/gpu/drm/i915/intel_guc_log.c | 156 ++++++++++++++--------------------- drivers/gpu/drm/i915/intel_guc_log.h | 6 +- drivers/gpu/drm/i915/intel_uc.c | 41 +++++---- drivers/gpu/drm/i915/intel_uc.h | 2 + 5 files changed, 95 insertions(+), 116 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index d7c4de45644d..987c6770d1a6 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1238,9 +1238,11 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) /* Reveal our presence to userspace */ if (drm_dev_register(dev, 0) == 0) { i915_debugfs_register(dev_priv); - i915_guc_log_register(dev_priv); i915_setup_sysfs(dev_priv); + /* Depends on debugfs having been initialized */ + intel_uc_register(dev_priv); + /* Depends on sysfs having been initialized */ i915_perf_register(dev_priv); } else @@ -1298,7 +1300,7 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) i915_pmu_unregister(dev_priv); i915_teardown_sysfs(dev_priv); - i915_guc_log_unregister(dev_priv); + intel_uc_unregister(dev_priv); drm_dev_unregister(&dev_priv->drm); i915_gem_shrinker_unregister(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 7e59fb07b06b..90b395f34808 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -443,7 +443,7 @@ void intel_guc_log_init_early(struct intel_guc *guc) INIT_WORK(&guc->log.runtime.flush_work, capture_logs_work); } -int intel_guc_log_relay_create(struct intel_guc *guc) +static int guc_log_relay_create(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); struct rchan *guc_log_relay_chan; @@ -496,7 +496,7 @@ err: return ret; } -void intel_guc_log_relay_destroy(struct intel_guc *guc) +static void guc_log_relay_destroy(struct intel_guc *guc) { mutex_lock(&guc->log.runtime.relay_lock); @@ -514,49 +514,6 @@ out_unlock: mutex_unlock(&guc->log.runtime.relay_lock); } -static int guc_log_late_setup(struct intel_guc *guc) -{ - struct drm_i915_private *dev_priv = guc_to_i915(guc); - int ret; - - 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 = 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); - if (ret) - goto err_runtime; - - 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; - return ret; -} - static void guc_log_capture_logs(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); @@ -576,16 +533,6 @@ 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) - 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. @@ -628,12 +575,6 @@ int intel_guc_log_create(struct intel_guc *guc) guc->log.vma = vma; - if (i915_modparams.guc_log_level) { - ret = guc_log_runtime_create(guc); - if (ret < 0) - goto err_vma; - } - /* each allocated unit is a page */ flags = GUC_LOG_VALID | GUC_LOG_NOTIFY_ON_HALF_FULL | (GUC_LOG_DPC_PAGES << GUC_LOG_DPC_SHIFT) | @@ -645,8 +586,6 @@ int intel_guc_log_create(struct intel_guc *guc) return 0; -err_vma: - i915_vma_unpin_and_release(&guc->log.vma); err: /* logging will be off */ i915_modparams.guc_log_level = 0; @@ -712,26 +651,14 @@ int intel_guc_log_control_set(struct intel_guc *guc, u64 val) mutex_unlock(&dev_priv->drm.struct_mutex); if (enabled && !guc_log_has_runtime(guc)) { - ret = guc_log_late_setup(guc); + ret = intel_guc_log_register(guc); if (ret) { - DRM_DEBUG_DRIVER("GuC log late setup failed %d\n", ret); + /* logging will remain off */ + i915_modparams.guc_log_level = 0; goto out; } - - /* 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 if (!enabled && guc_log_has_runtime(guc)) { - /* - * 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. - */ - guc_flush_logs(guc); + intel_guc_log_unregister(guc); } return 0; @@ -742,29 +669,72 @@ out: return ret; } -void i915_guc_log_register(struct drm_i915_private *dev_priv) +int intel_guc_log_register(struct intel_guc *guc) { - if (!USES_GUC_SUBMISSION(dev_priv) || !i915_modparams.guc_log_level) - return; + struct drm_i915_private *i915 = guc_to_i915(guc); + int ret; + + GEM_BUG_ON(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_relay_create(guc); + if (ret) + goto err; + + mutex_lock(&i915->drm.struct_mutex); + ret = guc_log_runtime_create(guc); + mutex_unlock(&i915->drm.struct_mutex); + + if (ret) + goto err_relay; + + ret = guc_log_relay_file_create(guc); + if (ret) + goto err_runtime; + + /* GuC logging is currently the only user of Guc2Host interrupts */ + mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); + gen9_enable_guc_interrupts(i915); + intel_runtime_pm_put(i915); + mutex_unlock(&i915->drm.struct_mutex); + + return 0; - guc_log_late_setup(&dev_priv->guc); +err_runtime: + mutex_lock(&i915->drm.struct_mutex); + guc_log_runtime_destroy(guc); + mutex_unlock(&i915->drm.struct_mutex); +err_relay: + guc_log_relay_destroy(guc); +err: + return ret; } -void i915_guc_log_unregister(struct drm_i915_private *dev_priv) +void intel_guc_log_unregister(struct intel_guc *guc) { - struct intel_guc *guc = &dev_priv->guc; + struct drm_i915_private *i915 = guc_to_i915(guc); - if (!USES_GUC_SUBMISSION(dev_priv)) - return; + /* + * 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. + */ + guc_flush_logs(guc); - mutex_lock(&dev_priv->drm.struct_mutex); + mutex_lock(&i915->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); + intel_runtime_pm_get(i915); + gen9_disable_guc_interrupts(i915); + intel_runtime_pm_put(i915); guc_log_runtime_destroy(guc); - mutex_unlock(&dev_priv->drm.struct_mutex); + mutex_unlock(&i915->drm.struct_mutex); - intel_guc_log_relay_destroy(guc); + 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 141ce9ca22ce..09dd2ef1933d 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -62,11 +62,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 intel_guc_log_control_get(struct intel_guc *guc); int intel_guc_log_control_set(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); +int intel_guc_log_register(struct intel_guc *guc); +void intel_guc_log_unregister(struct intel_guc *guc); #endif diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index e5bf0d37bf43..1c1a00df010b 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -219,6 +219,28 @@ static void guc_free_load_err_log(struct intel_guc *guc) i915_gem_object_put(guc->load_err_log); } +int intel_uc_register(struct drm_i915_private *i915) +{ + int ret = 0; + + if (!USES_GUC(i915)) + return 0; + + if (i915_modparams.guc_log_level) + ret = intel_guc_log_register(&i915->guc); + + return ret; +} + +void intel_uc_unregister(struct drm_i915_private *i915) +{ + if (!USES_GUC(i915)) + return; + + if (i915_modparams.guc_log_level) + intel_guc_log_unregister(&i915->guc); +} + static int guc_enable_communication(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); @@ -249,23 +271,10 @@ int intel_uc_init_misc(struct drm_i915_private *dev_priv) return 0; ret = intel_guc_init_wq(guc); - if (ret) { - DRM_ERROR("Couldn't allocate workqueues for GuC\n"); - goto err; - } - - ret = intel_guc_log_relay_create(guc); - if (ret) { - DRM_ERROR("Couldn't allocate relay for GuC log\n"); - goto err_relay; - } + if (ret) + return ret; return 0; - -err_relay: - intel_guc_fini_wq(guc); -err: - return ret; } void intel_uc_fini_misc(struct drm_i915_private *dev_priv) @@ -276,8 +285,6 @@ void intel_uc_fini_misc(struct drm_i915_private *dev_priv) return; 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 f76d51d1ce70..d6af984cd789 100644 --- a/drivers/gpu/drm/i915/intel_uc.h +++ b/drivers/gpu/drm/i915/intel_uc.h @@ -31,6 +31,8 @@ void intel_uc_sanitize_options(struct drm_i915_private *dev_priv); void intel_uc_init_early(struct drm_i915_private *dev_priv); void intel_uc_init_mmio(struct drm_i915_private *dev_priv); +int intel_uc_register(struct drm_i915_private *dev_priv); +void intel_uc_unregister(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_misc(struct drm_i915_private *dev_priv); -- cgit v1.2.3 From 93bf8096c7daa78f0dabc811dad62fa98fe01742 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 8 Mar 2018 16:46:55 +0100 Subject: drm/i915/guc: Move GuC notification handling to separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To allow future code reuse. While here, fix comment style. v2: Notifications are a separate thing - rename the handler (Sagar) Suggested-by: Oscar Mateo Signed-off-by: Michal Wajdeczko Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Oscar Mateo Cc: Sagar Arun Kamble Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180308154707.21716-3-michal.winiarski@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 33 ++------------------------------- drivers/gpu/drm/i915/intel_guc.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_guc.h | 1 + 3 files changed, 40 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c8c29d8ecbab..828f3104488c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1766,37 +1766,8 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir) { - if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT) { - /* Sample the log buffer flush related bits & clear them out now - * itself from the message identity register to minimize the - * probability of losing a flush interrupt, when there are back - * to back flush interrupts. - * There can be a new flush interrupt, for different log buffer - * type (like for ISR), whilst Host is handling one (for DPC). - * Since same bit is used in message register for ISR & DPC, it - * could happen that GuC sets the bit for 2nd interrupt but Host - * clears out the bit on handling the 1st interrupt. - */ - u32 msg, flush; - - msg = I915_READ(SOFT_SCRATCH(15)); - flush = msg & (INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED | - INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER); - if (flush) { - /* Clear the message bits that are handled */ - I915_WRITE(SOFT_SCRATCH(15), msg & ~flush); - - /* Handle flush interrupt in bottom half */ - queue_work(dev_priv->guc.log.runtime.flush_wq, - &dev_priv->guc.log.runtime.flush_work); - - dev_priv->guc.log.flush_interrupt_count++; - } else { - /* Not clearing of unhandled event bits won't result in - * re-triggering of the interrupt. - */ - } - } + if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT) + intel_guc_to_host_event_handler(&dev_priv->guc); } static void i9xx_pipestat_irq_reset(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index ff08ea0ebf49..25f92291fd40 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -364,6 +364,43 @@ int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len) return ret; } +void intel_guc_to_host_event_handler(struct intel_guc *guc) +{ + struct drm_i915_private *dev_priv = guc_to_i915(guc); + u32 msg, flush; + + /* + * Sample the log buffer flush related bits & clear them out now + * itself from the message identity register to minimize the + * probability of losing a flush interrupt, when there are back + * to back flush interrupts. + * There can be a new flush interrupt, for different log buffer + * type (like for ISR), whilst Host is handling one (for DPC). + * Since same bit is used in message register for ISR & DPC, it + * could happen that GuC sets the bit for 2nd interrupt but Host + * clears out the bit on handling the 1st interrupt. + */ + + msg = I915_READ(SOFT_SCRATCH(15)); + flush = msg & (INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED | + INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER); + if (flush) { + /* Clear the message bits that are handled */ + I915_WRITE(SOFT_SCRATCH(15), msg & ~flush); + + /* Handle flush interrupt in bottom half */ + queue_work(guc->log.runtime.flush_wq, + &guc->log.runtime.flush_work); + + guc->log.flush_interrupt_count++; + } else { + /* + * Not clearing of unhandled event bits won't result in + * re-triggering of the interrupt. + */ + } +} + int intel_guc_sample_forcewake(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index b9424ac644ac..6d5aebe55039 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -125,6 +125,7 @@ int intel_guc_init(struct intel_guc *guc); void intel_guc_fini(struct intel_guc *guc); int intel_guc_send_nop(struct intel_guc *guc, const u32 *action, u32 len); int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len); +void intel_guc_to_host_event_handler(struct intel_guc *guc); int intel_guc_sample_forcewake(struct intel_guc *guc); int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset); int intel_guc_suspend(struct intel_guc *guc); -- cgit v1.2.3 From ff491603ffec80d79b970d540f066535c8743796 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 8 Mar 2018 09:50:34 +0000 Subject: drm/i915: Include i915_reg.h in intel_ringbuffer.h Header intel_ringbuffer.h is using definitions from i915_reg.h but forget to include it. Remove this hidden dependency by explicitly include missing header. v2: add reminder (Chris) Signed-off-by: Michal Wajdeczko Cc: Chris Wilson Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180308095037.18264-2-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 0320c2c4cfba..c31258d27e20 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -7,6 +7,7 @@ #include "i915_gem_batch_pool.h" #include "i915_gem_timeline.h" +#include "i915_reg.h" /* FIXME split out i915_gpu_commands.h */ #include "i915_pmu.h" #include "i915_request.h" #include "i915_selftest.h" -- cgit v1.2.3 From c5781351450db8ff8374657a8c568772967f3795 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 8 Mar 2018 09:50:35 +0000 Subject: drm/i915: Change parameters order in i915_gem_batch_pool_init Function i915_gem_batch_pool_init() failed to follow obj-verb naming schema. Fix that by swapping function parameters. While here, change license text to SPDX format. v2: use intel_engine_init_batch_pool (Chris) as proxy (Michal) Signed-off-by: Michal Wajdeczko Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180308095037.18264-3-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/i915_gem_batch_pool.c | 30 ++++++------------------------ drivers/gpu/drm/i915/i915_gem_batch_pool.h | 29 +++++------------------------ drivers/gpu/drm/i915/intel_engine_cs.c | 9 ++++++--- 3 files changed, 17 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_batch_pool.c b/drivers/gpu/drm/i915/i915_gem_batch_pool.c index d3cbe8432f48..f3890b664e3f 100644 --- a/drivers/gpu/drm/i915/i915_gem_batch_pool.c +++ b/drivers/gpu/drm/i915/i915_gem_batch_pool.c @@ -1,29 +1,11 @@ /* - * Copyright © 2014 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. + * SPDX-License-Identifier: MIT * + * Copyright © 2014-2018 Intel Corporation */ -#include "i915_drv.h" #include "i915_gem_batch_pool.h" +#include "i915_drv.h" /** * DOC: batch pool @@ -41,11 +23,11 @@ /** * i915_gem_batch_pool_init() - initialize a batch buffer pool - * @engine: the associated request submission engine * @pool: the batch buffer pool + * @engine: the associated request submission engine */ -void i915_gem_batch_pool_init(struct intel_engine_cs *engine, - struct i915_gem_batch_pool *pool) +void i915_gem_batch_pool_init(struct i915_gem_batch_pool *pool, + struct intel_engine_cs *engine) { int n; diff --git a/drivers/gpu/drm/i915/i915_gem_batch_pool.h b/drivers/gpu/drm/i915/i915_gem_batch_pool.h index 10d5ac4c00d3..56947daaaf65 100644 --- a/drivers/gpu/drm/i915/i915_gem_batch_pool.h +++ b/drivers/gpu/drm/i915/i915_gem_batch_pool.h @@ -1,31 +1,13 @@ /* - * Copyright © 2014 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. + * SPDX-License-Identifier: MIT * + * Copyright © 2014-2018 Intel Corporation */ #ifndef I915_GEM_BATCH_POOL_H #define I915_GEM_BATCH_POOL_H -#include "i915_drv.h" +#include struct intel_engine_cs; @@ -34,9 +16,8 @@ struct i915_gem_batch_pool { struct list_head cache_list[4]; }; -/* i915_gem_batch_pool.c */ -void i915_gem_batch_pool_init(struct intel_engine_cs *engine, - struct i915_gem_batch_pool *pool); +void i915_gem_batch_pool_init(struct i915_gem_batch_pool *pool, + struct intel_engine_cs *engine); void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool); struct drm_i915_gem_object* i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, size_t size); diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 048cd011484c..a2b1e9e2c008 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -441,6 +441,11 @@ static void intel_engine_init_timeline(struct intel_engine_cs *engine) engine->timeline = &engine->i915->gt.global_timeline.engine[engine->id]; } +static void intel_engine_init_batch_pool(struct intel_engine_cs *engine) +{ + i915_gem_batch_pool_init(&engine->batch_pool, engine); +} + static bool csb_force_mmio(struct drm_i915_private *i915) { /* @@ -485,11 +490,9 @@ static void intel_engine_init_execlist(struct intel_engine_cs *engine) void intel_engine_setup_common(struct intel_engine_cs *engine) { intel_engine_init_execlist(engine); - intel_engine_init_timeline(engine); intel_engine_init_hangcheck(engine); - i915_gem_batch_pool_init(engine, &engine->batch_pool); - + intel_engine_init_batch_pool(engine); intel_engine_init_cmd_parser(engine); } -- cgit v1.2.3 From 058a9b43a37a2406a574752707c5346e7b6444f4 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 8 Mar 2018 09:50:36 +0000 Subject: drm/i915: Make header i915_pmu.h more robust Definitions in i915_pmu.h header depend on other types and declarations that were not explicitly included. Fix that by adding related headers and forward declarations. While here, change license text to SPDX format. v2: don't drop "intel_ringbuffer.h" (Tvrtko) Signed-off-by: Michal Wajdeczko Cc: Chris Wilson Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180308095037.18264-4-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 27 +++------------------------ drivers/gpu/drm/i915/i915_pmu.h | 30 ++++++++++-------------------- 2 files changed, 13 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 964467b03e4d..4bc7aefa9541 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -1,33 +1,12 @@ /* - * Copyright © 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. + * SPDX-License-Identifier: MIT * + * Copyright © 2017-2018 Intel Corporation */ -#include -#include - -#include "i915_drv.h" #include "i915_pmu.h" #include "intel_ringbuffer.h" +#include "i915_drv.h" /* Frequency for the sampling timer for events which need it. */ #define FREQUENCY 200 diff --git a/drivers/gpu/drm/i915/i915_pmu.h b/drivers/gpu/drm/i915/i915_pmu.h index aa1b1a987ea1..2ba735299f7c 100644 --- a/drivers/gpu/drm/i915/i915_pmu.h +++ b/drivers/gpu/drm/i915/i915_pmu.h @@ -1,29 +1,19 @@ /* - * Copyright © 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. + * SPDX-License-Identifier: MIT * + * Copyright © 2017-2018 Intel Corporation */ + #ifndef __I915_PMU_H__ #define __I915_PMU_H__ +#include +#include +#include +#include + +struct drm_i915_private; + enum { __I915_SAMPLE_FREQ_ACT = 0, __I915_SAMPLE_FREQ_REQ, -- cgit v1.2.3 From d897a111940fe2d644172466914d7c97791bda05 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 8 Mar 2018 09:50:37 +0000 Subject: drm/i915: Move i915_gpu_error into its own header Error state management code was moved into separate .c unit but we didn't move related definitions into own header. v2: move also intel_display_error_state forward decl fix ("Prefer 'unsigned int' to bare use of 'unsigned'") warnings detected by checkpatch in moved code (Michal) Signed-off-by: Michal Wajdeczko Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180308095037.18264-5-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 332 +------------------------------ drivers/gpu/drm/i915/i915_gpu_error.c | 1 + drivers/gpu/drm/i915/i915_gpu_error.h | 356 ++++++++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+), 331 deletions(-) create mode 100644 drivers/gpu/drm/i915/i915_gpu_error.h (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6e740f6fe33f..d35f805cb177 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -72,7 +72,7 @@ #include "i915_gem_object.h" #include "i915_gem_gtt.h" #include "i915_gem_timeline.h" - +#include "i915_gpu_error.h" #include "i915_request.h" #include "i915_vma.h" @@ -453,172 +453,6 @@ struct intel_csr { uint32_t allowed_dc_mask; }; -struct intel_display_error_state; - -struct i915_gpu_state { - struct kref ref; - ktime_t time; - ktime_t boottime; - ktime_t uptime; - - struct drm_i915_private *i915; - - char error_msg[128]; - bool simulated; - bool awake; - bool wakelock; - bool suspended; - int iommu; - u32 reset_count; - u32 suspend_count; - struct intel_device_info device_info; - struct intel_driver_caps driver_caps; - struct i915_params params; - - struct i915_error_uc { - struct intel_uc_fw guc_fw; - struct intel_uc_fw huc_fw; - struct drm_i915_error_object *guc_log; - } uc; - - /* Generic register state */ - u32 eir; - u32 pgtbl_er; - u32 ier; - u32 gtier[4], ngtier; - u32 ccid; - u32 derrmr; - u32 forcewake; - u32 error; /* gen6+ */ - u32 err_int; /* gen7 */ - u32 fault_data0; /* gen8, gen9 */ - u32 fault_data1; /* gen8, gen9 */ - u32 done_reg; - u32 gac_eco; - u32 gam_ecochk; - u32 gab_ctl; - u32 gfx_mode; - - u32 nfence; - u64 fence[I915_MAX_NUM_FENCES]; - struct intel_overlay_error_state *overlay; - struct intel_display_error_state *display; - - struct drm_i915_error_engine { - int engine_id; - /* Software tracked state */ - bool idle; - bool waiting; - int num_waiters; - unsigned long hangcheck_timestamp; - bool hangcheck_stalled; - enum intel_engine_hangcheck_action hangcheck_action; - struct i915_address_space *vm; - int num_requests; - u32 reset_count; - - /* position of active request inside the ring */ - u32 rq_head, rq_post, rq_tail; - - /* our own tracking of ring head and tail */ - u32 cpu_ring_head; - u32 cpu_ring_tail; - - u32 last_seqno; - - /* Register state */ - u32 start; - u32 tail; - u32 head; - u32 ctl; - u32 mode; - u32 hws; - u32 ipeir; - u32 ipehr; - u32 bbstate; - u32 instpm; - u32 instps; - u32 seqno; - u64 bbaddr; - u64 acthd; - u32 fault_reg; - u64 faddr; - u32 rc_psmi; /* sleep state */ - u32 semaphore_mboxes[I915_NUM_ENGINES - 1]; - struct intel_instdone instdone; - - struct drm_i915_error_context { - char comm[TASK_COMM_LEN]; - pid_t pid; - u32 handle; - u32 hw_id; - int priority; - int ban_score; - int active; - int guilty; - bool bannable; - } context; - - struct drm_i915_error_object { - u64 gtt_offset; - u64 gtt_size; - int page_count; - int unused; - u32 *pages[0]; - } *ringbuffer, *batchbuffer, *wa_batchbuffer, *ctx, *hws_page; - - struct drm_i915_error_object **user_bo; - long user_bo_count; - - struct drm_i915_error_object *wa_ctx; - struct drm_i915_error_object *default_state; - - struct drm_i915_error_request { - long jiffies; - pid_t pid; - u32 context; - int priority; - int ban_score; - u32 seqno; - u32 head; - u32 tail; - } *requests, execlist[EXECLIST_MAX_PORTS]; - unsigned int num_ports; - - struct drm_i915_error_waiter { - char comm[TASK_COMM_LEN]; - pid_t pid; - u32 seqno; - } *waiters; - - struct { - u32 gfx_mode; - union { - u64 pdp[4]; - u32 pp_dir_base; - }; - } vm_info; - } engine[I915_NUM_ENGINES]; - - struct drm_i915_error_buffer { - u32 size; - u32 name; - u32 rseqno[I915_NUM_ENGINES], wseqno; - u64 gtt_offset; - u32 read_domains; - u32 write_domain; - s32 fence_reg:I915_MAX_NUM_FENCE_BITS; - u32 tiling:2; - u32 dirty:1; - u32 purgeable:1; - u32 userptr:1; - s32 engine:4; - u32 cache_level:3; - } *active_bo[I915_NUM_ENGINES], *pinned_bo; - u32 active_bo_count[I915_NUM_ENGINES], pinned_bo_count; - struct i915_address_space *active_vm[I915_NUM_ENGINES]; -}; - enum i915_cache_level { I915_CACHE_NONE = 0, I915_CACHE_LLC, /* also used for snoopable memory on non-LLC */ @@ -1146,16 +980,6 @@ struct i915_gem_mm { u32 object_count; }; -struct drm_i915_error_state_buf { - struct drm_i915_private *i915; - unsigned bytes; - unsigned size; - int err; - u8 *buf; - loff_t start; - loff_t pos; -}; - #define I915_IDLE_ENGINES_TIMEOUT (200) /* in ms */ #define I915_RESET_TIMEOUT (10 * HZ) /* 10s */ @@ -1164,102 +988,6 @@ struct drm_i915_error_state_buf { #define I915_ENGINE_DEAD_TIMEOUT (4 * HZ) /* Seqno, head and subunits dead */ #define I915_SEQNO_DEAD_TIMEOUT (12 * HZ) /* Seqno dead with active head */ -struct i915_gpu_error { - /* For hangcheck timer */ -#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ -#define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD) - - struct delayed_work hangcheck_work; - - /* For reset and error_state handling. */ - spinlock_t lock; - /* Protected by the above dev->gpu_error.lock. */ - struct i915_gpu_state *first_error; - - atomic_t pending_fb_pin; - - unsigned long missed_irq_rings; - - /** - * State variable controlling the reset flow and count - * - * This is a counter which gets incremented when reset is triggered, - * - * Before the reset commences, the I915_RESET_BACKOFF bit is set - * meaning that any waiters holding onto the struct_mutex should - * relinquish the lock immediately in order for the reset to start. - * - * If reset is not completed succesfully, the I915_WEDGE bit is - * set meaning that hardware is terminally sour and there is no - * recovery. All waiters on the reset_queue will be woken when - * that happens. - * - * This counter is used by the wait_seqno code to notice that reset - * event happened and it needs to restart the entire ioctl (since most - * likely the seqno it waited for won't ever signal anytime soon). - * - * This is important for lock-free wait paths, where no contended lock - * naturally enforces the correct ordering between the bail-out of the - * waiter and the gpu reset work code. - */ - unsigned long reset_count; - - /** - * flags: Control various stages of the GPU reset - * - * #I915_RESET_BACKOFF - When we start a reset, we want to stop any - * other users acquiring the struct_mutex. To do this we set the - * #I915_RESET_BACKOFF bit in the error flags when we detect a reset - * and then check for that bit before acquiring the struct_mutex (in - * i915_mutex_lock_interruptible()?). I915_RESET_BACKOFF serves a - * secondary role in preventing two concurrent global reset attempts. - * - * #I915_RESET_HANDOFF - To perform the actual GPU reset, we need the - * struct_mutex. We try to acquire the struct_mutex in the reset worker, - * but it may be held by some long running waiter (that we cannot - * interrupt without causing trouble). Once we are ready to do the GPU - * reset, we set the I915_RESET_HANDOFF bit and wakeup any waiters. If - * they already hold the struct_mutex and want to participate they can - * inspect the bit and do the reset directly, otherwise the worker - * waits for the struct_mutex. - * - * #I915_RESET_ENGINE[num_engines] - Since the driver doesn't need to - * acquire the struct_mutex to reset an engine, we need an explicit - * flag to prevent two concurrent reset attempts in the same engine. - * As the number of engines continues to grow, allocate the flags from - * the most significant bits. - * - * #I915_WEDGED - If reset fails and we can no longer use the GPU, - * we set the #I915_WEDGED bit. Prior to command submission, e.g. - * i915_request_alloc(), this bit is checked and the sequence - * aborted (with -EIO reported to userspace) if set. - */ - unsigned long flags; -#define I915_RESET_BACKOFF 0 -#define I915_RESET_HANDOFF 1 -#define I915_RESET_MODESET 2 -#define I915_WEDGED (BITS_PER_LONG - 1) -#define I915_RESET_ENGINE (I915_WEDGED - I915_NUM_ENGINES) - - /** Number of times an engine has been reset */ - u32 reset_engine_count[I915_NUM_ENGINES]; - - /** - * Waitqueue to signal when a hang is detected. Used to for waiters - * to release the struct_mutex for the reset to procede. - */ - wait_queue_head_t wait_queue; - - /** - * Waitqueue to signal when the reset has completed. Used by clients - * that wait for dev_priv->mm.wedged to settle. - */ - wait_queue_head_t reset_queue; - - /* For missed irq/seqno simulation. */ - unsigned long test_irq_rings; -}; - enum modeset_restore { MODESET_ON_LID_OPEN, MODESET_DONE, @@ -3589,64 +3317,6 @@ static inline int i915_debugfs_connector_add(struct drm_connector *connector) static inline void intel_display_crc_init(struct drm_i915_private *dev_priv) {} #endif -/* i915_gpu_error.c */ -#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) - -__printf(2, 3) -void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...); -int i915_error_state_to_str(struct drm_i915_error_state_buf *estr, - const struct i915_gpu_state *gpu); -int i915_error_state_buf_init(struct drm_i915_error_state_buf *eb, - struct drm_i915_private *i915, - size_t count, loff_t pos); -static inline void i915_error_state_buf_release( - struct drm_i915_error_state_buf *eb) -{ - kfree(eb->buf); -} - -struct i915_gpu_state *i915_capture_gpu_state(struct drm_i915_private *i915); -void i915_capture_error_state(struct drm_i915_private *dev_priv, - u32 engine_mask, - const char *error_msg); - -static inline struct i915_gpu_state * -i915_gpu_state_get(struct i915_gpu_state *gpu) -{ - kref_get(&gpu->ref); - return gpu; -} - -void __i915_gpu_state_free(struct kref *kref); -static inline void i915_gpu_state_put(struct i915_gpu_state *gpu) -{ - if (gpu) - kref_put(&gpu->ref, __i915_gpu_state_free); -} - -struct i915_gpu_state *i915_first_error_state(struct drm_i915_private *i915); -void i915_reset_error_state(struct drm_i915_private *i915); - -#else - -static inline void i915_capture_error_state(struct drm_i915_private *dev_priv, - u32 engine_mask, - const char *error_msg) -{ -} - -static inline struct i915_gpu_state * -i915_first_error_state(struct drm_i915_private *i915) -{ - return NULL; -} - -static inline void i915_reset_error_state(struct drm_i915_private *i915) -{ -} - -#endif - const char *i915_cache_level_str(struct drm_i915_private *i915, int type); /* i915_cmd_parser.c */ diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index f89ac7a8f95f..effaf982b19b 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -32,6 +32,7 @@ #include #include +#include "i915_gpu_error.h" #include "i915_drv.h" static inline const struct intel_engine_cs * diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h new file mode 100644 index 000000000000..ebbdf37e2879 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -0,0 +1,356 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright � 2008-2018 Intel Corporation + */ + +#ifndef _I915_GPU_ERROR_H_ +#define _I915_GPU_ERROR_H_ + +#include +#include +#include + +#include + +#include "intel_device_info.h" +#include "intel_ringbuffer.h" +#include "intel_uc_fw.h" + +#include "i915_gem.h" +#include "i915_gem_gtt.h" +#include "i915_params.h" + +struct drm_i915_private; +struct intel_overlay_error_state; +struct intel_display_error_state; + +struct i915_gpu_state { + struct kref ref; + ktime_t time; + ktime_t boottime; + ktime_t uptime; + + struct drm_i915_private *i915; + + char error_msg[128]; + bool simulated; + bool awake; + bool wakelock; + bool suspended; + int iommu; + u32 reset_count; + u32 suspend_count; + struct intel_device_info device_info; + struct intel_driver_caps driver_caps; + struct i915_params params; + + struct i915_error_uc { + struct intel_uc_fw guc_fw; + struct intel_uc_fw huc_fw; + struct drm_i915_error_object *guc_log; + } uc; + + /* Generic register state */ + u32 eir; + u32 pgtbl_er; + u32 ier; + u32 gtier[4], ngtier; + u32 ccid; + u32 derrmr; + u32 forcewake; + u32 error; /* gen6+ */ + u32 err_int; /* gen7 */ + u32 fault_data0; /* gen8, gen9 */ + u32 fault_data1; /* gen8, gen9 */ + u32 done_reg; + u32 gac_eco; + u32 gam_ecochk; + u32 gab_ctl; + u32 gfx_mode; + + u32 nfence; + u64 fence[I915_MAX_NUM_FENCES]; + struct intel_overlay_error_state *overlay; + struct intel_display_error_state *display; + + struct drm_i915_error_engine { + int engine_id; + /* Software tracked state */ + bool idle; + bool waiting; + int num_waiters; + unsigned long hangcheck_timestamp; + bool hangcheck_stalled; + enum intel_engine_hangcheck_action hangcheck_action; + struct i915_address_space *vm; + int num_requests; + u32 reset_count; + + /* position of active request inside the ring */ + u32 rq_head, rq_post, rq_tail; + + /* our own tracking of ring head and tail */ + u32 cpu_ring_head; + u32 cpu_ring_tail; + + u32 last_seqno; + + /* Register state */ + u32 start; + u32 tail; + u32 head; + u32 ctl; + u32 mode; + u32 hws; + u32 ipeir; + u32 ipehr; + u32 bbstate; + u32 instpm; + u32 instps; + u32 seqno; + u64 bbaddr; + u64 acthd; + u32 fault_reg; + u64 faddr; + u32 rc_psmi; /* sleep state */ + u32 semaphore_mboxes[I915_NUM_ENGINES - 1]; + struct intel_instdone instdone; + + struct drm_i915_error_context { + char comm[TASK_COMM_LEN]; + pid_t pid; + u32 handle; + u32 hw_id; + int priority; + int ban_score; + int active; + int guilty; + bool bannable; + } context; + + struct drm_i915_error_object { + u64 gtt_offset; + u64 gtt_size; + int page_count; + int unused; + u32 *pages[0]; + } *ringbuffer, *batchbuffer, *wa_batchbuffer, *ctx, *hws_page; + + struct drm_i915_error_object **user_bo; + long user_bo_count; + + struct drm_i915_error_object *wa_ctx; + struct drm_i915_error_object *default_state; + + struct drm_i915_error_request { + long jiffies; + pid_t pid; + u32 context; + int priority; + int ban_score; + u32 seqno; + u32 head; + u32 tail; + } *requests, execlist[EXECLIST_MAX_PORTS]; + unsigned int num_ports; + + struct drm_i915_error_waiter { + char comm[TASK_COMM_LEN]; + pid_t pid; + u32 seqno; + } *waiters; + + struct { + u32 gfx_mode; + union { + u64 pdp[4]; + u32 pp_dir_base; + }; + } vm_info; + } engine[I915_NUM_ENGINES]; + + struct drm_i915_error_buffer { + u32 size; + u32 name; + u32 rseqno[I915_NUM_ENGINES], wseqno; + u64 gtt_offset; + u32 read_domains; + u32 write_domain; + s32 fence_reg:I915_MAX_NUM_FENCE_BITS; + u32 tiling:2; + u32 dirty:1; + u32 purgeable:1; + u32 userptr:1; + s32 engine:4; + u32 cache_level:3; + } *active_bo[I915_NUM_ENGINES], *pinned_bo; + u32 active_bo_count[I915_NUM_ENGINES], pinned_bo_count; + struct i915_address_space *active_vm[I915_NUM_ENGINES]; +}; + +struct i915_gpu_error { + /* For hangcheck timer */ +#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ +#define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD) + + struct delayed_work hangcheck_work; + + /* For reset and error_state handling. */ + spinlock_t lock; + /* Protected by the above dev->gpu_error.lock. */ + struct i915_gpu_state *first_error; + + atomic_t pending_fb_pin; + + unsigned long missed_irq_rings; + + /** + * State variable controlling the reset flow and count + * + * This is a counter which gets incremented when reset is triggered, + * + * Before the reset commences, the I915_RESET_BACKOFF bit is set + * meaning that any waiters holding onto the struct_mutex should + * relinquish the lock immediately in order for the reset to start. + * + * If reset is not completed successfully, the I915_WEDGE bit is + * set meaning that hardware is terminally sour and there is no + * recovery. All waiters on the reset_queue will be woken when + * that happens. + * + * This counter is used by the wait_seqno code to notice that reset + * event happened and it needs to restart the entire ioctl (since most + * likely the seqno it waited for won't ever signal anytime soon). + * + * This is important for lock-free wait paths, where no contended lock + * naturally enforces the correct ordering between the bail-out of the + * waiter and the gpu reset work code. + */ + unsigned long reset_count; + + /** + * flags: Control various stages of the GPU reset + * + * #I915_RESET_BACKOFF - When we start a reset, we want to stop any + * other users acquiring the struct_mutex. To do this we set the + * #I915_RESET_BACKOFF bit in the error flags when we detect a reset + * and then check for that bit before acquiring the struct_mutex (in + * i915_mutex_lock_interruptible()?). I915_RESET_BACKOFF serves a + * secondary role in preventing two concurrent global reset attempts. + * + * #I915_RESET_HANDOFF - To perform the actual GPU reset, we need the + * struct_mutex. We try to acquire the struct_mutex in the reset worker, + * but it may be held by some long running waiter (that we cannot + * interrupt without causing trouble). Once we are ready to do the GPU + * reset, we set the I915_RESET_HANDOFF bit and wakeup any waiters. If + * they already hold the struct_mutex and want to participate they can + * inspect the bit and do the reset directly, otherwise the worker + * waits for the struct_mutex. + * + * #I915_RESET_ENGINE[num_engines] - Since the driver doesn't need to + * acquire the struct_mutex to reset an engine, we need an explicit + * flag to prevent two concurrent reset attempts in the same engine. + * As the number of engines continues to grow, allocate the flags from + * the most significant bits. + * + * #I915_WEDGED - If reset fails and we can no longer use the GPU, + * we set the #I915_WEDGED bit. Prior to command submission, e.g. + * i915_request_alloc(), this bit is checked and the sequence + * aborted (with -EIO reported to userspace) if set. + */ + unsigned long flags; +#define I915_RESET_BACKOFF 0 +#define I915_RESET_HANDOFF 1 +#define I915_RESET_MODESET 2 +#define I915_WEDGED (BITS_PER_LONG - 1) +#define I915_RESET_ENGINE (I915_WEDGED - I915_NUM_ENGINES) + + /** Number of times an engine has been reset */ + u32 reset_engine_count[I915_NUM_ENGINES]; + + /** + * Waitqueue to signal when a hang is detected. Used to for waiters + * to release the struct_mutex for the reset to procede. + */ + wait_queue_head_t wait_queue; + + /** + * Waitqueue to signal when the reset has completed. Used by clients + * that wait for dev_priv->mm.wedged to settle. + */ + wait_queue_head_t reset_queue; + + /* For missed irq/seqno simulation. */ + unsigned long test_irq_rings; +}; + +struct drm_i915_error_state_buf { + struct drm_i915_private *i915; + unsigned int bytes; + unsigned int size; + int err; + u8 *buf; + loff_t start; + loff_t pos; +}; + +#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) + +__printf(2, 3) +void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...); +int i915_error_state_to_str(struct drm_i915_error_state_buf *estr, + const struct i915_gpu_state *gpu); +int i915_error_state_buf_init(struct drm_i915_error_state_buf *eb, + struct drm_i915_private *i915, + size_t count, loff_t pos); + +static inline void +i915_error_state_buf_release(struct drm_i915_error_state_buf *eb) +{ + kfree(eb->buf); +} + +struct i915_gpu_state *i915_capture_gpu_state(struct drm_i915_private *i915); +void i915_capture_error_state(struct drm_i915_private *dev_priv, + u32 engine_mask, + const char *error_msg); + +static inline struct i915_gpu_state * +i915_gpu_state_get(struct i915_gpu_state *gpu) +{ + kref_get(&gpu->ref); + return gpu; +} + +void __i915_gpu_state_free(struct kref *kref); +static inline void i915_gpu_state_put(struct i915_gpu_state *gpu) +{ + if (gpu) + kref_put(&gpu->ref, __i915_gpu_state_free); +} + +struct i915_gpu_state *i915_first_error_state(struct drm_i915_private *i915); +void i915_reset_error_state(struct drm_i915_private *i915); + +#else + +static inline void i915_capture_error_state(struct drm_i915_private *dev_priv, + u32 engine_mask, + const char *error_msg) +{ +} + +static inline struct i915_gpu_state * +i915_first_error_state(struct drm_i915_private *i915) +{ + return NULL; +} + +static inline void i915_reset_error_state(struct drm_i915_private *i915) +{ +} + +#endif /* IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) */ + +#endif /* _I915_GPU_ERROR_H_ */ -- cgit v1.2.3 From caa1fd660e6f6701255544a3586a498676527fa4 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 8 Mar 2018 16:52:18 -0800 Subject: drm/i915/psr: Display WA 0884 applied broadly for more HW tracking. WA 0884:bxt:all,cnl:*:A - "When FBC is enabled with eDP PSR, the CPU host modify writes may not get updated on the Display as expected. WA: Write 0x00000000 to CUR_SURFLIVE_A with every CPU host modify write to trigger PSR exit." We can also find on spec other cases where they describe bogus writes to cursor registers to force PSR exit with HW tracking. And it was confirmed by HW engineers that this Wa can be safely applied for any frontbuffer activity. So let's use this more and more here instead of forcibly disable and re-enable PSR everytime that we have a simple reliable flush case. Other commits improve the fbcon/fbdev use a lot, but this approach is the only when where we can get a fully reliable console with no slowness or missed frames and PSR still enabled and active. v2: - Rebase on drm-tip - (DK) Add a comment to explain that WA tells about writing 0 to CUR_SURFLIVE_A but we write to CUR_SURFLIVE(pipe). v3: Wa doesn't work on PSR2. Cc: Dhinakaran Pandiyan Signed-off-by: Rodrigo Vivi Reviewed-by: Dhinakaran Pandiyan Link: https://patchwork.freedesktop.org/patch/msgid/20180309005218.26772-1-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_psr.c | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9e765462ca44..60febfb33154 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6032,6 +6032,9 @@ enum { #define IVB_CURSOR_B_OFFSET 0x71080 #define IVB_CURSOR_C_OFFSET 0x72080 +#define _CUR_SURLIVE 0x700AC +#define CUR_SURLIVE(pipe) _CURSOR2(pipe, _CUR_SURLIVE) + /* Display A control */ #define _DSPACNTR 0x70180 #define DISPLAY_PLANE_ENABLE (1<<31) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 23175c5c4a50..975ebb51c7af 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -1027,8 +1027,23 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, dev_priv->psr.busy_frontbuffer_bits &= ~frontbuffer_bits; /* By definition flush = invalidate + flush */ - if (frontbuffer_bits) - intel_psr_exit(dev_priv); + if (frontbuffer_bits) { + if (dev_priv->psr.psr2_support || + IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { + intel_psr_exit(dev_priv); + } else { + /* + * Display WA #0884: all + * This documented WA for bxt can be safely applied + * broadly so we can force HW tracking to exit PSR + * instead of disabling and re-enabling. + * Workaround tells us to write 0 to CUR_SURLIVE_A, + * but it makes more sense write to the current active + * pipe. + */ + I915_WRITE(CUR_SURLIVE(pipe), 0); + } + } if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits) if (!work_busy(&dev_priv->psr.work.work)) -- cgit v1.2.3 From 6f9ec414ec47eea3f3e2c5ad4c67b4265bbff2a3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 8 Mar 2018 14:07:32 +0000 Subject: drm/i915: Remove the impedance mismatch around intel_engine_enable_signaling There is some redundancy between dma_fence->ops->enable_signaling (via i915_fence_enable_signaling) and our backend, intel_engine_enable_signaling() in that both levels recheck the fence status multiple times. If we convert intel_engine_enable_signaling() to return the information desired by dma_fence->ops->enable_signaling, we can reduce i915_fence_enable_signaling to a simple stub and avoid trying to reinterpret the same information. Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Mika Kuoppala Cc: Michal Winiarski Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180308140732.25090-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_request.c | 6 +----- drivers/gpu/drm/i915/intel_breadcrumbs.c | 21 +++++++++++++-------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 2f62acd2dc3d..1810fa1b81cb 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -59,11 +59,7 @@ static bool i915_fence_signaled(struct dma_fence *fence) static bool i915_fence_enable_signaling(struct dma_fence *fence) { - if (i915_fence_signaled(fence)) - return false; - - intel_engine_enable_signaling(to_request(fence), true); - return !i915_fence_signaled(fence); + return intel_engine_enable_signaling(to_request(fence), true); } static signed long i915_fence_wait(struct dma_fence *fence, diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c index 1f79e7a47433..671a6d61e29d 100644 --- a/drivers/gpu/drm/i915/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c @@ -730,10 +730,11 @@ static void insert_signal(struct intel_breadcrumbs *b, list_add(&request->signaling.link, &iter->signaling.link); } -void intel_engine_enable_signaling(struct i915_request *request, bool wakeup) +bool intel_engine_enable_signaling(struct i915_request *request, bool wakeup) { struct intel_engine_cs *engine = request->engine; struct intel_breadcrumbs *b = &engine->breadcrumbs; + struct intel_wait *wait = &request->signaling.wait; u32 seqno; /* @@ -750,12 +751,12 @@ void intel_engine_enable_signaling(struct i915_request *request, bool wakeup) seqno = i915_request_global_seqno(request); if (!seqno) /* will be enabled later upon execution */ - return; + return true; - GEM_BUG_ON(request->signaling.wait.seqno); - request->signaling.wait.tsk = b->signaler; - request->signaling.wait.request = request; - request->signaling.wait.seqno = seqno; + GEM_BUG_ON(wait->seqno); + wait->tsk = b->signaler; + wait->request = request; + wait->seqno = seqno; /* * Add ourselves into the list of waiters, but registering our @@ -768,11 +769,15 @@ void intel_engine_enable_signaling(struct i915_request *request, bool wakeup) */ spin_lock(&b->rb_lock); insert_signal(b, request, seqno); - wakeup &= __intel_engine_add_wait(engine, &request->signaling.wait); + wakeup &= __intel_engine_add_wait(engine, wait); spin_unlock(&b->rb_lock); - if (wakeup) + if (wakeup) { wake_up_process(b->signaler); + return !intel_wait_complete(wait); + } + + return true; } void intel_engine_cancel_signaling(struct i915_request *request) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index c31258d27e20..81cdbbf257ec 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -940,7 +940,7 @@ bool intel_engine_add_wait(struct intel_engine_cs *engine, struct intel_wait *wait); void intel_engine_remove_wait(struct intel_engine_cs *engine, struct intel_wait *wait); -void intel_engine_enable_signaling(struct i915_request *request, bool wakeup); +bool intel_engine_enable_signaling(struct i915_request *request, bool wakeup); void intel_engine_cancel_signaling(struct i915_request *request); static inline bool intel_engine_has_waiter(const struct intel_engine_cs *engine) -- cgit v1.2.3 From 3c33fc7c1af9a3426eff9015e5bab08a21a5fa9d Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 12 Mar 2018 13:03:06 +0000 Subject: drm/i915/uc: Sanitize uC options early We are sanitizing uC related modparams together with other driver modparams in intel_sanitize_options called from i915_driver_init_hw, but this is too late for us as we will want to use USES_GUC/USES_HUC macros at earlier stage. Since our sanitizing does not require any MMIO access, we can do it in intel_uc_init_early right after we resolve firmware names. Signed-off-by: Michal Wajdeczko Cc: Sagar Arun Kamble Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180312130308.22952-2-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 2 -- drivers/gpu/drm/i915/intel_uc.c | 6 ++++-- drivers/gpu/drm/i915/intel_uc.h | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 987c6770d1a6..0126b222ab7f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1074,8 +1074,6 @@ static void intel_sanitize_options(struct drm_i915_private *dev_priv) i915_modparams.enable_ppgtt); DRM_DEBUG_DRIVER("ppgtt mode: %i\n", i915_modparams.enable_ppgtt); - intel_uc_sanitize_options(dev_priv); - intel_gvt_sanitize_options(dev_priv); } diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 1c1a00df010b..6dec6d67f4ad 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -83,7 +83,7 @@ static int __get_default_guc_log_level(struct drm_i915_private *dev_priv) } /** - * intel_uc_sanitize_options - sanitize uC related modparam options + * sanitize_options_early - sanitize uC related modparam options * @dev_priv: device private * * In case of "enable_guc" option this function will attempt to modify @@ -99,7 +99,7 @@ static int __get_default_guc_log_level(struct drm_i915_private *dev_priv) * 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) +static void sanitize_options_early(struct drm_i915_private *dev_priv) { struct intel_uc_fw *guc_fw = &dev_priv->guc.fw; struct intel_uc_fw *huc_fw = &dev_priv->huc.fw; @@ -163,6 +163,8 @@ void intel_uc_init_early(struct drm_i915_private *dev_priv) { intel_guc_init_early(&dev_priv->guc); intel_huc_init_early(&dev_priv->huc); + + sanitize_options_early(dev_priv); } void intel_uc_init_fw(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 d6af984cd789..49b5b2f274bc 100644 --- a/drivers/gpu/drm/i915/intel_uc.h +++ b/drivers/gpu/drm/i915/intel_uc.h @@ -28,7 +28,6 @@ #include "intel_huc.h" #include "i915_params.h" -void intel_uc_sanitize_options(struct drm_i915_private *dev_priv); void intel_uc_init_early(struct drm_i915_private *dev_priv); void intel_uc_init_mmio(struct drm_i915_private *dev_priv); int intel_uc_register(struct drm_i915_private *dev_priv); -- cgit v1.2.3 From c37d57282033067edf60e044229a4b4f367cc81b Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 12 Mar 2018 13:03:07 +0000 Subject: drm/i915/uc: Sanitize uC together with GEM Instead of dancing around uC on reset/suspend/resume scenarios, explicitly sanitize uC when we sanitize GEM to force uC reload and start from known beginning. v2: don't forget about reset path (Daniele) sanitize uc before gem initiated full reset (Daniele) v3: drop redundant disable_communication in init_hw (Daniele) Signed-off-by: Michal Wajdeczko Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Chris Wilson Cc: Michel Thierry Reviewed-by: Daniele Ceraolo Spurio Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180312130308.22952-3-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/i915_gem.c | 2 ++ drivers/gpu/drm/i915/intel_guc.h | 6 ++++++ drivers/gpu/drm/i915/intel_huc.h | 6 ++++++ drivers/gpu/drm/i915/intel_uc.c | 19 ++++++++++++++++++- drivers/gpu/drm/i915/intel_uc.h | 1 + drivers/gpu/drm/i915/intel_uc_fw.h | 6 ++++++ 6 files changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e58b741e2ec0..05b0724b60dc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2998,6 +2998,7 @@ int i915_gem_reset_prepare(struct drm_i915_private *dev_priv) } i915_gem_revoke_fences(dev_priv); + intel_uc_sanitize(dev_priv); return err; } @@ -4978,6 +4979,7 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv) * machines is a good idea, we don't - just in case it leaves the * machine in an unusable condition. */ + intel_uc_sanitize(dev_priv); i915_gem_sanitize(dev_priv); intel_runtime_pm_put(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 6d5aebe55039..d878160ee6e5 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -133,4 +133,10 @@ int intel_guc_resume(struct intel_guc *guc); struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size); u32 intel_guc_wopcm_size(struct drm_i915_private *dev_priv); +static inline int intel_guc_sanitize(struct intel_guc *guc) +{ + intel_uc_fw_sanitize(&guc->fw); + return 0; +} + #endif diff --git a/drivers/gpu/drm/i915/intel_huc.h b/drivers/gpu/drm/i915/intel_huc.h index 5d6e804f9771..b1858503c451 100644 --- a/drivers/gpu/drm/i915/intel_huc.h +++ b/drivers/gpu/drm/i915/intel_huc.h @@ -38,4 +38,10 @@ struct intel_huc { void intel_huc_init_early(struct intel_huc *huc); int intel_huc_auth(struct intel_huc *huc); +static inline int intel_huc_sanitize(struct intel_huc *huc) +{ + intel_uc_fw_sanitize(&huc->fw); + return 0; +} + #endif diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 6dec6d67f4ad..9d5ffd74c16a 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -334,6 +334,24 @@ void intel_uc_fini(struct drm_i915_private *dev_priv) intel_guc_fini(guc); } +void intel_uc_sanitize(struct drm_i915_private *i915) +{ + struct intel_guc *guc = &i915->guc; + struct intel_huc *huc = &i915->huc; + + if (!USES_GUC(i915)) + return; + + GEM_BUG_ON(!HAS_GUC(i915)); + + guc_disable_communication(guc); + + intel_huc_sanitize(huc); + intel_guc_sanitize(guc); + + __intel_uc_reset_hw(i915); +} + int intel_uc_init_hw(struct drm_i915_private *dev_priv) { struct intel_guc *guc = &dev_priv->guc; @@ -345,7 +363,6 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) GEM_BUG_ON(!HAS_GUC(dev_priv)); - guc_disable_communication(guc); gen9_reset_guc_interrupts(dev_priv); /* init WOPCM */ diff --git a/drivers/gpu/drm/i915/intel_uc.h b/drivers/gpu/drm/i915/intel_uc.h index 49b5b2f274bc..0a2b413e9cd0 100644 --- a/drivers/gpu/drm/i915/intel_uc.h +++ b/drivers/gpu/drm/i915/intel_uc.h @@ -36,6 +36,7 @@ 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_misc(struct drm_i915_private *dev_priv); void intel_uc_fini_misc(struct drm_i915_private *dev_priv); +void intel_uc_sanitize(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); diff --git a/drivers/gpu/drm/i915/intel_uc_fw.h b/drivers/gpu/drm/i915/intel_uc_fw.h index d5fd4609c785..2601521a4006 100644 --- a/drivers/gpu/drm/i915/intel_uc_fw.h +++ b/drivers/gpu/drm/i915/intel_uc_fw.h @@ -115,6 +115,12 @@ static inline bool intel_uc_fw_is_selected(struct intel_uc_fw *uc_fw) return uc_fw->path != NULL; } +static inline void intel_uc_fw_sanitize(struct intel_uc_fw *uc_fw) +{ + if (uc_fw->load_status == INTEL_UC_FIRMWARE_SUCCESS) + uc_fw->load_status = INTEL_UC_FIRMWARE_PENDING; +} + void intel_uc_fw_fetch(struct drm_i915_private *dev_priv, struct intel_uc_fw *uc_fw); int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, -- cgit v1.2.3 From 7aa0b14ede643fb7c33aaa8e0041de04a0d6f278 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 13 Mar 2018 00:40:54 +0000 Subject: drm/i915: Remove variable length arrays from sseu debugfs printers In order to enable -Wvla to prevent new variable length arrays being used in i915.ko, we first must remove the existing VLA. Inside i915_print_sseu_info(), VLA are used as the actual size of the sseu depends on platform. Replace the VLA with the maximum required. Signed-off-by: Chris Wilson Cc: Lionel Landwerlin Cc: Tvrtko Ursulin Cc: Matthew Auld Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180313004055.25411-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_debugfs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index c4cc8fef11a0..0eac7dcdddbf 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4312,9 +4312,10 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_cache_sharing_fops, static void cherryview_sseu_device_status(struct drm_i915_private *dev_priv, struct sseu_dev_info *sseu) { - int ss_max = 2; +#define SS_MAX 2 + const int ss_max = SS_MAX; + u32 sig1[SS_MAX], sig2[SS_MAX]; int ss; - u32 sig1[ss_max], sig2[ss_max]; sig1[0] = I915_READ(CHV_POWER_SS0_SIG1); sig1[1] = I915_READ(CHV_POWER_SS1_SIG1); @@ -4338,15 +4339,15 @@ static void cherryview_sseu_device_status(struct drm_i915_private *dev_priv, sseu->eu_per_subslice = max_t(unsigned int, sseu->eu_per_subslice, eu_cnt); } +#undef SS_MAX } static void gen10_sseu_device_status(struct drm_i915_private *dev_priv, struct sseu_dev_info *sseu) { const struct intel_device_info *info = INTEL_INFO(dev_priv); + u32 s_reg[6], eu_reg[2 * 4], eu_mask[2]; int s, ss; - u32 s_reg[info->sseu.max_slices]; - u32 eu_reg[2 * info->sseu.max_subslices], eu_mask[2]; for (s = 0; s < info->sseu.max_slices; s++) { /* @@ -4399,9 +4400,8 @@ static void gen9_sseu_device_status(struct drm_i915_private *dev_priv, struct sseu_dev_info *sseu) { const struct intel_device_info *info = INTEL_INFO(dev_priv); + u32 s_reg[3], eu_reg[2 * 4], eu_mask[2]; int s, ss; - u32 s_reg[info->sseu.max_slices]; - u32 eu_reg[2 * info->sseu.max_subslices], eu_mask[2]; for (s = 0; s < info->sseu.max_slices; s++) { s_reg[s] = I915_READ(GEN9_SLICE_PGCTL_ACK(s)); -- cgit v1.2.3 From c5c2b11894f4f862cf243b955ac59bb1a5fe61b9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 13 Mar 2018 00:40:55 +0000 Subject: drm/i915: Warn against variable length arrays VLA are strongly discouraged in the kernel due to ambiguity they impose on the limited stack space and security concerns over manipulating the stack frame. Add -Wvla to our compiler flags so that CI rejects them. Signed-off-by: Chris Wilson Cc: Jani Nikula Cc: Joonas Lahtinen Acked-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180313004055.25411-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 4eee91a3a236..fcb8a7b27ae2 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -12,7 +12,7 @@ # Note the danger in using -Wall -Wextra is that when CI updates gcc we # will most likely get a sudden build breakage... Hopefully we will fix # new warnings before CI updates! -subdir-ccflags-y := -Wall -Wextra +subdir-ccflags-y := -Wall -Wextra -Wvla subdir-ccflags-y += $(call cc-disable-warning, unused-parameter) subdir-ccflags-y += $(call cc-disable-warning, type-limits) subdir-ccflags-y += $(call cc-disable-warning, missing-field-initializers) -- cgit v1.2.3 From c7fb3c6c1893fddbbd39e13066489050c29397c1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 13 Mar 2018 11:31:49 +0000 Subject: drm/i915: Use sseu size for determining eu_regs[] eu_regs[] is written 2*max_slices times (like s_reg[]) but oddly read 2*max_slices + max_subslices/2 times. Allocate the array large enough for the writes to avoid overwriting our stack and worry about the logic later. Fixes: 7aa0b14ede64 ("drm/i915: Remove variable length arrays from sseu debugfs printers") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105479 Signed-off-by: Chris Wilson Cc: Lionel Landwerlin Cc: Tvrtko Ursulin Cc: Matthew Auld Reviewed-by: Lionel Landwerlin Link: https://patchwork.freedesktop.org/patch/msgid/20180313113149.1094-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_debugfs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 0eac7dcdddbf..bc3f7d546d53 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4345,8 +4345,9 @@ static void cherryview_sseu_device_status(struct drm_i915_private *dev_priv, static void gen10_sseu_device_status(struct drm_i915_private *dev_priv, struct sseu_dev_info *sseu) { +#define SS_MAX 6 const struct intel_device_info *info = INTEL_INFO(dev_priv); - u32 s_reg[6], eu_reg[2 * 4], eu_mask[2]; + u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2]; int s, ss; for (s = 0; s < info->sseu.max_slices; s++) { @@ -4394,13 +4395,15 @@ static void gen10_sseu_device_status(struct drm_i915_private *dev_priv, eu_cnt); } } +#undef SS_MAX } static void gen9_sseu_device_status(struct drm_i915_private *dev_priv, struct sseu_dev_info *sseu) { +#define SS_MAX 3 const struct intel_device_info *info = INTEL_INFO(dev_priv); - u32 s_reg[3], eu_reg[2 * 4], eu_mask[2]; + u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2]; int s, ss; for (s = 0; s < info->sseu.max_slices; s++) { @@ -4448,6 +4451,7 @@ static void gen9_sseu_device_status(struct drm_i915_private *dev_priv, eu_cnt); } } +#undef SS_MAX } static void broadwell_sseu_device_status(struct drm_i915_private *dev_priv, -- cgit v1.2.3 From 07bcd99b80477cc4f1b878afb3dec26877fa0ed0 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Tue, 6 Mar 2018 19:34:18 -0800 Subject: drm/i915/frontbuffer: Pull frontbuffer_flush out of gem_obj_pin_to_display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i915_gem_obj_pin_to_display() calls frontbuffer_flush with origin set to DIRTYFB. The callers however are at a vantage point to decide if hardware frontbuffer tracking can do the flush for us. For example, legacy cursor updates, like flips, write to MMIO registers, which then triggers PSR flush by the hardware. Moving frontbuffer_flush out will enable us to skip a software initiated flush by setting origin to FLIP. Thanks to Chris for the idea. v2: Rebased due to Ville adding intel_plane_pin_fb(). Minor code reordering as fb_obj_flush doesn't need struct_mutex (Chris) Cc: Chris Wilson Cc: Ville Syrjälä Cc: Paulo Zanoni Signed-off-by: Dhinakaran Pandiyan Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180307033420.3086-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/i915_gem.c | 9 ++++----- drivers/gpu/drm/i915/intel_display.c | 9 +++++++-- drivers/gpu/drm/i915/intel_fbdev.c | 5 +++-- drivers/gpu/drm/i915/intel_overlay.c | 1 + 4 files changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 05b0724b60dc..58f8cf7d3b40 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4094,9 +4094,10 @@ out: } /* - * Prepare buffer for display plane (scanout, cursors, etc). - * Can be called from an uninterruptible phase (modesetting) and allows - * any flushes to be pipelined (for pageflips). + * Prepare buffer for display plane (scanout, cursors, etc). Can be called from + * an uninterruptible phase (modesetting) and allows any flushes to be pipelined + * (for pageflips). We only flush the caches while preparing the buffer for + * display, the callers are responsible for frontbuffer flush. */ struct i915_vma * i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, @@ -4152,9 +4153,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, vma->display_alignment = max_t(u64, vma->display_alignment, alignment); - /* Treat this as an end-of-frame, like intel_user_framebuffer_dirty() */ __i915_gem_object_flush_for_display(obj); - intel_fb_obj_flush(obj, ORIGIN_DIRTYFB); /* It should now be out of any other write domains, and we can update * the domain values for our changes. diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f424fff477f6..1b2a402e32fa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2858,6 +2858,9 @@ valid_fb: return; } + obj = intel_fb_obj(fb); + intel_fb_obj_flush(obj, ORIGIN_DIRTYFB); + plane_state->src_x = 0; plane_state->src_y = 0; plane_state->src_w = fb->width << 16; @@ -2871,7 +2874,6 @@ valid_fb: intel_state->base.src = drm_plane_state_src(plane_state); intel_state->base.dst = drm_plane_state_dest(plane_state); - obj = intel_fb_obj(fb); if (i915_gem_object_is_tiled(obj)) dev_priv->preserve_bios_swizzle = true; @@ -12793,6 +12795,8 @@ intel_prepare_plane_fb(struct drm_plane *plane, if (ret) return ret; + intel_fb_obj_flush(obj, ORIGIN_DIRTYFB); + if (!new_state->fence) { /* implicit fencing */ struct dma_fence *fence; @@ -13186,8 +13190,9 @@ intel_legacy_cursor_update(struct drm_plane *plane, if (ret) goto out_unlock; - old_fb = old_plane_state->fb; + intel_fb_obj_flush(intel_fb_obj(fb), ORIGIN_DIRTYFB); + old_fb = old_plane_state->fb; i915_gem_track_fb(intel_fb_obj(old_fb), intel_fb_obj(fb), intel_plane->frontbuffer_bit); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 6f12adc06365..65a3313723c9 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -221,6 +221,9 @@ static int intelfb_create(struct drm_fb_helper *helper, goto out_unlock; } + fb = &ifbdev->fb->base; + intel_fb_obj_flush(intel_fb_obj(fb), ORIGIN_DIRTYFB); + info = drm_fb_helper_alloc_fbi(helper); if (IS_ERR(info)) { DRM_ERROR("Failed to allocate fb_info\n"); @@ -230,8 +233,6 @@ static int intelfb_create(struct drm_fb_helper *helper, info->par = helper; - fb = &ifbdev->fb->base; - ifbdev->helper.fb = fb; strcpy(info->fix.id, "inteldrmfb"); diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 36671a937fa4..c2f10d899329 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -807,6 +807,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, ret = PTR_ERR(vma); goto out_pin_section; } + intel_fb_obj_flush(new_bo, ORIGIN_DIRTYFB); ret = i915_vma_put_fence(vma); if (ret) -- cgit v1.2.3 From a694e226fbaefbf3101982e54ca2f014292c540f Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Tue, 6 Mar 2018 19:34:19 -0800 Subject: drm/i915/frontbuffer: HW tracking for cursor moves to fix PSR lags. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DRM_IOCTL_MODE_CURSOR results in frontbuffer flush before the cursor plane MMIOs are written to. But this flush should not be necessary for PSR as hardware tracking triggers PSR exit when MMIOs are written. As for FBC, the spec says "Flips or changes to plane size and panning" cause FBC to be nuked. Use origin == ORIGIN_FLIP so that features can ignore cursor updates in their frontbuffer_flush implementations. /sys/kernel/debug/dri/0/i915_fbc_status shows "Compressing: yes" when I move the cursor around. v3: Use ORIGIN_FLIP now that pin_to_display does not flush frontbuffer. v2: Update comment in i915_gem_object_pin_to_display_plane. (Chris) Cc: Paulo Zanoni Cc: Ville Syrjälä 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/20180307033420.3086-2-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1b2a402e32fa..a7bfa238054c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13190,7 +13190,7 @@ intel_legacy_cursor_update(struct drm_plane *plane, if (ret) goto out_unlock; - intel_fb_obj_flush(intel_fb_obj(fb), ORIGIN_DIRTYFB); + intel_fb_obj_flush(intel_fb_obj(fb), ORIGIN_FLIP); old_fb = old_plane_state->fb; i915_gem_track_fb(intel_fb_obj(old_fb), intel_fb_obj(fb), -- cgit v1.2.3 From 5baf63cc4d7879474221c5a32e4c2adc7ed33add Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Tue, 6 Mar 2018 19:34:20 -0800 Subject: drm/i915/psr: Use more PSR HW tracking. So far we are using frontbuffer tracking for everything and ignoring that PSR has a HW capable HW tracking for many modern usages of GPU on Core platforms and newer Atom ones. One reason for that is that we were trying to keep same infrastructure in place for VLV/CHV than the rest of platforms. But also because when this infrastructure was created the front-buffer-tracking origin wasn't that good and stable how it is today after Paulo reworked it to attend FBC cases. However this PSR implementation without HW tracking died on gen8LP. And newer platforms are starting to demand more HW tracking specially with PSR2 cases in mind. By disabling and re-enabling PSR totally every time we believe someone is going to change the front buffer content we don't allow PSR HW tracking to do this job and specially compromising the whole idea of PSR2 case where the HW tracking detect only the damaged area and do a partial screen update. So, from now on, on the platforms that has hw_tracking let's rely more on HW tracking. This also is the case in used by other drivers and more validated by SV teams. So I hope that this will lead us to less misterious bugs. v2: Only do this for platform that actually has hw tracking. v3 from DK Do this only for flips, small gradual changes are better. Cc: Dhinakaran Pandiyan Cc: Jim Bride Cc: Vathsala Nagaraju Signed-off-by: Rodrigo Vivi Signed-off-by: Dhinakaran Pandiyan Reviewed-by: Jose Roberto de Souza Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180307033420.3086-3-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_drv.h | 3 ++- drivers/gpu/drm/i915/intel_frontbuffer.c | 2 +- drivers/gpu/drm/i915/intel_psr.c | 10 +++++++++- 4 files changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d35f805cb177..74b0e9d8ff62 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -606,6 +606,7 @@ struct i915_psr { bool y_cord_support; bool colorimetry_support; bool alpm; + bool has_hw_tracking; void (*enable_source)(struct intel_dp *, const struct intel_crtc_state *); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 83e5ca889d9c..de6db9196638 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1876,7 +1876,8 @@ void intel_psr_enable(struct intel_dp *intel_dp, void intel_psr_disable(struct intel_dp *intel_dp, const struct intel_crtc_state *old_crtc_state); void intel_psr_invalidate(struct drm_i915_private *dev_priv, - unsigned frontbuffer_bits); + unsigned frontbuffer_bits, + enum fb_op_origin origin); void intel_psr_flush(struct drm_i915_private *dev_priv, unsigned frontbuffer_bits, enum fb_op_origin origin); diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 3a8d3d06c26a..7fff0a0eceb4 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -80,7 +80,7 @@ void __intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, } might_sleep(); - intel_psr_invalidate(dev_priv, frontbuffer_bits); + intel_psr_invalidate(dev_priv, frontbuffer_bits, origin); intel_edp_drrs_invalidate(dev_priv, frontbuffer_bits); intel_fbc_invalidate(dev_priv, frontbuffer_bits, origin); } diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 975ebb51c7af..a079b62a148b 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -957,6 +957,7 @@ void intel_psr_single_frame_update(struct drm_i915_private *dev_priv, * intel_psr_invalidate - Invalidade PSR * @dev_priv: i915 device * @frontbuffer_bits: frontbuffer plane tracking bits + * @origin: which operation caused the invalidate * * Since the hardware frontbuffer tracking has gaps we need to integrate * with the software frontbuffer tracking. This function gets called every @@ -966,7 +967,7 @@ void intel_psr_single_frame_update(struct drm_i915_private *dev_priv, * Dirty frontbuffers relevant to PSR are tracked in busy_frontbuffer_bits." */ void intel_psr_invalidate(struct drm_i915_private *dev_priv, - unsigned frontbuffer_bits) + unsigned frontbuffer_bits, enum fb_op_origin origin) { struct drm_crtc *crtc; enum pipe pipe; @@ -974,6 +975,9 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv, if (!CAN_PSR(dev_priv)) return; + if (dev_priv->psr.has_hw_tracking && origin == ORIGIN_FLIP) + return; + mutex_lock(&dev_priv->psr.lock); if (!dev_priv->psr.enabled) { mutex_unlock(&dev_priv->psr.lock); @@ -1014,6 +1018,9 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, if (!CAN_PSR(dev_priv)) return; + if (dev_priv->psr.has_hw_tracking && origin == ORIGIN_FLIP) + return; + mutex_lock(&dev_priv->psr.lock); if (!dev_priv->psr.enabled) { mutex_unlock(&dev_priv->psr.lock); @@ -1105,6 +1112,7 @@ void intel_psr_init(struct drm_i915_private *dev_priv) dev_priv->psr.activate = vlv_psr_activate; dev_priv->psr.setup_vsc = vlv_psr_setup_vsc; } else { + dev_priv->psr.has_hw_tracking = true; dev_priv->psr.enable_source = hsw_psr_enable_source; dev_priv->psr.disable_source = hsw_psr_disable; dev_priv->psr.enable_sink = hsw_psr_enable_sink; -- cgit v1.2.3 From be74229bd5456729a9e81dabc8aac2fb58a69492 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Mon, 12 Mar 2018 21:42:11 -0700 Subject: drm/i915/psr: Remove PSR active flag from debugfs The flag becomes misleading with flips and cursor moves not modifying it's state as HW takes care of exiting PSR (when HW tracking is enabled) Cc: Rodrigo Vivi Signed-off-by: Dhinakaran Pandiyan Acked-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180313044211.27105-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index bc3f7d546d53..972014b2497d 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2565,7 +2565,6 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) mutex_lock(&dev_priv->psr.lock); 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", dev_priv->psr.busy_frontbuffer_bits); seq_printf(m, "Re-enable work scheduled: %s\n", -- cgit v1.2.3 From a8ada068a5025d738c870851d023b80cf6be0c95 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 12 Mar 2018 14:05:28 -0700 Subject: drm/i915: Move CUR SURFLIVE definition to a better place. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional change. But let's keep definitions clean and cursor related register definitions together. v2: Fix caps x no caps on same reg. Change name to match original reg name. (by Ville). Also fix name on code s/surlive/surflive and on subject s/cur_surlife/cur surflive/. 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/20180312210528.7905-1-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 5 ++--- drivers/gpu/drm/i915/intel_psr.c | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 60febfb33154..38d4be46462f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6009,6 +6009,7 @@ enum { #define CURSIZE _MMIO(0x700a0) /* 845/865 */ #define _CUR_FBC_CTL_A 0x700a0 /* ivb+ */ #define CUR_FBC_CTL_EN (1 << 31) +#define _CURASURFLIVE 0x700ac /* g4x+ */ #define _CURBCNTR 0x700c0 #define _CURBBASE 0x700c4 #define _CURBPOS 0x700c8 @@ -6025,6 +6026,7 @@ enum { #define CURBASE(pipe) _CURSOR2(pipe, _CURABASE) #define CURPOS(pipe) _CURSOR2(pipe, _CURAPOS) #define CUR_FBC_CTL(pipe) _CURSOR2(pipe, _CUR_FBC_CTL_A) +#define CURSURFLIVE(pipe) _CURSOR2(pipe, _CURASURFLIVE) #define CURSOR_A_OFFSET 0x70080 #define CURSOR_B_OFFSET 0x700c0 @@ -6032,9 +6034,6 @@ enum { #define IVB_CURSOR_B_OFFSET 0x71080 #define IVB_CURSOR_C_OFFSET 0x72080 -#define _CUR_SURLIVE 0x700AC -#define CUR_SURLIVE(pipe) _CURSOR2(pipe, _CUR_SURLIVE) - /* Display A control */ #define _DSPACNTR 0x70180 #define DISPLAY_PLANE_ENABLE (1<<31) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index a079b62a148b..317cb4a12693 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -1044,11 +1044,11 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, * This documented WA for bxt can be safely applied * broadly so we can force HW tracking to exit PSR * instead of disabling and re-enabling. - * Workaround tells us to write 0 to CUR_SURLIVE_A, + * Workaround tells us to write 0 to CUR_SURFLIVE_A, * but it makes more sense write to the current active * pipe. */ - I915_WRITE(CUR_SURLIVE(pipe), 0); + I915_WRITE(CURSURFLIVE(pipe), 0); } } -- cgit v1.2.3 From 629820fcd0ddbb7955a37c075e82756da69ea908 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 9 Mar 2018 10:11:14 +0000 Subject: drm/i915: Show GEM_TRACE when detecting a failed GPU idle If we timeout waiting for the GPU to idle, something went seriously wrong. We currently dump the engine state, but we can also dump the ftrace buffer showing our last operations (when available). In passing, note that since commit 559e040f1f08 ("drm/i915: Show the GPU state when declaring wedged", we now show the engine state twice, once in detecting the failed idle and then again on declaring wedged. v2: ftrace_dump() takes a parameter specifying whether to dump all cpu buffers or the local cpu's. Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Cc: Mika Kuoppala Reviewed-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20180309101114.1138-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 11 +---------- drivers/gpu/drm/i915/i915_gem.h | 2 ++ 2 files changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 58f8cf7d3b40..d0624c57d9a6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3672,16 +3672,7 @@ static int wait_for_engines(struct drm_i915_private *i915) if (wait_for(intel_engines_are_idle(i915), I915_IDLE_ENGINES_TIMEOUT)) { dev_err(i915->drm.dev, "Failed to idle engines, declaring wedged!\n"); - if (drm_debug & DRM_UT_DRIVER) { - struct drm_printer p = drm_debug_printer(__func__); - struct intel_engine_cs *engine; - enum intel_engine_id id; - - for_each_engine(engine, i915, id) - intel_engine_dump(engine, &p, - "%s\n", engine->name); - } - + GEM_TRACE_DUMP(); i915_gem_set_wedged(i915); return -EIO; } diff --git a/drivers/gpu/drm/i915/i915_gem.h b/drivers/gpu/drm/i915/i915_gem.h index f54c4ff74ded..8922344fc21b 100644 --- a/drivers/gpu/drm/i915/i915_gem.h +++ b/drivers/gpu/drm/i915/i915_gem.h @@ -53,8 +53,10 @@ #if IS_ENABLED(CONFIG_DRM_I915_TRACE_GEM) #define GEM_TRACE(...) trace_printk(__VA_ARGS__) +#define GEM_TRACE_DUMP() ftrace_dump(DUMP_ALL) #else #define GEM_TRACE(...) do { } while (0) +#define GEM_TRACE_DUMP() do { } while (0) #endif #define I915_NUM_ENGINES 8 -- cgit v1.2.3 From 62801bf615679293957ecdf37cc093a18158a201 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Mon, 12 Mar 2018 21:09:54 -0700 Subject: drm/i915/psr: Comment to clarify SRD_DEBUG is called PSR_MASK SKL+ What was called SRD_DEBUG(0x6F860) on HSW and BDW was renamed to PSR_MASK SKL onwards, add a note next to the macro definition. There is also a different PSR_DEBUG on SKL+ to add to the confusion. Signed-off-by: Dhinakaran Pandiyan Acked-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180313040954.6289-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 38d4be46462f..761bd3a4c5c1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4180,13 +4180,13 @@ enum { #define EDP_PSR_PERF_CNT _MMIO(dev_priv->psr_mmio_base + 0x44) #define EDP_PSR_PERF_CNT_MASK 0xffffff -#define EDP_PSR_DEBUG _MMIO(dev_priv->psr_mmio_base + 0x60) +#define EDP_PSR_DEBUG _MMIO(dev_priv->psr_mmio_base + 0x60) /* PSR_MASK on SKL+ */ #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) #define EDP_PSR_DEBUG_MASK_HPD (1<<25) #define EDP_PSR_DEBUG_MASK_DISP_REG_WRITE (1<<16) -#define EDP_PSR_DEBUG_EXIT_ON_PIXEL_UNDERRUN (1<<15) +#define EDP_PSR_DEBUG_EXIT_ON_PIXEL_UNDERRUN (1<<15) /* SKL+ */ #define EDP_PSR2_CTL _MMIO(0x6f900) #define EDP_PSR2_ENABLE (1<<31) -- cgit v1.2.3 From 3c009e3c468a9c095343febca7de6397c0e78b7d Mon Sep 17 00:00:00 2001 From: Jackie Li Date: Tue, 13 Mar 2018 17:32:49 -0700 Subject: drm/i915/guc: Rename guc_ggtt_offset to intel_guc_ggtt_offset GuC related exported functions should start with "intel_guc_" prefix and pass intel_guc as the first parameter since its GuC related. Current guc_ggtt_offset() failed to follow this code convention and this is a problem for future patches that needs to access intel_guc data to verify the GGTT offset against the GuC WOPCM top. This patch renames the guc_ggtt_offset to intel_guc_ggtt_offset and updates the related code to pass intel_guc pointer to this function call, so that we can have a unified coding style for GuC code and also enable the future patches to get GuC related data from intel_guc to do the offset verification. Meanwhile, this patch also moves the GUC_GGTT_TOP from intel_guc_regs.h to intel_guc.h since it is not GuC register related definition. v8: - Fixed coding style issues and moved GUC_GGTT_TOP to intel_guc.h (Sagar) - Updated commit message to explain to reason and motivation to add intel_guc as the first parameter of intel_guc_ggtt_offset (Chris) v9: - Fixed code alignment issue due to line break (Chris) v10: - Removed unnecessary comments, redundant code and avoided reuse variable to avoid potential issues (Joonas) v13: - Updated the ordering of s-o-b/cc/r-b tags (Sagar) Signed-off-by: Jackie Li Cc: Michal Wajdeczko Cc: Sagar Arun Kamble Cc: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Sagar Arun Kamble (v8) Reviewed-by: Joonas Lahtinen (v9) Reviewed-by: Michal Wajdeczko (v11) Reviewed-by: Joonas Lahtinen (v12) Reviewed-by: Joonas Lahtinen Signed-off-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/1520987574-19351-1-git-send-email-yaodong.li@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 11 ++++++----- drivers/gpu/drm/i915/intel_guc.h | 14 ++++++++++++-- drivers/gpu/drm/i915/intel_guc_ads.c | 8 ++++---- drivers/gpu/drm/i915/intel_guc_ct.c | 5 +++-- drivers/gpu/drm/i915/intel_guc_fw.c | 2 +- drivers/gpu/drm/i915/intel_guc_log.c | 2 +- drivers/gpu/drm/i915/intel_guc_reg.h | 3 --- drivers/gpu/drm/i915/intel_guc_submission.c | 10 +++++----- drivers/gpu/drm/i915/intel_huc.c | 3 ++- drivers/gpu/drm/i915/intel_huc_fw.c | 3 ++- 10 files changed, 36 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 25f92291fd40..78463842ea7b 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -269,8 +269,9 @@ void intel_guc_init_params(struct intel_guc *guc) /* If GuC submission is enabled, set up additional parameters here */ if (USES_GUC_SUBMISSION(dev_priv)) { - u32 ads = guc_ggtt_offset(guc->ads_vma) >> PAGE_SHIFT; - u32 pgs = guc_ggtt_offset(dev_priv->guc.stage_desc_pool); + u32 ads = intel_guc_ggtt_offset(guc, + guc->ads_vma) >> PAGE_SHIFT; + u32 pgs = intel_guc_ggtt_offset(guc, guc->stage_desc_pool); u32 ctx_in_16 = GUC_MAX_STAGE_DESCRIPTORS / 16; params[GUC_CTL_DEBUG] |= ads << GUC_ADS_ADDR_SHIFT; @@ -447,7 +448,7 @@ int intel_guc_suspend(struct intel_guc *guc) u32 data[] = { INTEL_GUC_ACTION_ENTER_S_STATE, GUC_POWER_D1, /* any value greater than GUC_POWER_D0 */ - guc_ggtt_offset(guc->shared_data) + intel_guc_ggtt_offset(guc, guc->shared_data) }; return intel_guc_send(guc, data, ARRAY_SIZE(data)); @@ -471,7 +472,7 @@ int intel_guc_reset_engine(struct intel_guc *guc, data[3] = 0; data[4] = 0; data[5] = guc->execbuf_client->stage_id; - data[6] = guc_ggtt_offset(guc->shared_data); + data[6] = intel_guc_ggtt_offset(guc, guc->shared_data); return intel_guc_send(guc, data, ARRAY_SIZE(data)); } @@ -485,7 +486,7 @@ int intel_guc_resume(struct intel_guc *guc) u32 data[] = { INTEL_GUC_ACTION_EXIT_S_STATE, GUC_POWER_D0, - guc_ggtt_offset(guc->shared_data) + intel_guc_ggtt_offset(guc, guc->shared_data) }; return intel_guc_send(guc, data, ARRAY_SIZE(data)); diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index d878160ee6e5..a1be04eaafda 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -100,13 +100,23 @@ static inline void intel_guc_notify(struct intel_guc *guc) guc->notify(guc); } -/* +/* GuC addresses above GUC_GGTT_TOP also don't map through the GTT */ +#define GUC_GGTT_TOP 0xFEE00000 + +/** + * intel_guc_ggtt_offset() - Get and validate the GGTT offset of @vma + * @guc: intel_guc structure. + * @vma: i915 graphics virtual memory area. + * * GuC does not allow any gfx GGTT address that falls into range [0, WOPCM_TOP), * which is reserved for Boot ROM, SRAM and WOPCM. Currently this top address is * 512K. In order to exclude 0-512K address space from GGTT, all gfx objects * used by GuC is pinned with PIN_OFFSET_BIAS along with size of WOPCM. + * + * Return: GGTT offset that meets the GuC gfx address requirement. */ -static inline u32 guc_ggtt_offset(struct i915_vma *vma) +static inline u32 intel_guc_ggtt_offset(struct intel_guc *guc, + struct i915_vma *vma) { u32 offset = i915_ggtt_offset(vma); diff --git a/drivers/gpu/drm/i915/intel_guc_ads.c b/drivers/gpu/drm/i915/intel_guc_ads.c index ac627534667d..334cb5202e1c 100644 --- a/drivers/gpu/drm/i915/intel_guc_ads.c +++ b/drivers/gpu/drm/i915/intel_guc_ads.c @@ -75,7 +75,7 @@ static void guc_policies_init(struct guc_policies *policies) int intel_guc_ads_create(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); - struct i915_vma *vma; + struct i915_vma *vma, *kernel_ctx_vma; struct page *page; /* The ads obj includes the struct itself and buffers passed to GuC */ struct { @@ -121,9 +121,9 @@ int intel_guc_ads_create(struct intel_guc *guc) * to find it. Note that we have to skip our header (1 page), * because our GuC shared data is there. */ + kernel_ctx_vma = dev_priv->kernel_context->engine[RCS].state; blob->ads.golden_context_lrca = - guc_ggtt_offset(dev_priv->kernel_context->engine[RCS].state) + - skipped_offset; + intel_guc_ggtt_offset(guc, kernel_ctx_vma) + skipped_offset; /* * The GuC expects us to exclude the portion of the context image that @@ -135,7 +135,7 @@ int intel_guc_ads_create(struct intel_guc *guc) blob->ads.eng_state_size[engine->guc_id] = engine->context_size - skipped_size; - base = guc_ggtt_offset(vma); + base = intel_guc_ggtt_offset(guc, 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); diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index 24ad55752396..0a0d3d523c23 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -156,7 +156,8 @@ static int ctch_init(struct intel_guc *guc, err = PTR_ERR(blob); goto err_vma; } - DRM_DEBUG_DRIVER("CT: vma base=%#x\n", guc_ggtt_offset(ctch->vma)); + DRM_DEBUG_DRIVER("CT: vma base=%#x\n", + intel_guc_ggtt_offset(guc, ctch->vma)); /* store pointers to desc and cmds */ for (i = 0; i < ARRAY_SIZE(ctch->ctbs); i++) { @@ -202,7 +203,7 @@ static int ctch_open(struct intel_guc *guc, } /* vma should be already allocated and map'ed */ - base = guc_ggtt_offset(ctch->vma); + base = intel_guc_ggtt_offset(guc, ctch->vma); /* (re)initialize descriptors * cmds buffers are in the second half of the blob page diff --git a/drivers/gpu/drm/i915/intel_guc_fw.c b/drivers/gpu/drm/i915/intel_guc_fw.c index d07f2b985f1c..978668cf82cc 100644 --- a/drivers/gpu/drm/i915/intel_guc_fw.c +++ b/drivers/gpu/drm/i915/intel_guc_fw.c @@ -165,7 +165,7 @@ static int guc_xfer_ucode(struct intel_guc *guc, struct i915_vma *vma) I915_WRITE(DMA_COPY_SIZE, guc_fw->header_size + guc_fw->ucode_size); /* Set the source address for the new blob */ - offset = guc_ggtt_offset(vma) + guc_fw->header_offset; + offset = intel_guc_ggtt_offset(guc, vma) + guc_fw->header_offset; I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset)); I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF); diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 90b395f34808..b9c7bd745565 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -581,7 +581,7 @@ int intel_guc_log_create(struct intel_guc *guc) (GUC_LOG_ISR_PAGES << GUC_LOG_ISR_SHIFT) | (GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT); - offset = guc_ggtt_offset(vma) >> PAGE_SHIFT; /* in pages */ + offset = intel_guc_ggtt_offset(guc, vma) >> PAGE_SHIFT; guc->log.flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags; return 0; diff --git a/drivers/gpu/drm/i915/intel_guc_reg.h b/drivers/gpu/drm/i915/intel_guc_reg.h index 19a9247c5664..711e9e974b7c 100644 --- a/drivers/gpu/drm/i915/intel_guc_reg.h +++ b/drivers/gpu/drm/i915/intel_guc_reg.h @@ -80,9 +80,6 @@ #define GUC_WOPCM_TOP (0x80 << 12) /* 512KB */ #define BXT_GUC_WOPCM_RC6_RESERVED (0x10 << 12) /* 64KB */ -/* GuC addresses above GUC_GGTT_TOP also don't map through the GTT */ -#define GUC_GGTT_TOP 0xFEE00000 - #define GEN8_GT_PM_CONFIG _MMIO(0x138140) #define GEN9LP_GT_PM_CONFIG _MMIO(0x138140) #define GEN9_GT_PM_CONFIG _MMIO(0x13816c) diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 8a8ad2fe158d..33af2930fc79 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -386,8 +386,8 @@ static void guc_stage_desc_init(struct intel_guc *guc, lrc->context_desc = lower_32_bits(ce->lrc_desc); /* The state page is after PPHWSP */ - lrc->ring_lrca = - guc_ggtt_offset(ce->state) + LRC_STATE_PN * PAGE_SIZE; + lrc->ring_lrca = intel_guc_ggtt_offset(guc, ce->state) + + LRC_STATE_PN * PAGE_SIZE; /* XXX: In direct submission, the GuC wants the HW context id * here. In proxy submission, it wants the stage id @@ -395,7 +395,7 @@ static void guc_stage_desc_init(struct intel_guc *guc, lrc->context_id = (client->stage_id << GUC_ELC_CTXID_OFFSET) | (guc_engine_id << GUC_ELC_ENGINE_OFFSET); - lrc->ring_begin = guc_ggtt_offset(ce->ring->vma); + lrc->ring_begin = intel_guc_ggtt_offset(guc, ce->ring->vma); lrc->ring_end = lrc->ring_begin + ce->ring->size - 1; lrc->ring_next_free_location = lrc->ring_begin; lrc->ring_current_tail_pointer_value = 0; @@ -411,7 +411,7 @@ static void guc_stage_desc_init(struct intel_guc *guc, * The doorbell, process descriptor, and workqueue are all parts * of the client object, which the GuC will reference via the GGTT */ - gfx_addr = guc_ggtt_offset(client->vma); + gfx_addr = intel_guc_ggtt_offset(guc, client->vma); desc->db_trigger_phy = sg_dma_address(client->vma->pages->sgl) + client->doorbell_offset; desc->db_trigger_cpu = ptr_to_u64(__get_doorbell(client)); @@ -584,7 +584,7 @@ static void inject_preempt_context(struct work_struct *work) data[3] = engine->guc_id; data[4] = guc->execbuf_client->priority; data[5] = guc->execbuf_client->stage_id; - data[6] = guc_ggtt_offset(guc->shared_data); + data[6] = intel_guc_ggtt_offset(guc, guc->shared_data); if (WARN_ON(intel_guc_send(guc, data, ARRAY_SIZE(data)))) { execlists_clear_active(&engine->execlists, diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c index 65e2afb9b955..858c9543630d 100644 --- a/drivers/gpu/drm/i915/intel_huc.c +++ b/drivers/gpu/drm/i915/intel_huc.c @@ -63,7 +63,8 @@ int intel_huc_auth(struct intel_huc *huc) } ret = intel_guc_auth_huc(guc, - guc_ggtt_offset(vma) + huc->fw.rsa_offset); + intel_guc_ggtt_offset(guc, vma) + + huc->fw.rsa_offset); if (ret) { DRM_ERROR("HuC: GuC did not ack Auth request %d\n", ret); goto fail_unpin; diff --git a/drivers/gpu/drm/i915/intel_huc_fw.c b/drivers/gpu/drm/i915/intel_huc_fw.c index c66afa9b989a..bb0f8b7a8d2b 100644 --- a/drivers/gpu/drm/i915/intel_huc_fw.c +++ b/drivers/gpu/drm/i915/intel_huc_fw.c @@ -118,7 +118,8 @@ static int huc_fw_xfer(struct intel_uc_fw *huc_fw, struct i915_vma *vma) intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); /* Set the source address for the uCode */ - offset = guc_ggtt_offset(vma) + huc_fw->header_offset; + offset = intel_guc_ggtt_offset(&dev_priv->guc, vma) + + huc_fw->header_offset; I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset)); I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF); -- cgit v1.2.3 From 6b0478fb722ae638ad747e17251e90bbf1b7969b Mon Sep 17 00:00:00 2001 From: Jackie Li Date: Tue, 13 Mar 2018 17:32:50 -0700 Subject: drm/i915: Implement dynamic GuC WOPCM offset and size calculation Hardware may have specific restrictions on GuC WOPCM offset and size. On Gen9, the value of the GuC WOPCM size register needs to be larger than the value of GuC WOPCM offset register + a Gen9 specific offset (144KB) for reserved GuC WOPCM. Fail to enforce such a restriction on GuC WOPCM size will lead to GuC firmware execution failures. On the other hand, with current static GuC WOPCM offset and size values (512KB for both offset and size), the GuC WOPCM size verification will fail on Gen9 even if it can be fixed by lowering the GuC WOPCM offset by calculating its value based on HuC firmware size (which is likely less than 200KB on Gen9), so that we can have a GuC WOPCM size value which is large enough to pass the GuC WOPCM size check. This patch updates the reserved GuC WOPCM size for RC6 context on Gen9 to 24KB to strictly align with the Gen9 GuC WOPCM layout. It also adds support to verify the GuC WOPCM size aganist the Gen9 hardware restrictions. To meet all above requirements, let's provide dynamic partitioning of the WOPCM that will be based on platform specific HuC/GuC firmware sizes. v2: - Removed intel_wopcm_init (Ville/Sagar/Joonas) - Renamed and Moved the intel_wopcm_partition into intel_guc (Sagar) - Removed unnecessary function calls (Joonas) - Init GuC WOPCM partition as soon as firmware fetching is completed v3: - Fixed indentation issues (Chris) - Removed layering violation code (Chris/Michal) - Created separat files for GuC wopcm code (Michal) - Used inline function to avoid code duplication (Michal) v4: - Preset the GuC WOPCM top during early GuC init (Chris) - Fail intel_uc_init_hw() as soon as GuC WOPCM partitioning failed v5: - Moved GuC DMA WOPCM register updating code into intel_wopcm.c - Took care of the locking status before writing to GuC DMA Write-Once registers. (Joonas) v6: - Made sure the GuC WOPCM size to be multiple of 4K (4K aligned) v8: - Updated comments and fixed naming issues (Sagar/Joonas) - Updated commit message to include more description about the hardware restriction on GuC WOPCM size (Sagar) v9: - Minor changes variable names and code comments (Sagar) - Added detailed GuC WOPCM layout drawing (Sagar/Michal) - Refined macro definitions to be reader friendly (Michal) - Removed redundent check to valid flag (Michal) - Unified first parameter for exported GuC WOPCM functions (Michal) - Refined the name and parameter list of hardware restriction checking functions (Michal) v10: - Used shorter function name for internal functions (Joonas) - Moved init-ealry function into c file (Joonas) - Consolidated and removed redundant size checks (Joonas/Michal) - Removed unnecessary unlikely() from code which is only called once during boot (Joonas) - More fixes to kernel-doc format and content (Michal) - Avoided the use of PAGE_MASK for 4K pages (Michal) - Added error log messages to error paths (Michal) v11: - Replaced intel_guc_wopcm with more generic intel_wopcm and attached intel_wopcm to drm_i915_private instead intel_guc (Michal) - dynamic calculation of GuC non-wopcm memory start (a.k.a WOPCM Top offset from GuC WOPCM base) (Michal) - Moved WOPCM marco definitions into .c source file (Michal) - Exported WOPCM layout diagram as kernel-doc (Michal) v12: - Updated naming, function kernel-doc to align with new changes (Michal) v13: - Updated the ordering of s-o-b/cc/r-b tags (Sagar) - Corrected one tense error in comment (Sagar) - Corrected typos and removed spurious comments (Joonas) Bspec: 12690 Signed-off-by: Jackie Li Cc: Michal Wajdeczko Cc: Sagar Arun Kamble Cc: Sujaritha Sundaresan Cc: Daniele Ceraolo Spurio Cc: John Spotswood Cc: Oscar Mateo Cc: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Sagar Arun Kamble (v8) Reviewed-by: Joonas Lahtinen (v9) Reviewed-by: Michal Wajdeczko (v11) Reviewed-by: Joonas Lahtinen (v12) Reviewed-by: Joonas Lahtinen Signed-off-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/1520987574-19351-2-git-send-email-yaodong.li@intel.com --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/i915_drv.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 8 ++ drivers/gpu/drm/i915/i915_gem.c | 4 + drivers/gpu/drm/i915/i915_gem_context.c | 5 +- drivers/gpu/drm/i915/intel_guc.c | 66 +++++++++--- drivers/gpu/drm/i915/intel_guc.h | 18 ++-- drivers/gpu/drm/i915/intel_guc_reg.h | 8 +- drivers/gpu/drm/i915/intel_huc.c | 2 +- drivers/gpu/drm/i915/intel_uc.c | 6 +- drivers/gpu/drm/i915/intel_uc_fw.c | 13 +-- drivers/gpu/drm/i915/intel_uc_fw.h | 16 +++ drivers/gpu/drm/i915/intel_wopcm.c | 182 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_wopcm.h | 30 ++++++ 14 files changed, 321 insertions(+), 41 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_wopcm.c create mode 100644 drivers/gpu/drm/i915/intel_wopcm.h (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index fcb8a7b27ae2..552e43e9663f 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -79,7 +79,8 @@ i915-y += i915_cmd_parser.o \ intel_lrc.o \ intel_mocs.o \ intel_ringbuffer.o \ - intel_uncore.o + intel_uncore.o \ + intel_wopcm.o # general-purpose microcontroller (GuC) support i915-y += intel_uc.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0126b222ab7f..f03555efc520 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -919,6 +919,7 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv, mutex_init(&dev_priv->wm.wm_mutex); mutex_init(&dev_priv->pps_mutex); + intel_wopcm_init_early(&dev_priv->wopcm); intel_uc_init_early(dev_priv); i915_memcpy_init_early(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 74b0e9d8ff62..e27ba8fb64e6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -64,6 +64,7 @@ #include "intel_opregion.h" #include "intel_ringbuffer.h" #include "intel_uncore.h" +#include "intel_wopcm.h" #include "intel_uc.h" #include "i915_gem.h" @@ -1589,6 +1590,8 @@ struct drm_i915_private { struct intel_gvt *gvt; + struct intel_wopcm wopcm; + struct intel_huc huc; struct intel_guc guc; @@ -2121,6 +2124,11 @@ static inline struct drm_i915_private *kdev_to_i915(struct device *kdev) return to_i915(dev_get_drvdata(kdev)); } +static inline struct drm_i915_private *wopcm_to_i915(struct intel_wopcm *wopcm) +{ + return container_of(wopcm, struct drm_i915_private, wopcm); +} + static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc) { return container_of(guc, struct drm_i915_private, guc); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d0624c57d9a6..51faa6506739 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5294,6 +5294,10 @@ int i915_gem_init(struct drm_i915_private *dev_priv) if (ret) return ret; + ret = intel_wopcm_init(&dev_priv->wopcm); + if (ret) + return ret; + ret = intel_uc_init_misc(dev_priv); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index f2cbea7cf940..5cfac0255758 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -318,12 +318,13 @@ __create_hw_context(struct drm_i915_private *dev_priv, ctx->desc_template = default_desc_template(dev_priv, dev_priv->mm.aliasing_ppgtt); - /* GuC requires the ring to be placed above GUC_WOPCM_TOP. If GuC is not + /* + * GuC requires the ring to be placed in Non-WOPCM memory. If GuC is not * present or not in use we still need a small bias as ring wraparound * at offset 0 sometimes hangs. No idea why. */ if (USES_GUC(dev_priv)) - ctx->ggtt_offset_bias = GUC_WOPCM_TOP; + ctx->ggtt_offset_bias = dev_priv->guc.ggtt_pin_bias; else ctx->ggtt_offset_bias = I915_GTT_PAGE_SIZE; diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 78463842ea7b..3eb516e7c225 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -492,6 +492,57 @@ int intel_guc_resume(struct intel_guc *guc) return intel_guc_send(guc, data, ARRAY_SIZE(data)); } +/** + * DOC: GuC Address Space + * + * The layout of GuC address space is shown as below: + * + * +==============> +====================+ <== GUC_GGTT_TOP + * ^ | | + * | | | + * | | DRAM | + * | | Memory | + * | | | + * GuC | | + * Address +========> +====================+ <== WOPCM Top + * Space ^ | HW contexts RSVD | + * | | | WOPCM | + * | | +==> +--------------------+ <== GuC WOPCM Top + * | GuC ^ | | + * | GGTT | | | + * | Pin GuC | GuC | + * | Bias WOPCM | WOPCM | + * | | Size | | + * | | | | | + * v v v | | + * +=====+=====+==> +====================+ <== GuC WOPCM Base + * | Non-GuC WOPCM | + * | (HuC/Reserved) | + * +====================+ <== WOPCM Base + * + * The lower part [0, GuC ggtt_pin_bias) is mapped to WOPCM which consists of + * GuC WOPCM and WOPCM reserved for other usage (e.g.RC6 context). The value of + * the GuC ggtt_pin_bias is determined by the actually GuC WOPCM size which is + * set in GUC_WOPCM_SIZE register. + */ + +/** + * intel_guc_init_ggtt_pin_bias() - Initialize the GuC ggtt_pin_bias value. + * @guc: intel_guc structure. + * + * This function will calculate and initialize the ggtt_pin_bias value based on + * overall WOPCM size and GuC WOPCM size. + */ +void intel_guc_init_ggtt_pin_bias(struct intel_guc *guc) +{ + struct drm_i915_private *i915 = guc_to_i915(guc); + + GEM_BUG_ON(!i915->wopcm.size); + GEM_BUG_ON(i915->wopcm.size < i915->wopcm.guc.base); + + guc->ggtt_pin_bias = i915->wopcm.size - i915->wopcm.guc.base; +} + /** * intel_guc_allocate_vma() - Allocate a GGTT VMA for GuC usage * @guc: the guc @@ -500,7 +551,7 @@ int intel_guc_resume(struct intel_guc *guc) * This is a wrapper to create an object for use with the GuC. In order to * use it inside the GuC, an object needs to be pinned lifetime, so we allocate * both some backing storage and a range inside the Global GTT. We must pin - * it in the GGTT somewhere other than than [0, GUC_WOPCM_TOP) because that + * it in the GGTT somewhere other than than [0, GUC ggtt_pin_bias) because that * range is reserved inside GuC. * * Return: A i915_vma if successful, otherwise an ERR_PTR. @@ -521,7 +572,7 @@ struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size) goto err; ret = i915_vma_pin(vma, 0, PAGE_SIZE, - PIN_GLOBAL | PIN_OFFSET_BIAS | GUC_WOPCM_TOP); + PIN_GLOBAL | PIN_OFFSET_BIAS | guc->ggtt_pin_bias); if (ret) { vma = ERR_PTR(ret); goto err; @@ -533,14 +584,3 @@ err: i915_gem_object_put(obj); return vma; } - -u32 intel_guc_wopcm_size(struct drm_i915_private *dev_priv) -{ - u32 wopcm_size = GUC_WOPCM_TOP; - - /* On BXT, the top of WOPCM is reserved for RC6 context */ - if (IS_GEN9_LP(dev_priv)) - wopcm_size -= BXT_GUC_WOPCM_RC6_RESERVED; - - return wopcm_size; -} diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index a1be04eaafda..cdb649a9a4cf 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -49,6 +49,9 @@ struct intel_guc { struct intel_guc_log log; struct intel_guc_ct ct; + /* Offset where Non-WOPCM memory starts. */ + u32 ggtt_pin_bias; + /* Log snapshot if GuC errors during load */ struct drm_i915_gem_object *load_err_log; @@ -108,19 +111,20 @@ static inline void intel_guc_notify(struct intel_guc *guc) * @guc: intel_guc structure. * @vma: i915 graphics virtual memory area. * - * GuC does not allow any gfx GGTT address that falls into range [0, WOPCM_TOP), - * which is reserved for Boot ROM, SRAM and WOPCM. Currently this top address is - * 512K. In order to exclude 0-512K address space from GGTT, all gfx objects - * used by GuC is pinned with PIN_OFFSET_BIAS along with size of WOPCM. + * GuC does not allow any gfx GGTT address that falls into range + * [0, GuC ggtt_pin_bias), which is reserved for Boot ROM, SRAM and WOPCM. + * Currently, in order to exclude [0, GuC ggtt_pin_bias) address space from + * GGTT, all gfx objects used by GuC are allocated with intel_guc_allocate_vma() + * and pinned with PIN_OFFSET_BIAS along with the value of GuC ggtt_pin_bias. * - * Return: GGTT offset that meets the GuC gfx address requirement. + * Return: GGTT offset of the @vma. */ static inline u32 intel_guc_ggtt_offset(struct intel_guc *guc, struct i915_vma *vma) { u32 offset = i915_ggtt_offset(vma); - GEM_BUG_ON(offset < GUC_WOPCM_TOP); + GEM_BUG_ON(offset < guc->ggtt_pin_bias); GEM_BUG_ON(range_overflows_t(u64, offset, vma->size, GUC_GGTT_TOP)); return offset; @@ -129,6 +133,7 @@ static inline u32 intel_guc_ggtt_offset(struct intel_guc *guc, void intel_guc_init_early(struct intel_guc *guc); void intel_guc_init_send_regs(struct intel_guc *guc); void intel_guc_init_params(struct intel_guc *guc); +void intel_guc_init_ggtt_pin_bias(struct intel_guc *guc); int intel_guc_init_wq(struct intel_guc *guc); void intel_guc_fini_wq(struct intel_guc *guc); int intel_guc_init(struct intel_guc *guc); @@ -141,7 +146,6 @@ int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset); int intel_guc_suspend(struct intel_guc *guc); int intel_guc_resume(struct intel_guc *guc); struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size); -u32 intel_guc_wopcm_size(struct drm_i915_private *dev_priv); static inline int intel_guc_sanitize(struct intel_guc *guc) { diff --git a/drivers/gpu/drm/i915/intel_guc_reg.h b/drivers/gpu/drm/i915/intel_guc_reg.h index 711e9e974b7c..01963d085ed6 100644 --- a/drivers/gpu/drm/i915/intel_guc_reg.h +++ b/drivers/gpu/drm/i915/intel_guc_reg.h @@ -68,17 +68,15 @@ #define DMA_GUC_WOPCM_OFFSET _MMIO(0xc340) #define HUC_LOADING_AGENT_VCR (0<<1) #define HUC_LOADING_AGENT_GUC (1<<1) -#define GUC_WOPCM_OFFSET_VALUE 0x80000 /* 512KB */ +#define GUC_WOPCM_OFFSET_SHIFT 14 #define GUC_MAX_IDLE_COUNT _MMIO(0xC3E4) #define HUC_STATUS2 _MMIO(0xD3B0) #define HUC_FW_VERIFIED (1<<7) -/* Defines WOPCM space available to GuC firmware */ #define GUC_WOPCM_SIZE _MMIO(0xc050) -/* GuC addresses below GUC_WOPCM_TOP don't map through the GTT */ -#define GUC_WOPCM_TOP (0x80 << 12) /* 512KB */ -#define BXT_GUC_WOPCM_RC6_RESERVED (0x10 << 12) /* 64KB */ +#define GUC_WOPCM_SIZE_SHIFT 12 +#define GUC_WOPCM_SIZE_MASK (0xfffff << GUC_WOPCM_SIZE_SHIFT) #define GEN8_GT_PM_CONFIG _MMIO(0x138140) #define GEN9LP_GT_PM_CONFIG _MMIO(0x138140) diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c index 858c9543630d..1d6c47b17935 100644 --- a/drivers/gpu/drm/i915/intel_huc.c +++ b/drivers/gpu/drm/i915/intel_huc.c @@ -55,7 +55,7 @@ int intel_huc_auth(struct intel_huc *huc) return -ENOEXEC; vma = i915_gem_object_ggtt_pin(huc->fw.obj, NULL, 0, 0, - PIN_OFFSET_BIAS | GUC_WOPCM_TOP); + PIN_OFFSET_BIAS | guc->ggtt_pin_bias); if (IS_ERR(vma)) { ret = PTR_ERR(vma); DRM_ERROR("HuC: Failed to pin huc fw object %d\n", ret); diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 9d5ffd74c16a..ed5a6fcc8557 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -272,6 +272,8 @@ int intel_uc_init_misc(struct drm_i915_private *dev_priv) if (!USES_GUC(dev_priv)) return 0; + intel_guc_init_ggtt_pin_bias(guc); + ret = intel_guc_init_wq(guc); if (ret) return ret; @@ -366,9 +368,9 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) gen9_reset_guc_interrupts(dev_priv); /* init WOPCM */ - I915_WRITE(GUC_WOPCM_SIZE, intel_guc_wopcm_size(dev_priv)); + I915_WRITE(GUC_WOPCM_SIZE, dev_priv->wopcm.guc.size); I915_WRITE(DMA_GUC_WOPCM_OFFSET, - GUC_WOPCM_OFFSET_VALUE | HUC_LOADING_AGENT_GUC); + dev_priv->wopcm.guc.base | HUC_LOADING_AGENT_GUC); /* WaEnableuKernelHeaderValidFix:skl */ /* WaEnableGuCBootHashCheckNotSet:skl,bxt,kbl */ diff --git a/drivers/gpu/drm/i915/intel_uc_fw.c b/drivers/gpu/drm/i915/intel_uc_fw.c index 3ec0ce505b76..30c73243f54d 100644 --- a/drivers/gpu/drm/i915/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/intel_uc_fw.c @@ -95,15 +95,6 @@ void intel_uc_fw_fetch(struct drm_i915_private *dev_priv, uc_fw->ucode_offset = uc_fw->header_offset + uc_fw->header_size; uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32); - /* Header and uCode will be loaded to WOPCM */ - size = uc_fw->header_size + uc_fw->ucode_size; - if (size > intel_guc_wopcm_size(dev_priv)) { - DRM_WARN("%s: Firmware is too large to fit in WOPCM\n", - intel_uc_fw_type_repr(uc_fw->type)); - err = -E2BIG; - goto fail; - } - /* now RSA */ if (css->key_size_dw != UOS_RSA_SCRATCH_COUNT) { DRM_WARN("%s: Mismatched firmware RSA key size (%u)\n", @@ -208,6 +199,7 @@ int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, int (*xfer)(struct intel_uc_fw *uc_fw, struct i915_vma *vma)) { + struct drm_i915_private *i915 = to_i915(uc_fw->obj->base.dev); struct i915_vma *vma; int err; @@ -231,7 +223,8 @@ int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, } vma = i915_gem_object_ggtt_pin(uc_fw->obj, NULL, 0, 0, - PIN_OFFSET_BIAS | GUC_WOPCM_TOP); + PIN_OFFSET_BIAS | + i915->guc.ggtt_pin_bias); if (IS_ERR(vma)) { err = PTR_ERR(vma); DRM_DEBUG_DRIVER("%s fw ggtt-pin err=%d\n", diff --git a/drivers/gpu/drm/i915/intel_uc_fw.h b/drivers/gpu/drm/i915/intel_uc_fw.h index 2601521a4006..dc33b12394de 100644 --- a/drivers/gpu/drm/i915/intel_uc_fw.h +++ b/drivers/gpu/drm/i915/intel_uc_fw.h @@ -121,6 +121,22 @@ static inline void intel_uc_fw_sanitize(struct intel_uc_fw *uc_fw) uc_fw->load_status = INTEL_UC_FIRMWARE_PENDING; } +/** + * intel_uc_fw_get_upload_size() - Get size of firmware needed to be uploaded. + * @uc_fw: uC firmware. + * + * Get the size of the firmware and header that will be uploaded to WOPCM. + * + * Return: Upload firmware size, or zero on firmware fetch failure. + */ +static inline u32 intel_uc_fw_get_upload_size(struct intel_uc_fw *uc_fw) +{ + if (uc_fw->fetch_status != INTEL_UC_FIRMWARE_SUCCESS) + return 0; + + return uc_fw->header_size + uc_fw->ucode_size; +} + void intel_uc_fw_fetch(struct drm_i915_private *dev_priv, struct intel_uc_fw *uc_fw); int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, diff --git a/drivers/gpu/drm/i915/intel_wopcm.c b/drivers/gpu/drm/i915/intel_wopcm.c new file mode 100644 index 000000000000..7b150d580d4a --- /dev/null +++ b/drivers/gpu/drm/i915/intel_wopcm.c @@ -0,0 +1,182 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright © 2017-2018 Intel Corporation + */ + +#include "intel_wopcm.h" +#include "i915_drv.h" + +/** + * DOC: WOPCM Layout + * + * The layout of the WOPCM will be fixed after writing to GuC WOPCM size and + * offset registers whose are calculated are determined by size of HuC/GuC + * firmware size and set of hw requirements/restrictions as shown below: + * + * +=========> +====================+ <== WOPCM Top + * ^ | HW contexts RSVD | + * | +===> +====================+ <== GuC WOPCM Top + * | ^ | | + * | | | | + * | | | | + * | GuC | | + * | WOPCM | | + * | Size +--------------------+ + * WOPCM | | GuC FW RSVD | + * | | +--------------------+ + * | | | GuC Stack RSVD | + * | | +------------------- + + * | v | GuC WOPCM RSVD | + * | +===> +====================+ <== GuC WOPCM base + * | | WOPCM RSVD | + * | +------------------- + <== HuC Firmware Top + * v | HuC FW | + * +=========> +====================+ <== WOPCM Base + * + * GuC accessible WOPCM starts at GuC WOPCM base and ends at GuC WOPCM top. + * The top part of the WOPCM is reserved for hardware contexts (e.g. RC6 + * context). + */ + +/* Default WOPCM size 1MB. */ +#define GEN9_WOPCM_SIZE (1024 * 1024) +/* 16KB WOPCM (RSVD WOPCM) is reserved from HuC firmware top. */ +#define WOPCM_RESERVED_SIZE (16 * 1024) + +/* 16KB reserved at the beginning of GuC WOPCM. */ +#define GUC_WOPCM_RESERVED (16 * 1024) +/* 8KB from GUC_WOPCM_RESERVED is reserved for GuC stack. */ +#define GUC_WOPCM_STACK_RESERVED (8 * 1024) + +/* GuC WOPCM Offset value needs to be aligned to 16KB. */ +#define GUC_WOPCM_OFFSET_ALIGNMENT (1UL << GUC_WOPCM_OFFSET_SHIFT) + +/* 24KB at the end of WOPCM is reserved for RC6 CTX on BXT. */ +#define BXT_WOPCM_RC6_CTX_RESERVED (24 * 1024) + +/* 128KB from GUC_WOPCM_RESERVED is reserved for FW on Gen9. */ +#define GEN9_GUC_FW_RESERVED (128 * 1024) +#define GEN9_GUC_WOPCM_OFFSET (GUC_WOPCM_RESERVED + GEN9_GUC_FW_RESERVED) + +/** + * intel_wopcm_init_early() - Early initialization of the WOPCM. + * @wopcm: pointer to intel_wopcm. + * + * Setup the size of WOPCM which will be used by later on WOPCM partitioning. + */ +void intel_wopcm_init_early(struct intel_wopcm *wopcm) +{ + wopcm->size = GEN9_WOPCM_SIZE; + + DRM_DEBUG_DRIVER("WOPCM size: %uKiB\n", wopcm->size / 1024); +} + +static inline u32 context_reserved_size(struct drm_i915_private *i915) +{ + if (IS_GEN9_LP(i915)) + return BXT_WOPCM_RC6_CTX_RESERVED; + else + return 0; +} + +static inline int gen9_check_dword_gap(u32 guc_wopcm_base, u32 guc_wopcm_size) +{ + u32 offset; + + /* + * GuC WOPCM size shall be at least a dword larger than the offset from + * WOPCM base (GuC WOPCM offset from WOPCM base + GEN9_GUC_WOPCM_OFFSET) + * due to hardware limitation on Gen9. + */ + offset = guc_wopcm_base + GEN9_GUC_WOPCM_OFFSET; + if (offset > guc_wopcm_size || + (guc_wopcm_size - offset) < sizeof(u32)) { + DRM_ERROR("GuC WOPCM size %uKiB is too small. %uKiB needed.\n", + guc_wopcm_size / 1024, + (u32)(offset + sizeof(u32)) / 1024); + return -E2BIG; + } + + return 0; +} + +static inline int check_hw_restriction(struct drm_i915_private *i915, + u32 guc_wopcm_base, u32 guc_wopcm_size) +{ + int err = 0; + + if (IS_GEN9(i915)) + err = gen9_check_dword_gap(guc_wopcm_base, guc_wopcm_size); + + return err; +} + +/** + * intel_wopcm_init() - Initialize the WOPCM structure. + * @wopcm: pointer to intel_wopcm. + * + * This function will partition WOPCM space based on GuC and HuC firmware sizes + * and will allocate max remaining for use by GuC. This function will also + * enforce platform dependent hardware restrictions on GuC WOPCM offset and + * size. It will fail the WOPCM init if any of these checks were failed, so that + * the following GuC firmware uploading would be aborted. + * + * Return: 0 on success, non-zero error code on failure. + */ +int intel_wopcm_init(struct intel_wopcm *wopcm) +{ + struct drm_i915_private *i915 = wopcm_to_i915(wopcm); + u32 guc_fw_size = intel_uc_fw_get_upload_size(&i915->guc.fw); + u32 huc_fw_size = intel_uc_fw_get_upload_size(&i915->huc.fw); + u32 ctx_rsvd = context_reserved_size(i915); + u32 guc_wopcm_base; + u32 guc_wopcm_size; + u32 guc_wopcm_rsvd; + int err; + + GEM_BUG_ON(!wopcm->size); + + if (guc_fw_size >= wopcm->size) { + DRM_ERROR("GuC FW (%uKiB) is too big to fit in WOPCM.", + guc_fw_size / 1024); + return -E2BIG; + } + + if (huc_fw_size >= wopcm->size) { + DRM_ERROR("HuC FW (%uKiB) is too big to fit in WOPCM.", + huc_fw_size / 1024); + return -E2BIG; + } + + guc_wopcm_base = ALIGN(huc_fw_size + WOPCM_RESERVED_SIZE, + GUC_WOPCM_OFFSET_ALIGNMENT); + if ((guc_wopcm_base + ctx_rsvd) >= wopcm->size) { + DRM_ERROR("GuC WOPCM base (%uKiB) is too big.\n", + guc_wopcm_base / 1024); + return -E2BIG; + } + + guc_wopcm_size = wopcm->size - guc_wopcm_base - ctx_rsvd; + guc_wopcm_size &= GUC_WOPCM_SIZE_MASK; + + DRM_DEBUG_DRIVER("Calculated GuC WOPCM Region: [%uKiB, %uKiB)\n", + guc_wopcm_base / 1024, guc_wopcm_size / 1024); + + guc_wopcm_rsvd = GUC_WOPCM_RESERVED + GUC_WOPCM_STACK_RESERVED; + if ((guc_fw_size + guc_wopcm_rsvd) > guc_wopcm_size) { + DRM_ERROR("Need %uKiB WOPCM for GuC, %uKiB available.\n", + (guc_fw_size + guc_wopcm_rsvd) / 1024, + guc_wopcm_size / 1024); + return -E2BIG; + } + + err = check_hw_restriction(i915, guc_wopcm_base, guc_wopcm_size); + if (err) + return err; + + wopcm->guc.base = guc_wopcm_base; + wopcm->guc.size = guc_wopcm_size; + + return 0; +} diff --git a/drivers/gpu/drm/i915/intel_wopcm.h b/drivers/gpu/drm/i915/intel_wopcm.h new file mode 100644 index 000000000000..93c402ca7489 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_wopcm.h @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright © 2017-2018 Intel Corporation + */ + +#ifndef _INTEL_WOPCM_H_ +#define _INTEL_WOPCM_H_ + +#include + +/** + * struct intel_wopcm - Overall WOPCM info and WOPCM regions. + * @size: Size of overall WOPCM. + * @guc: GuC WOPCM Region info. + * @guc.base: GuC WOPCM base which is offset from WOPCM base. + * @guc.size: Size of the GuC WOPCM region. + */ +struct intel_wopcm { + u32 size; + struct { + u32 base; + u32 size; + } guc; +}; + +void intel_wopcm_init_early(struct intel_wopcm *wopcm); +int intel_wopcm_init(struct intel_wopcm *wopcm); + +#endif -- cgit v1.2.3 From 5cbc1e2f48086ea08a37b3b75aa481ae9842af39 Mon Sep 17 00:00:00 2001 From: Jackie Li Date: Tue, 13 Mar 2018 17:32:51 -0700 Subject: drm/i915: Add support to return CNL specific reserved WOPCM size CNL has its specific reserved GuC WOPCM size for RC6 and other hardware contexts. This patch updates the code to return CNL specific reserved GuC WOPCM size for RC6 and other hardware contexts so that the GuC WOPCM size can be calculated correctly for CNL. v9: - Created a new patch for these changes originally made in v8 4/6 patch of this series (Sagar/Michal) v10: - Used if-else ladder to the returning of context sizes (Joonas) v11: - Removed GUC_ prefix from context size macro (Michal) v13: - Updated the ordering of s-o-b/cc/r-b tags (Sagar) Bspec: 12690 Signed-off-by: Jackie Li Cc: Sagar Arun Kamble Cc: Michal Wajdeczko Cc: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen (v9) Reviewed-by: Michal Wajdeczko (v11) Reviewed-by: Joonas Lahtinen (v12) Reviewed-by: Joonas Lahtinen Signed-off-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/1520987574-19351-3-git-send-email-yaodong.li@intel.com --- drivers/gpu/drm/i915/intel_wopcm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_wopcm.c b/drivers/gpu/drm/i915/intel_wopcm.c index 7b150d580d4a..a29e0c9e60a7 100644 --- a/drivers/gpu/drm/i915/intel_wopcm.c +++ b/drivers/gpu/drm/i915/intel_wopcm.c @@ -54,6 +54,8 @@ /* 24KB at the end of WOPCM is reserved for RC6 CTX on BXT. */ #define BXT_WOPCM_RC6_CTX_RESERVED (24 * 1024) +/* 36KB WOPCM reserved at the end of WOPCM on CNL. */ +#define CNL_WOPCM_HW_CTX_RESERVED (36 * 1024) /* 128KB from GUC_WOPCM_RESERVED is reserved for FW on Gen9. */ #define GEN9_GUC_FW_RESERVED (128 * 1024) @@ -76,6 +78,8 @@ static inline u32 context_reserved_size(struct drm_i915_private *i915) { if (IS_GEN9_LP(i915)) return BXT_WOPCM_RC6_CTX_RESERVED; + else if (INTEL_GEN(i915) >= 10) + return CNL_WOPCM_HW_CTX_RESERVED; else return 0; } -- cgit v1.2.3 From 96c83d35a26f7ba06a1623adaf872b56d54fe093 Mon Sep 17 00:00:00 2001 From: Jackie Li Date: Tue, 13 Mar 2018 17:32:52 -0700 Subject: drm/i915: Add HuC firmware size related restriction for Gen9 and CNL A0 On CNL A0 and Gen9, there's a hardware restriction that requires the available GuC WOPCM size to be larger than or equal to HuC firmware size. This patch adds new verification code to ensure the available GuC WOPCM size to be larger than or equal to HuC firmware size on both Gen9 and CNL A0. v6: - Extended HuC FW size check against GuC WOPCM size to all Gen9 and CNL A0 platforms v7: - Fixed patch format issues v8: - Renamed variables and functions to avoid ambiguity (Joonas) - Updated commit message and comments to be more comprehensive (Sagar) v9: - Moved code that is not related to restriction check into a separate patch and updated the commit message accordingly (Sagar/Michal) - Avoided to call uc_get_fw_size for better layer isolation (Michal) v10: - Shorten function names and reorganized size_check code to have clear isolation (Joonas) - Removed unnecessary comments (Joonas) v11: - Fixed logic error in size check (Michal) v12: - Add space between "HuC FW" and "(%uKiB)" in error message (Michal) v13: - Updated the ordering of s-o-b/cc/r-b tags (Sagar) BSpec: 10875 Signed-off-by: Jackie Li Cc: Michal Wajdeczko Cc: Sagar Arun Kamble Cc: John Spotswood Cc: Jeff McGee Cc: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Sagar Arun Kamble (v8) Reviewed-by: Michal Wajdeczko (v11) Reviewed-by: Joonas Lahtinen (v12) Reviewed-by: Joonas Lahtinen Signed-off-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/1520987574-19351-4-git-send-email-yaodong.li@intel.com --- drivers/gpu/drm/i915/intel_wopcm.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_wopcm.c b/drivers/gpu/drm/i915/intel_wopcm.c index a29e0c9e60a7..1fd1125f464b 100644 --- a/drivers/gpu/drm/i915/intel_wopcm.c +++ b/drivers/gpu/drm/i915/intel_wopcm.c @@ -105,14 +105,36 @@ static inline int gen9_check_dword_gap(u32 guc_wopcm_base, u32 guc_wopcm_size) return 0; } +static inline int gen9_check_huc_fw_fits(u32 guc_wopcm_size, u32 huc_fw_size) +{ + /* + * On Gen9 & CNL A0, hardware requires the total available GuC WOPCM + * size to be larger than or equal to HuC firmware size. Otherwise, + * firmware uploading would fail. + */ + if (huc_fw_size > guc_wopcm_size - GUC_WOPCM_RESERVED) { + DRM_ERROR("HuC FW (%uKiB) won't fit in GuC WOPCM (%uKiB).\n", + huc_fw_size / 1024, + (guc_wopcm_size - GUC_WOPCM_RESERVED) / 1024); + return -E2BIG; + } + + return 0; +} + static inline int check_hw_restriction(struct drm_i915_private *i915, - u32 guc_wopcm_base, u32 guc_wopcm_size) + u32 guc_wopcm_base, u32 guc_wopcm_size, + u32 huc_fw_size) { int err = 0; if (IS_GEN9(i915)) err = gen9_check_dword_gap(guc_wopcm_base, guc_wopcm_size); + if (!err && + (IS_GEN9(i915) || IS_CNL_REVID(i915, CNL_REVID_A0, CNL_REVID_A0))) + err = gen9_check_huc_fw_fits(guc_wopcm_size, huc_fw_size); + return err; } @@ -175,7 +197,8 @@ int intel_wopcm_init(struct intel_wopcm *wopcm) return -E2BIG; } - err = check_hw_restriction(i915, guc_wopcm_base, guc_wopcm_size); + err = check_hw_restriction(i915, guc_wopcm_base, guc_wopcm_size, + huc_fw_size); if (err) return err; -- cgit v1.2.3 From f08e2035cc089caf52ce57e855d96ba6ba90c71a Mon Sep 17 00:00:00 2001 From: Jackie Li Date: Tue, 13 Mar 2018 17:32:53 -0700 Subject: drm/i915/guc: Check the locking status of GuC WOPCM registers GuC WOPCM registers are write-once registers. Current driver code accesses these registers without checking the accessibility to these registers which will lead to unpredictable driver behaviors if these registers were touch by other components (such as faulty BIOS code). This patch moves the GuC WOPCM registers updating code into intel_wopcm.c and adds check before and after the update to GuC WOPCM registers so that we can make sure the driver is in a known state after writing to these write-once registers. v6: - Made sure module reloading won't bug the kernel while doing locking status checking v7: - Fixed patch format issues v8: - Fixed coding style issue on register lock bit macro definition (Sagar) v9: - Avoided to use redundant !! to cast uint to bool (Chris) - Return error code instead of GEM_BUG_ON for locked with invalid register values case (Sagar) - Updated guc_wopcm_hw_init to use guc_wopcm as first parameter (Michal) - Added code to set and validate the HuC_LOADING_AGENT_GUC bit in GuC WOPCM offset register based on the presence of HuC firmware (Michal) - Use bit fields instead of macros for GuC WOPCM flags (Michal) v10: - Refined variable names, removed redundant comments (Joonas) - Introduced lockable_reg to handle the write once register write and propagate the write error to caller (Joonas) - Used lockable_reg abstraction to avoid locking bit check on generic i915_reg_t (Michal) - Added log message for error paths (Michal) - Removed hw_updated flag and only relies on real hardware status v11: - Replaced lockable_reg with simplified function (Michal) - Used new macros for locking bits of WOPCM size/offset registers instead of using BIT(0) directly (Michal) - use intel_wopcm_init_hw() called from intel_gem_init_hw() to do GuC WOPCM register setup instead of calling from intel_uc_init_hw() (Michal) v12: - Updated function kernel-doc to align with code changes (Michal) - Updated code to use wopcm pointer directly (Michal) v13: - Updated the ordering of s-o-b/cc/r-b tags (Sagar) BSpec: 10875, 10833 Signed-off-by: Jackie Li Cc: Michal Wajdeczko Cc: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Michal Wajdeczko (v11) Reviewed-by: Joonas Lahtinen (v12) Reviewed-by: Joonas Lahtinen Signed-off-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/1520987574-19351-5-git-send-email-yaodong.li@intel.com --- drivers/gpu/drm/i915/i915_gem.c | 6 ++++ drivers/gpu/drm/i915/intel_guc_reg.h | 3 ++ drivers/gpu/drm/i915/intel_uc.c | 5 --- drivers/gpu/drm/i915/intel_wopcm.c | 64 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_wopcm.h | 1 + 5 files changed, 74 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 51faa6506739..13d4b0e74641 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5137,6 +5137,12 @@ int i915_gem_init_hw(struct drm_i915_private *dev_priv) goto out; } + ret = intel_wopcm_init_hw(&dev_priv->wopcm); + if (ret) { + DRM_ERROR("Enabling WOPCM failed (%d)\n", ret); + goto out; + } + /* We can't enable contexts until all firmware is loaded */ ret = intel_uc_init_hw(dev_priv); if (ret) { diff --git a/drivers/gpu/drm/i915/intel_guc_reg.h b/drivers/gpu/drm/i915/intel_guc_reg.h index 01963d085ed6..d86084742a4a 100644 --- a/drivers/gpu/drm/i915/intel_guc_reg.h +++ b/drivers/gpu/drm/i915/intel_guc_reg.h @@ -66,15 +66,18 @@ #define UOS_MOVE (1<<4) #define START_DMA (1<<0) #define DMA_GUC_WOPCM_OFFSET _MMIO(0xc340) +#define GUC_WOPCM_OFFSET_VALID (1<<0) #define HUC_LOADING_AGENT_VCR (0<<1) #define HUC_LOADING_AGENT_GUC (1<<1) #define GUC_WOPCM_OFFSET_SHIFT 14 +#define GUC_WOPCM_OFFSET_MASK (0x3ffff << GUC_WOPCM_OFFSET_SHIFT) #define GUC_MAX_IDLE_COUNT _MMIO(0xC3E4) #define HUC_STATUS2 _MMIO(0xD3B0) #define HUC_FW_VERIFIED (1<<7) #define GUC_WOPCM_SIZE _MMIO(0xc050) +#define GUC_WOPCM_SIZE_LOCKED (1<<0) #define GUC_WOPCM_SIZE_SHIFT 12 #define GUC_WOPCM_SIZE_MASK (0xfffff << GUC_WOPCM_SIZE_SHIFT) diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index ed5a6fcc8557..6316548a1c78 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -367,11 +367,6 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) gen9_reset_guc_interrupts(dev_priv); - /* init WOPCM */ - I915_WRITE(GUC_WOPCM_SIZE, dev_priv->wopcm.guc.size); - I915_WRITE(DMA_GUC_WOPCM_OFFSET, - dev_priv->wopcm.guc.base | HUC_LOADING_AGENT_GUC); - /* WaEnableuKernelHeaderValidFix:skl */ /* WaEnableGuCBootHashCheckNotSet:skl,bxt,kbl */ if (IS_GEN9(dev_priv)) diff --git a/drivers/gpu/drm/i915/intel_wopcm.c b/drivers/gpu/drm/i915/intel_wopcm.c index 1fd1125f464b..4117886bfb05 100644 --- a/drivers/gpu/drm/i915/intel_wopcm.c +++ b/drivers/gpu/drm/i915/intel_wopcm.c @@ -207,3 +207,67 @@ int intel_wopcm_init(struct intel_wopcm *wopcm) return 0; } + +static inline int write_and_verify(struct drm_i915_private *dev_priv, + i915_reg_t reg, u32 val, u32 mask, + u32 locked_bit) +{ + u32 reg_val; + + GEM_BUG_ON(val & ~mask); + + I915_WRITE(reg, val); + + reg_val = I915_READ(reg); + + return (reg_val & mask) != (val | locked_bit) ? -EIO : 0; +} + +/** + * intel_wopcm_init_hw() - Setup GuC WOPCM registers. + * @wopcm: pointer to intel_wopcm. + * + * Setup the GuC WOPCM size and offset registers with the calculated values. It + * will verify the register values to make sure the registers are locked with + * correct values. + * + * Return: 0 on success. -EIO if registers were locked with incorrect values. + */ +int intel_wopcm_init_hw(struct intel_wopcm *wopcm) +{ + struct drm_i915_private *dev_priv = wopcm_to_i915(wopcm); + u32 huc_agent; + u32 mask; + int err; + + if (!USES_GUC(dev_priv)) + return 0; + + GEM_BUG_ON(!HAS_GUC(dev_priv)); + GEM_BUG_ON(!wopcm->guc.size); + GEM_BUG_ON(!wopcm->guc.base); + + err = write_and_verify(dev_priv, GUC_WOPCM_SIZE, wopcm->guc.size, + GUC_WOPCM_SIZE_MASK | GUC_WOPCM_SIZE_LOCKED, + GUC_WOPCM_SIZE_LOCKED); + if (err) + goto err_out; + + huc_agent = USES_HUC(dev_priv) ? HUC_LOADING_AGENT_GUC : 0; + mask = GUC_WOPCM_OFFSET_MASK | GUC_WOPCM_OFFSET_VALID | huc_agent; + err = write_and_verify(dev_priv, DMA_GUC_WOPCM_OFFSET, + wopcm->guc.base | huc_agent, mask, + GUC_WOPCM_OFFSET_VALID); + if (err) + goto err_out; + + return 0; + +err_out: + DRM_ERROR("Failed to init WOPCM registers:\n"); + DRM_ERROR("DMA_GUC_WOPCM_OFFSET=%#x\n", + I915_READ(DMA_GUC_WOPCM_OFFSET)); + DRM_ERROR("GUC_WOPCM_SIZE=%#x\n", I915_READ(GUC_WOPCM_SIZE)); + + return err; +} diff --git a/drivers/gpu/drm/i915/intel_wopcm.h b/drivers/gpu/drm/i915/intel_wopcm.h index 93c402ca7489..6298910a384c 100644 --- a/drivers/gpu/drm/i915/intel_wopcm.h +++ b/drivers/gpu/drm/i915/intel_wopcm.h @@ -26,5 +26,6 @@ struct intel_wopcm { void intel_wopcm_init_early(struct intel_wopcm *wopcm); int intel_wopcm_init(struct intel_wopcm *wopcm); +int intel_wopcm_init_hw(struct intel_wopcm *wopcm); #endif -- cgit v1.2.3 From ab2681512b4c10d65a0fc412de0ce09bc4166edd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 14 Mar 2018 10:16:30 +0000 Subject: drm/i915: Check rq->timeline before deference Not only is the context suspect to disappearing, but so is it's timeline. Under a lockless inspection of the requests for debugging from intel_engine_dump(), the context may already have been freed and we have to check before chasing the dangling pointer. [28033.681755] Modules linked in: vgem snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic x86_pkg_temp_thermal intel_powerclamp coretemp snd_hda_intel crct10dif_pclmul crc32_pclmul snd_hda_codec snd_hwdep snd_hda_core ghash_clmulni_intel snd_pcm mei_me mei i915 r8169 mii prime_numbers i2c_hid [28033.681796] CPU: 3 PID: 3058 Comm: gem_exec_schedu Tainted: G U 4.16.0-rc5+ #9 [28033.681804] Hardware name: Acer Aspire E5-575G/Ironman_SK , BIOS V1.12 08/02/2016 [28033.681834] RIP: 0010:print_request+0x2b/0xb0 [i915] [28033.681840] RSP: 0018:ffffc90004afbc18 EFLAGS: 00010202 [28033.681847] RAX: 6b6b6b6b6b6b6b6b RBX: ffff8801921b5a40 RCX: 0000000000000006 [28033.681854] RDX: ffffc90004afbc60 RSI: ffff8801921b5a40 RDI: 0000000000000004 [28033.681861] RBP: ffffc90004afbd80 R08: 0000000000000000 R09: 0000000000000001 [28033.681868] R10: ffffc90004afbbd0 R11: ffffc90004afbc73 R12: ffffc90004afbc60 [28033.681875] R13: ffffc90004afbd80 R14: ffff8801d40ec670 R15: ffff8801921b5a40 [28033.681883] FS: 00007fbba5f6c8c0(0000) GS:ffff8801e8400000(0000) knlGS:0000000000000000 [28033.681891] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [28033.681897] CR2: 00007fbba5f8f000 CR3: 00000001b2efa002 CR4: 00000000003606e0 [28033.681904] Call Trace: [28033.681932] intel_engine_print_registers+0x6a7/0x930 [i915] [28033.681962] intel_engine_dump+0x30d/0x740 [i915] [28033.681971] ? seq_printf+0x3a/0x50 [28033.681995] i915_engine_info+0xb8/0xe0 [i915] [28033.682003] ? drm_get_color_range_name+0x20/0x20 [28033.682010] seq_read+0xe1/0x440 [28033.682018] full_proxy_read+0x51/0x80 [28033.682025] __vfs_read+0x21/0x130 [28033.682031] ? do_sys_open+0x134/0x220 [28033.682037] ? kmem_cache_free+0x177/0x2b0 [28033.682043] vfs_read+0xa1/0x150 [28033.682049] SyS_read+0x40/0xa0 [28033.682055] do_syscall_64+0x6b/0x1b0 [28033.682063] entry_SYSCALL_64_after_hwframe+0x42/0xb7 [28033.682069] RIP: 0033:0x7fbba4655d11 [28033.682074] RSP: 002b:00007ffd8c49da58 EFLAGS: 00000246 ORIG_RAX: 0000000000000000 [28033.682082] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fbba4655d11 [28033.682089] RDX: 000000000000003f RSI: 00005647bfbfc260 RDI: 0000000000000006 [28033.682096] RBP: 000000000000003f R08: 00000000ffffffff R09: 0000000000000000 [28033.682104] R10: 0000000000000000 R11: 0000000000000246 R12: 00005647bfbfc260 [28033.682111] R13: 0000000000000006 R14: 0000000000000000 R15: 00005647bfbfc260 [28033.682119] Code: 41 55 41 54 49 89 d4 55 53 48 89 fd 48 8b 86 c8 00 00 00 48 8b 3d d6 1e 14 e2 48 89 f3 48 2b be a8 02 00 00 48 8b 80 b0 00 00 00 <4c> 8b 68 18 e8 bc 80 02 e1 8b 8b 70 02 00 00 8b b3 28 02 00 00 [28033.682206] RIP: print_request+0x2b/0xb0 [i915] RSP: ffffc90004afbc18 Reported-by: Mika Kuoppala Signed-off-by: Chris Wilson Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180314101630.8933-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index a2b1e9e2c008..f22c5f72df8d 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1716,13 +1716,15 @@ static void print_request(struct drm_printer *m, struct i915_request *rq, const char *prefix) { + const char *name = rq->fence.ops->get_timeline_name(&rq->fence); + drm_printf(m, "%s%x%s [%llx:%x] prio=%d @ %dms: %s\n", prefix, rq->global_seqno, i915_request_completed(rq) ? "!" : "", rq->fence.context, rq->fence.seqno, rq->priotree.priority, jiffies_to_msecs(jiffies - rq->emitted_jiffies), - rq->timeline->common->name); + name); } static void hexdump(struct drm_printer *m, const void *buf, size_t len) -- cgit v1.2.3 From ad055fb8e010e4ff37f66aeed1d380329bddce67 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 14 Mar 2018 08:05:35 +0000 Subject: drm/i915/pmu: Work around compiler warnings on some kernel configs Arnd Bergman reports: """ The conditional spinlock confuses gcc into thinking the 'flags' value might contain uninitialized data: drivers/gpu/drm/i915/i915_pmu.c: In function '__i915_pmu_event_read': arch/x86/include/asm/paravirt_types.h:573:3: error: 'flags' may be used uninitialized in this function [-Werror=maybe-uninitialized] The code is correct, but it's easy to see how the compiler gets confused here. This avoids the problem by pulling the lock outside of the function into its only caller. """ On deeper look it seems this is caused by paravirt spinlocks implementation when CONFIG_PARAVIRT_DEBUG is set, which by being complicated, manages to convince gcc locked parameter can be changed externally (impossible). Work around it by removing the conditional locking parameters altogether. (It was never the most elegant code anyway.) Slight penalty we now pay is an additional irqsave spin lock/unlock cycle on the event enable path. But since enable is not a fast path, that is preferrable to the alternative solution which was doing MMIO under irqsave spinlock. Signed-off-by: Tvrtko Ursulin Reported-by: Arnd Bergmann Fixes: 1fe699e30113 ("drm/i915/pmu: Fix sleep under atomic in RC6 readout") Cc: Tvrtko Ursulin Cc: Chris Wilson Cc: Imre Deak Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: David Airlie Cc: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180314080535.17490-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 4bc7aefa9541..11fb76bd3860 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -412,7 +412,7 @@ static u64 __get_rc6(struct drm_i915_private *i915) return val; } -static u64 get_rc6(struct drm_i915_private *i915, bool locked) +static u64 get_rc6(struct drm_i915_private *i915) { #if IS_ENABLED(CONFIG_PM) unsigned long flags; @@ -428,8 +428,7 @@ static u64 get_rc6(struct drm_i915_private *i915, bool locked) * previously. */ - if (!locked) - spin_lock_irqsave(&i915->pmu.lock, flags); + spin_lock_irqsave(&i915->pmu.lock, flags); if (val >= i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur) { i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur = 0; @@ -438,12 +437,10 @@ static u64 get_rc6(struct drm_i915_private *i915, bool locked) val = i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur; } - if (!locked) - spin_unlock_irqrestore(&i915->pmu.lock, flags); + spin_unlock_irqrestore(&i915->pmu.lock, flags); } else { struct pci_dev *pdev = i915->drm.pdev; struct device *kdev = &pdev->dev; - unsigned long flags2; /* * We are runtime suspended. @@ -452,10 +449,8 @@ static u64 get_rc6(struct drm_i915_private *i915, bool locked) * on top of the last known real value, as the approximated RC6 * counter value. */ - if (!locked) - spin_lock_irqsave(&i915->pmu.lock, flags); - - spin_lock_irqsave(&kdev->power.lock, flags2); + spin_lock_irqsave(&i915->pmu.lock, flags); + spin_lock(&kdev->power.lock); if (!i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur) i915->pmu.suspended_jiffies_last = @@ -465,14 +460,13 @@ static u64 get_rc6(struct drm_i915_private *i915, bool locked) i915->pmu.suspended_jiffies_last; val += jiffies - kdev->power.accounting_timestamp; - spin_unlock_irqrestore(&kdev->power.lock, flags2); + spin_unlock(&kdev->power.lock); val = jiffies_to_nsecs(val); val += i915->pmu.sample[__I915_SAMPLE_RC6].cur; i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur = val; - if (!locked) - spin_unlock_irqrestore(&i915->pmu.lock, flags); + spin_unlock_irqrestore(&i915->pmu.lock, flags); } return val; @@ -481,7 +475,7 @@ static u64 get_rc6(struct drm_i915_private *i915, bool locked) #endif } -static u64 __i915_pmu_event_read(struct perf_event *event, bool locked) +static u64 __i915_pmu_event_read(struct perf_event *event) { struct drm_i915_private *i915 = container_of(event->pmu, typeof(*i915), pmu.base); @@ -519,7 +513,7 @@ static u64 __i915_pmu_event_read(struct perf_event *event, bool locked) val = count_interrupts(i915); break; case I915_PMU_RC6_RESIDENCY: - val = get_rc6(i915, locked); + val = get_rc6(i915); break; } } @@ -534,7 +528,7 @@ static void i915_pmu_event_read(struct perf_event *event) again: prev = local64_read(&hwc->prev_count); - new = __i915_pmu_event_read(event, false); + new = __i915_pmu_event_read(event); if (local64_cmpxchg(&hwc->prev_count, prev, new) != prev) goto again; @@ -584,14 +578,14 @@ static void i915_pmu_enable(struct perf_event *event) engine->pmu.enable_count[sample]++; } + spin_unlock_irqrestore(&i915->pmu.lock, flags); + /* * Store the current counter value so we can report the correct delta * for all listeners. Even when the event was already enabled and has * an existing non-zero value. */ - local64_set(&event->hw.prev_count, __i915_pmu_event_read(event, true)); - - spin_unlock_irqrestore(&i915->pmu.lock, flags); + local64_set(&event->hw.prev_count, __i915_pmu_event_read(event)); } static void i915_pmu_disable(struct perf_event *event) -- cgit v1.2.3 From 4635b573634c7028043244dbc1141ef57341deb2 Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Wed, 14 Mar 2018 13:36:52 +0530 Subject: drm/i915/cnl; Add macro to get PORT_TX register This patch creates a new macro to get PORT_TX register for any given DW. This removes the need of defining register address for each port & DW. Changes since V1: - Use underscope prefix, as macro isn't returning an mmio reg(Lucas) - Merge patch 1 & 2 of the series Changes since V2: - remove _MMIO_PORT6_LN macro (Rodrigo) Signed-off-by: Mahesh Kumar Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180314080653.9444-2-mahesh1.kumar@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 137 ++++++++++++---------------------------- 1 file changed, 39 insertions(+), 98 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 761bd3a4c5c1..5a2a3d6d8c97 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -154,8 +154,6 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define _PLL(pll, a, b) ((a) + (pll)*((b)-(a))) #define _MMIO_PLL(pll, a, b) _MMIO(_PLL(pll, a, b)) #define _MMIO_PORT6(port, a, b, c, d, e, f) _MMIO(_PICK(port, a, b, c, d, e, f)) -#define _MMIO_PORT6_LN(port, ln, a0, a1, b, c, d, e, f) \ - _MMIO(_PICK(port, a0, b, c, d, e, f) + (ln * (a1 - a0))) #define _PHY3(phy, ...) _PICK(phy, __VA_ARGS__) #define _MMIO_PHY3(phy, a, b, c) _MMIO(_PHY3(phy, a, b, c)) @@ -1964,30 +1962,36 @@ enum i915_power_well_id { _CNL_PORT_PCS_DW1_LN0_F) #define COMMON_KEEPER_EN (1 << 26) -#define _CNL_PORT_TX_DW2_GRP_AE 0x162348 -#define _CNL_PORT_TX_DW2_GRP_B 0x1623C8 -#define _CNL_PORT_TX_DW2_GRP_C 0x162B48 -#define _CNL_PORT_TX_DW2_GRP_D 0x162BC8 -#define _CNL_PORT_TX_DW2_GRP_F 0x162A48 -#define _CNL_PORT_TX_DW2_LN0_AE 0x162448 -#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 0x162848 -#define CNL_PORT_TX_DW2_GRP(port) _MMIO_PORT6(port, \ - _CNL_PORT_TX_DW2_GRP_AE, \ - _CNL_PORT_TX_DW2_GRP_B, \ - _CNL_PORT_TX_DW2_GRP_C, \ - _CNL_PORT_TX_DW2_GRP_D, \ - _CNL_PORT_TX_DW2_GRP_AE, \ - _CNL_PORT_TX_DW2_GRP_F) -#define CNL_PORT_TX_DW2_LN0(port) _MMIO_PORT6(port, \ - _CNL_PORT_TX_DW2_LN0_AE, \ - _CNL_PORT_TX_DW2_LN0_B, \ - _CNL_PORT_TX_DW2_LN0_C, \ - _CNL_PORT_TX_DW2_LN0_D, \ - _CNL_PORT_TX_DW2_LN0_AE, \ - _CNL_PORT_TX_DW2_LN0_F) +/* CNL Port TX registers */ +#define _CNL_PORT_TX_AE_GRP_OFFSET 0x162340 +#define _CNL_PORT_TX_B_GRP_OFFSET 0x1623C0 +#define _CNL_PORT_TX_C_GRP_OFFSET 0x162B40 +#define _CNL_PORT_TX_D_GRP_OFFSET 0x162BC0 +#define _CNL_PORT_TX_F_GRP_OFFSET 0x162A40 +#define _CNL_PORT_TX_AE_LN0_OFFSET 0x162440 +#define _CNL_PORT_TX_B_LN0_OFFSET 0x162640 +#define _CNL_PORT_TX_C_LN0_OFFSET 0x162C40 +#define _CNL_PORT_TX_D_LN0_OFFSET 0x162E40 +#define _CNL_PORT_TX_F_LN0_OFFSET 0x162840 +#define _CNL_PORT_TX_DW_GRP(port, dw) (_PICK((port), \ + _CNL_PORT_TX_AE_GRP_OFFSET, \ + _CNL_PORT_TX_B_GRP_OFFSET, \ + _CNL_PORT_TX_B_GRP_OFFSET, \ + _CNL_PORT_TX_D_GRP_OFFSET, \ + _CNL_PORT_TX_AE_GRP_OFFSET, \ + _CNL_PORT_TX_F_GRP_OFFSET) + \ + 4*(dw)) +#define _CNL_PORT_TX_DW_LN0(port, dw) (_PICK((port), \ + _CNL_PORT_TX_AE_LN0_OFFSET, \ + _CNL_PORT_TX_B_LN0_OFFSET, \ + _CNL_PORT_TX_B_LN0_OFFSET, \ + _CNL_PORT_TX_D_LN0_OFFSET, \ + _CNL_PORT_TX_AE_LN0_OFFSET, \ + _CNL_PORT_TX_F_LN0_OFFSET) + \ + 4*(dw)) + +#define CNL_PORT_TX_DW2_GRP(port) _MMIO(_CNL_PORT_TX_DW_GRP((port), 2)) +#define CNL_PORT_TX_DW2_LN0(port) _MMIO(_CNL_PORT_TX_DW_LN0((port), 2)) #define SWING_SEL_UPPER(x) ((x >> 3) << 15) #define SWING_SEL_UPPER_MASK (1 << 15) #define SWING_SEL_LOWER(x) ((x & 0x7) << 11) @@ -1995,32 +1999,13 @@ enum i915_power_well_id { #define RCOMP_SCALAR(x) ((x) << 0) #define RCOMP_SCALAR_MASK (0xFF << 0) -#define _CNL_PORT_TX_DW4_GRP_AE 0x162350 -#define _CNL_PORT_TX_DW4_GRP_B 0x1623D0 -#define _CNL_PORT_TX_DW4_GRP_C 0x162B50 -#define _CNL_PORT_TX_DW4_GRP_D 0x162BD0 -#define _CNL_PORT_TX_DW4_GRP_F 0x162A50 #define _CNL_PORT_TX_DW4_LN0_AE 0x162450 #define _CNL_PORT_TX_DW4_LN1_AE 0x1624D0 -#define _CNL_PORT_TX_DW4_LN0_B 0x162650 -#define _CNL_PORT_TX_DW4_LN0_C 0x162C50 -#define _CNL_PORT_TX_DW4_LN0_D 0x162E50 -#define _CNL_PORT_TX_DW4_LN0_F 0x162850 -#define CNL_PORT_TX_DW4_GRP(port) _MMIO_PORT6(port, \ - _CNL_PORT_TX_DW4_GRP_AE, \ - _CNL_PORT_TX_DW4_GRP_B, \ - _CNL_PORT_TX_DW4_GRP_C, \ - _CNL_PORT_TX_DW4_GRP_D, \ - _CNL_PORT_TX_DW4_GRP_AE, \ - _CNL_PORT_TX_DW4_GRP_F) -#define CNL_PORT_TX_DW4_LN(port, ln) _MMIO_PORT6_LN(port, ln, \ - _CNL_PORT_TX_DW4_LN0_AE, \ - _CNL_PORT_TX_DW4_LN1_AE, \ - _CNL_PORT_TX_DW4_LN0_B, \ - _CNL_PORT_TX_DW4_LN0_C, \ - _CNL_PORT_TX_DW4_LN0_D, \ - _CNL_PORT_TX_DW4_LN0_AE, \ - _CNL_PORT_TX_DW4_LN0_F) +#define CNL_PORT_TX_DW4_GRP(port) _MMIO(_CNL_PORT_TX_DW_GRP((port), 4)) +#define CNL_PORT_TX_DW4_LN0(port) _MMIO(_CNL_PORT_TX_DW_LN0((port), 4)) +#define CNL_PORT_TX_DW4_LN(port, ln) _MMIO(_CNL_PORT_TX_DW_LN0((port), 4) + \ + (ln * (_CNL_PORT_TX_DW4_LN1_AE - \ + _CNL_PORT_TX_DW4_LN0_AE))) #define LOADGEN_SELECT (1 << 31) #define POST_CURSOR_1(x) ((x) << 12) #define POST_CURSOR_1_MASK (0x3F << 12) @@ -2029,30 +2014,8 @@ enum i915_power_well_id { #define CURSOR_COEFF(x) ((x) << 0) #define CURSOR_COEFF_MASK (0x3F << 0) -#define _CNL_PORT_TX_DW5_GRP_AE 0x162354 -#define _CNL_PORT_TX_DW5_GRP_B 0x1623D4 -#define _CNL_PORT_TX_DW5_GRP_C 0x162B54 -#define _CNL_PORT_TX_DW5_GRP_D 0x162BD4 -#define _CNL_PORT_TX_DW5_GRP_F 0x162A54 -#define _CNL_PORT_TX_DW5_LN0_AE 0x162454 -#define _CNL_PORT_TX_DW5_LN0_B 0x162654 -#define _CNL_PORT_TX_DW5_LN0_C 0x162C54 -#define _CNL_PORT_TX_DW5_LN0_D 0x162E54 -#define _CNL_PORT_TX_DW5_LN0_F 0x162854 -#define CNL_PORT_TX_DW5_GRP(port) _MMIO_PORT6(port, \ - _CNL_PORT_TX_DW5_GRP_AE, \ - _CNL_PORT_TX_DW5_GRP_B, \ - _CNL_PORT_TX_DW5_GRP_C, \ - _CNL_PORT_TX_DW5_GRP_D, \ - _CNL_PORT_TX_DW5_GRP_AE, \ - _CNL_PORT_TX_DW5_GRP_F) -#define CNL_PORT_TX_DW5_LN0(port) _MMIO_PORT6(port, \ - _CNL_PORT_TX_DW5_LN0_AE, \ - _CNL_PORT_TX_DW5_LN0_B, \ - _CNL_PORT_TX_DW5_LN0_C, \ - _CNL_PORT_TX_DW5_LN0_D, \ - _CNL_PORT_TX_DW5_LN0_AE, \ - _CNL_PORT_TX_DW5_LN0_F) +#define CNL_PORT_TX_DW5_GRP(port) _MMIO(_CNL_PORT_TX_DW_GRP((port), 5)) +#define CNL_PORT_TX_DW5_LN0(port) _MMIO(_CNL_PORT_TX_DW_LN0((port), 5)) #define TX_TRAINING_EN (1 << 31) #define TAP3_DISABLE (1 << 29) #define SCALING_MODE_SEL(x) ((x) << 18) @@ -2060,30 +2023,8 @@ enum i915_power_well_id { #define RTERM_SELECT(x) ((x) << 3) #define RTERM_SELECT_MASK (0x7 << 3) -#define _CNL_PORT_TX_DW7_GRP_AE 0x16235C -#define _CNL_PORT_TX_DW7_GRP_B 0x1623DC -#define _CNL_PORT_TX_DW7_GRP_C 0x162B5C -#define _CNL_PORT_TX_DW7_GRP_D 0x162BDC -#define _CNL_PORT_TX_DW7_GRP_F 0x162A5C -#define _CNL_PORT_TX_DW7_LN0_AE 0x16245C -#define _CNL_PORT_TX_DW7_LN0_B 0x16265C -#define _CNL_PORT_TX_DW7_LN0_C 0x162C5C -#define _CNL_PORT_TX_DW7_LN0_D 0x162E5C -#define _CNL_PORT_TX_DW7_LN0_F 0x16285C -#define CNL_PORT_TX_DW7_GRP(port) _MMIO_PORT6(port, \ - _CNL_PORT_TX_DW7_GRP_AE, \ - _CNL_PORT_TX_DW7_GRP_B, \ - _CNL_PORT_TX_DW7_GRP_C, \ - _CNL_PORT_TX_DW7_GRP_D, \ - _CNL_PORT_TX_DW7_GRP_AE, \ - _CNL_PORT_TX_DW7_GRP_F) -#define CNL_PORT_TX_DW7_LN0(port) _MMIO_PORT6(port, \ - _CNL_PORT_TX_DW7_LN0_AE, \ - _CNL_PORT_TX_DW7_LN0_B, \ - _CNL_PORT_TX_DW7_LN0_C, \ - _CNL_PORT_TX_DW7_LN0_D, \ - _CNL_PORT_TX_DW7_LN0_AE, \ - _CNL_PORT_TX_DW7_LN0_F) +#define CNL_PORT_TX_DW7_GRP(port) _MMIO(_CNL_PORT_TX_DW_GRP((port), 7)) +#define CNL_PORT_TX_DW7_LN0(port) _MMIO(_CNL_PORT_TX_DW_LN0((port), 7)) #define N_SCALAR(x) ((x) << 24) #define N_SCALAR_MASK (0x7F << 24) -- cgit v1.2.3 From da9cb11f76623b99f2d5e6aa68f43d6ef714a7de Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Wed, 14 Mar 2018 13:36:53 +0530 Subject: drm/i915/cnl: Kill _MMIO_PORT6 macro This patch replaces use of remaining _MMIO_PORT6 macro and removes the macro. Changes Since V1: - Rebase Signed-off-by: Mahesh Kumar Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180314080653.9444-3-mahesh1.kumar@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5a2a3d6d8c97..d965b4ab6120 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -153,7 +153,6 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define _MMIO_PORT3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c)) #define _PLL(pll, a, b) ((a) + (pll)*((b)-(a))) #define _MMIO_PLL(pll, a, b) _MMIO(_PLL(pll, a, b)) -#define _MMIO_PORT6(port, a, b, c, d, e, f) _MMIO(_PICK(port, a, b, c, d, e, f)) #define _PHY3(phy, ...) _PICK(phy, __VA_ARGS__) #define _MMIO_PHY3(phy, a, b, c) _MMIO(_PHY3(phy, a, b, c)) @@ -1946,20 +1945,21 @@ enum i915_power_well_id { #define _CNL_PORT_PCS_DW1_LN0_C 0x162C04 #define _CNL_PORT_PCS_DW1_LN0_D 0x162E04 #define _CNL_PORT_PCS_DW1_LN0_F 0x162804 -#define CNL_PORT_PCS_DW1_GRP(port) _MMIO_PORT6(port, \ +#define CNL_PORT_PCS_DW1_GRP(port) _MMIO(_PICK(port, \ _CNL_PORT_PCS_DW1_GRP_AE, \ _CNL_PORT_PCS_DW1_GRP_B, \ _CNL_PORT_PCS_DW1_GRP_C, \ _CNL_PORT_PCS_DW1_GRP_D, \ _CNL_PORT_PCS_DW1_GRP_AE, \ - _CNL_PORT_PCS_DW1_GRP_F) -#define CNL_PORT_PCS_DW1_LN0(port) _MMIO_PORT6(port, \ + _CNL_PORT_PCS_DW1_GRP_F)) + +#define CNL_PORT_PCS_DW1_LN0(port) _MMIO(_PICK(port, \ _CNL_PORT_PCS_DW1_LN0_AE, \ _CNL_PORT_PCS_DW1_LN0_B, \ _CNL_PORT_PCS_DW1_LN0_C, \ _CNL_PORT_PCS_DW1_LN0_D, \ _CNL_PORT_PCS_DW1_LN0_AE, \ - _CNL_PORT_PCS_DW1_LN0_F) + _CNL_PORT_PCS_DW1_LN0_F)) #define COMMON_KEEPER_EN (1 << 26) /* CNL Port TX registers */ -- cgit v1.2.3 From 80b216b98b0cd4f10303863c062b7ab7d117ada7 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 14 Mar 2018 11:26:50 -0700 Subject: drm/i915: store all mmio bases in intel_engines The mmio bases we're currently storing in the intel_engines array are only valid for a subset of gens, so we need to ignore them and use different values in some cases. Instead of doing that, we can have a table of [starting gen, mmio base] pairs for each engine in intel_engines and select the correct one based on the gen we're running on in a consistent way. v2: document that the list goes in reverse order, update starting gen for render (Chris) v3: starting gen for render back to 1 to make our life easier with selftests (Chris) Cc: Chris Wilson Cc: Mika Kuoppala Cc: Tvrtko Ursulin Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Chris Wilson #v2 Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180314182653.26981-1-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/intel_engine_cs.c | 78 +++++++++++++++++++++------------ drivers/gpu/drm/i915/intel_ringbuffer.c | 1 - 2 files changed, 50 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index f22c5f72df8d..71eac571e141 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -81,12 +81,17 @@ static const struct engine_class_info intel_engine_classes[] = { }, }; +#define MAX_MMIO_BASES 3 struct engine_info { unsigned int hw_id; unsigned int uabi_id; u8 class; u8 instance; - u32 mmio_base; + /* mmio bases table *must* be sorted in reverse gen order */ + struct engine_mmio_base { + u32 gen : 8; + u32 base : 24; + } mmio_bases[MAX_MMIO_BASES]; unsigned irq_shift; }; @@ -96,7 +101,9 @@ static const struct engine_info intel_engines[] = { .uabi_id = I915_EXEC_RENDER, .class = RENDER_CLASS, .instance = 0, - .mmio_base = RENDER_RING_BASE, + .mmio_bases = { + { .gen = 1, .base = RENDER_RING_BASE } + }, .irq_shift = GEN8_RCS_IRQ_SHIFT, }, [BCS] = { @@ -104,7 +111,9 @@ static const struct engine_info intel_engines[] = { .uabi_id = I915_EXEC_BLT, .class = COPY_ENGINE_CLASS, .instance = 0, - .mmio_base = BLT_RING_BASE, + .mmio_bases = { + { .gen = 6, .base = BLT_RING_BASE } + }, .irq_shift = GEN8_BCS_IRQ_SHIFT, }, [VCS] = { @@ -112,7 +121,11 @@ static const struct engine_info intel_engines[] = { .uabi_id = I915_EXEC_BSD, .class = VIDEO_DECODE_CLASS, .instance = 0, - .mmio_base = GEN6_BSD_RING_BASE, + .mmio_bases = { + { .gen = 11, .base = GEN11_BSD_RING_BASE }, + { .gen = 6, .base = GEN6_BSD_RING_BASE }, + { .gen = 4, .base = BSD_RING_BASE } + }, .irq_shift = GEN8_VCS1_IRQ_SHIFT, }, [VCS2] = { @@ -120,7 +133,10 @@ static const struct engine_info intel_engines[] = { .uabi_id = I915_EXEC_BSD, .class = VIDEO_DECODE_CLASS, .instance = 1, - .mmio_base = GEN8_BSD2_RING_BASE, + .mmio_bases = { + { .gen = 11, .base = GEN11_BSD2_RING_BASE }, + { .gen = 8, .base = GEN8_BSD2_RING_BASE } + }, .irq_shift = GEN8_VCS2_IRQ_SHIFT, }, [VCS3] = { @@ -128,7 +144,9 @@ static const struct engine_info intel_engines[] = { .uabi_id = I915_EXEC_BSD, .class = VIDEO_DECODE_CLASS, .instance = 2, - .mmio_base = GEN11_BSD3_RING_BASE, + .mmio_bases = { + { .gen = 11, .base = GEN11_BSD3_RING_BASE } + }, .irq_shift = 0, /* not used */ }, [VCS4] = { @@ -136,7 +154,9 @@ static const struct engine_info intel_engines[] = { .uabi_id = I915_EXEC_BSD, .class = VIDEO_DECODE_CLASS, .instance = 3, - .mmio_base = GEN11_BSD4_RING_BASE, + .mmio_bases = { + { .gen = 11, .base = GEN11_BSD4_RING_BASE } + }, .irq_shift = 0, /* not used */ }, [VECS] = { @@ -144,7 +164,10 @@ static const struct engine_info intel_engines[] = { .uabi_id = I915_EXEC_VEBOX, .class = VIDEO_ENHANCEMENT_CLASS, .instance = 0, - .mmio_base = VEBOX_RING_BASE, + .mmio_bases = { + { .gen = 11, .base = GEN11_VEBOX_RING_BASE }, + { .gen = 7, .base = VEBOX_RING_BASE } + }, .irq_shift = GEN8_VECS_IRQ_SHIFT, }, [VECS2] = { @@ -152,7 +175,9 @@ static const struct engine_info intel_engines[] = { .uabi_id = I915_EXEC_VEBOX, .class = VIDEO_ENHANCEMENT_CLASS, .instance = 1, - .mmio_base = GEN11_VEBOX2_RING_BASE, + .mmio_bases = { + { .gen = 11, .base = GEN11_VEBOX2_RING_BASE } + }, .irq_shift = 0, /* not used */ }, }; @@ -223,6 +248,21 @@ __intel_engine_context_size(struct drm_i915_private *dev_priv, u8 class) } } +static u32 __engine_mmio_base(struct drm_i915_private *i915, + const struct engine_mmio_base *bases) +{ + int i; + + for (i = 0; i < MAX_MMIO_BASES; i++) + if (INTEL_GEN(i915) >= bases[i].gen) + break; + + GEM_BUG_ON(i == MAX_MMIO_BASES); + GEM_BUG_ON(!bases[i].base); + + return bases[i].base; +} + static int intel_engine_setup(struct drm_i915_private *dev_priv, enum intel_engine_id id) @@ -257,25 +297,7 @@ intel_engine_setup(struct drm_i915_private *dev_priv, class_info->name, info->instance) >= sizeof(engine->name)); engine->hw_id = engine->guc_id = info->hw_id; - if (INTEL_GEN(dev_priv) >= 11) { - switch (engine->id) { - case VCS: - engine->mmio_base = GEN11_BSD_RING_BASE; - break; - case VCS2: - engine->mmio_base = GEN11_BSD2_RING_BASE; - break; - case VECS: - engine->mmio_base = GEN11_VEBOX_RING_BASE; - break; - default: - /* take the original value for all other engines */ - engine->mmio_base = info->mmio_base; - break; - } - } else { - engine->mmio_base = info->mmio_base; - } + engine->mmio_base = __engine_mmio_base(dev_priv, info->mmio_bases); engine->irq_shift = info->irq_shift; engine->class = info->class; engine->instance = info->instance; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 88eeb64041ae..3b478769a8c1 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2080,7 +2080,6 @@ int intel_init_bsd_ring_buffer(struct intel_engine_cs *engine) engine->emit_flush = gen6_bsd_ring_flush; engine->irq_enable_mask = GT_BSD_USER_INTERRUPT; } else { - engine->mmio_base = BSD_RING_BASE; engine->emit_flush = bsd_ring_flush; if (IS_GEN5(dev_priv)) engine->irq_enable_mask = ILK_BSD_USER_INTERRUPT; -- cgit v1.2.3 From 74419daaae6c1dafe9cc5d4d0c92c17982f4eebd Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 14 Mar 2018 11:26:51 -0700 Subject: drm/i915: add a selftest for the mmio_bases table Check that the entries are in reverse gen order and that all entries with gen > 0 have an mmio base set. v2: loop forward, simplify logic, use i915_subtests (Chris) Suggested-by: Chris Wilson Cc: Chris Wilson Signed-off-by: Daniele Ceraolo Spurio Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180314182653.26981-2-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/intel_engine_cs.c | 16 +++--- .../gpu/drm/i915/selftests/i915_mock_selftests.h | 1 + drivers/gpu/drm/i915/selftests/intel_engine_cs.c | 58 ++++++++++++++++++++++ 3 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 drivers/gpu/drm/i915/selftests/intel_engine_cs.c (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 71eac571e141..8fda81126fbc 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -263,16 +263,21 @@ static u32 __engine_mmio_base(struct drm_i915_private *i915, return bases[i].base; } +static void __sprint_engine_name(char *name, const struct engine_info *info) +{ + WARN_ON(snprintf(name, INTEL_ENGINE_CS_MAX_NAME, "%s%u", + intel_engine_classes[info->class].name, + info->instance) >= INTEL_ENGINE_CS_MAX_NAME); +} + static int intel_engine_setup(struct drm_i915_private *dev_priv, enum intel_engine_id id) { const struct engine_info *info = &intel_engines[id]; - const struct engine_class_info *class_info; struct intel_engine_cs *engine; GEM_BUG_ON(info->class >= ARRAY_SIZE(intel_engine_classes)); - class_info = &intel_engine_classes[info->class]; BUILD_BUG_ON(MAX_ENGINE_CLASS >= BIT(GEN11_ENGINE_CLASS_WIDTH)); BUILD_BUG_ON(MAX_ENGINE_INSTANCE >= BIT(GEN11_ENGINE_INSTANCE_WIDTH)); @@ -293,9 +298,7 @@ intel_engine_setup(struct drm_i915_private *dev_priv, engine->id = id; engine->i915 = dev_priv; - WARN_ON(snprintf(engine->name, sizeof(engine->name), "%s%u", - class_info->name, info->instance) >= - sizeof(engine->name)); + __sprint_engine_name(engine->name, info); engine->hw_id = engine->guc_id = info->hw_id; engine->mmio_base = __engine_mmio_base(dev_priv, info->mmio_bases); engine->irq_shift = info->irq_shift; @@ -303,7 +306,7 @@ intel_engine_setup(struct drm_i915_private *dev_priv, engine->instance = info->instance; engine->uabi_id = info->uabi_id; - engine->uabi_class = class_info->uabi_class; + engine->uabi_class = intel_engine_classes[info->class].uabi_class; engine->context_size = __intel_engine_context_size(dev_priv, engine->class); @@ -2140,4 +2143,5 @@ void intel_disable_engine_stats(struct intel_engine_cs *engine) #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #include "selftests/mock_engine.c" +#include "selftests/intel_engine_cs.c" #endif diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h index 9a48aa441743..d16d74178e9d 100644 --- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h +++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h @@ -14,6 +14,7 @@ selftest(fence, i915_sw_fence_mock_selftests) selftest(scatterlist, scatterlist_mock_selftests) selftest(syncmap, i915_syncmap_mock_selftests) selftest(uncore, intel_uncore_mock_selftests) +selftest(engine, intel_engine_cs_mock_selftests) selftest(breadcrumbs, intel_breadcrumbs_mock_selftests) selftest(timelines, i915_gem_timeline_mock_selftests) selftest(requests, i915_request_mock_selftests) diff --git a/drivers/gpu/drm/i915/selftests/intel_engine_cs.c b/drivers/gpu/drm/i915/selftests/intel_engine_cs.c new file mode 100644 index 000000000000..cfaa6b296835 --- /dev/null +++ b/drivers/gpu/drm/i915/selftests/intel_engine_cs.c @@ -0,0 +1,58 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * + * Copyright © 2018 Intel Corporation + */ + +#include "../i915_selftest.h" + +static int intel_mmio_bases_check(void *arg) +{ + int i, j; + + for (i = 0; i < ARRAY_SIZE(intel_engines); i++) { + const struct engine_info *info = &intel_engines[i]; + char name[INTEL_ENGINE_CS_MAX_NAME]; + u8 prev = U8_MAX; + + __sprint_engine_name(name, info); + + for (j = 0; j < MAX_MMIO_BASES; j++) { + u8 gen = info->mmio_bases[j].gen; + u32 base = info->mmio_bases[j].base; + + if (gen >= prev) { + pr_err("%s: %s: mmio base for gen %x " + "is before the one for gen %x\n", + __func__, name, prev, gen); + return -EINVAL; + } + + if (gen == 0) + break; + + if (!base) { + pr_err("%s: %s: invalid mmio base (%x) " + "for gen %x at entry %u\n", + __func__, name, base, gen, j); + return -EINVAL; + } + + prev = gen; + } + + pr_info("%s: min gen supported for %s = %d\n", + __func__, name, prev); + } + + return 0; +} + +int intel_engine_cs_mock_selftests(void) +{ + static const struct i915_subtest tests[] = { + SUBTEST(intel_mmio_bases_check), + }; + + return i915_subtests(tests, NULL); +} -- cgit v1.2.3 From 210060edc216ebd6330ee4fded5a01547d938642 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 14 Mar 2018 11:26:52 -0700 Subject: drm/i915: use engine->irq_keep_mask when resetting irqs The "reset" value and the "keep" value are the same. While we are here, add a TODO for gen11 interrupt reset Suggested-by: Chris Wilson Cc: Chris Wilson Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180314182653.26981-3-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/intel_lrc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 3a69b367e565..5e8f6896d059 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1666,6 +1666,10 @@ static void reset_irq(struct intel_engine_cs *engine) struct drm_i915_private *dev_priv = engine->i915; int i; + /* TODO: correctly reset irqs for gen11 */ + if (WARN_ON_ONCE(INTEL_GEN(engine->i915) >= 11)) + return; + GEM_BUG_ON(engine->id >= ARRAY_SIZE(gtiir)); /* @@ -1677,11 +1681,11 @@ static void reset_irq(struct intel_engine_cs *engine) */ for (i = 0; i < 2; i++) { I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]), - GT_CONTEXT_SWITCH_INTERRUPT << engine->irq_shift); + engine->irq_keep_mask); 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)); + engine->irq_keep_mask); clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); } -- cgit v1.2.3 From fa6f071d54fb3658c7012634b8e4035c8d3a25bc Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 14 Mar 2018 11:26:53 -0700 Subject: drm/i915: move gen8 irq shifts to intel_lrc.c The only usage outside the intel_lrc.c file is in the ringbuffer init, but the irq mask calculated there is then overwritten for all engines that have a non-zero shift, so we can drop it. This change is not aimed at code saving but at removing from intel_engines information that does not apply to all gens that have the engine. When checking without the temporary WARN_ON, code size is basically unchanged. v2: make the irq_shifts array static const v3: rebase, move irq_shifts array to logical_ring_default_irqs v4: move array inside the if and use u8 for it (Chris) Suggested-by: Michel Thierry Signed-off-by: Daniele Ceraolo Spurio Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180314182653.26981-4-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/intel_engine_cs.c | 10 ---------- drivers/gpu/drm/i915/intel_lrc.c | 15 ++++++++++++++- drivers/gpu/drm/i915/intel_ringbuffer.c | 4 ++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 - 4 files changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 8fda81126fbc..337dfa56a738 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -92,7 +92,6 @@ struct engine_info { u32 gen : 8; u32 base : 24; } mmio_bases[MAX_MMIO_BASES]; - unsigned irq_shift; }; static const struct engine_info intel_engines[] = { @@ -104,7 +103,6 @@ static const struct engine_info intel_engines[] = { .mmio_bases = { { .gen = 1, .base = RENDER_RING_BASE } }, - .irq_shift = GEN8_RCS_IRQ_SHIFT, }, [BCS] = { .hw_id = BCS_HW, @@ -114,7 +112,6 @@ static const struct engine_info intel_engines[] = { .mmio_bases = { { .gen = 6, .base = BLT_RING_BASE } }, - .irq_shift = GEN8_BCS_IRQ_SHIFT, }, [VCS] = { .hw_id = VCS_HW, @@ -126,7 +123,6 @@ static const struct engine_info intel_engines[] = { { .gen = 6, .base = GEN6_BSD_RING_BASE }, { .gen = 4, .base = BSD_RING_BASE } }, - .irq_shift = GEN8_VCS1_IRQ_SHIFT, }, [VCS2] = { .hw_id = VCS2_HW, @@ -137,7 +133,6 @@ static const struct engine_info intel_engines[] = { { .gen = 11, .base = GEN11_BSD2_RING_BASE }, { .gen = 8, .base = GEN8_BSD2_RING_BASE } }, - .irq_shift = GEN8_VCS2_IRQ_SHIFT, }, [VCS3] = { .hw_id = VCS3_HW, @@ -147,7 +142,6 @@ static const struct engine_info intel_engines[] = { .mmio_bases = { { .gen = 11, .base = GEN11_BSD3_RING_BASE } }, - .irq_shift = 0, /* not used */ }, [VCS4] = { .hw_id = VCS4_HW, @@ -157,7 +151,6 @@ static const struct engine_info intel_engines[] = { .mmio_bases = { { .gen = 11, .base = GEN11_BSD4_RING_BASE } }, - .irq_shift = 0, /* not used */ }, [VECS] = { .hw_id = VECS_HW, @@ -168,7 +161,6 @@ static const struct engine_info intel_engines[] = { { .gen = 11, .base = GEN11_VEBOX_RING_BASE }, { .gen = 7, .base = VEBOX_RING_BASE } }, - .irq_shift = GEN8_VECS_IRQ_SHIFT, }, [VECS2] = { .hw_id = VECS2_HW, @@ -178,7 +170,6 @@ static const struct engine_info intel_engines[] = { .mmio_bases = { { .gen = 11, .base = GEN11_VEBOX2_RING_BASE } }, - .irq_shift = 0, /* not used */ }, }; @@ -301,7 +292,6 @@ intel_engine_setup(struct drm_i915_private *dev_priv, __sprint_engine_name(engine->name, info); engine->hw_id = engine->guc_id = info->hw_id; engine->mmio_base = __engine_mmio_base(dev_priv, info->mmio_bases); - engine->irq_shift = info->irq_shift; engine->class = info->class; engine->instance = info->instance; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 5e8f6896d059..53f1c009ed7b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -2118,7 +2118,20 @@ logical_ring_default_vfuncs(struct intel_engine_cs *engine) static inline void logical_ring_default_irqs(struct intel_engine_cs *engine) { - unsigned shift = engine->irq_shift; + unsigned int shift = 0; + + if (INTEL_GEN(engine->i915) < 11) { + const u8 irq_shifts[] = { + [RCS] = GEN8_RCS_IRQ_SHIFT, + [BCS] = GEN8_BCS_IRQ_SHIFT, + [VCS] = GEN8_VCS1_IRQ_SHIFT, + [VCS2] = GEN8_VCS2_IRQ_SHIFT, + [VECS] = GEN8_VECS_IRQ_SHIFT, + }; + + shift = irq_shifts[engine->id]; + } + engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT << shift; engine->irq_keep_mask = GT_CONTEXT_SWITCH_INTERRUPT << shift; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 3b478769a8c1..72d6167c519a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1944,8 +1944,6 @@ static void intel_ring_init_semaphores(struct drm_i915_private *dev_priv, static void intel_ring_init_irq(struct drm_i915_private *dev_priv, struct intel_engine_cs *engine) { - engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT << engine->irq_shift; - if (INTEL_GEN(dev_priv) >= 6) { engine->irq_enable = gen6_irq_enable; engine->irq_disable = gen6_irq_disable; @@ -2030,6 +2028,8 @@ int intel_init_render_ring_buffer(struct intel_engine_cs *engine) if (HAS_L3_DPF(dev_priv)) engine->irq_keep_mask = GT_RENDER_L3_PARITY_ERROR_INTERRUPT; + engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT; + if (INTEL_GEN(dev_priv) >= 6) { engine->init_context = intel_rcs_ctx_init; engine->emit_flush = gen7_render_ring_flush; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 81cdbbf257ec..80fae806aec9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -331,7 +331,6 @@ struct intel_engine_cs { u8 instance; u32 context_size; u32 mmio_base; - unsigned int irq_shift; struct intel_ring *buffer; struct intel_timeline *timeline; -- cgit v1.2.3 From c080363fcdc3015e4cb9b5582afe2cd3aa890630 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Tue, 13 Mar 2018 23:19:20 +0000 Subject: drm/i915: Split GPU commands definitions into separate header We should not mix MMIO with MI_INSTR definitions. v2: sanitize comment, change include order (Chris) Suggested-by: Chris Wilson Signed-off-by: Michal Wajdeczko Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180313124109.39216-1-michal.wajdeczko@intel.com Link: https://patchwork.freedesktop.org/patch/msgid/20180313231920.6932-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_reg.h | 263 ---------------------------- drivers/gpu/drm/i915/intel_gpu_commands.h | 274 ++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.h | 3 +- 3 files changed, 276 insertions(+), 264 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_gpu_commands.h (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d965b4ab6120..dbcb8829faba 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -427,145 +427,6 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define VGA_CR_INDEX_CGA 0x3d4 #define VGA_CR_DATA_CGA 0x3d5 -/* - * Instruction field definitions used by the command parser - */ -#define INSTR_CLIENT_SHIFT 29 -#define INSTR_MI_CLIENT 0x0 -#define INSTR_BC_CLIENT 0x2 -#define INSTR_RC_CLIENT 0x3 -#define INSTR_SUBCLIENT_SHIFT 27 -#define INSTR_SUBCLIENT_MASK 0x18000000 -#define INSTR_MEDIA_SUBCLIENT 0x2 -#define INSTR_26_TO_24_MASK 0x7000000 -#define INSTR_26_TO_24_SHIFT 24 - -/* - * Memory interface instructions used by the kernel - */ -#define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags)) -/* Many MI commands use bit 22 of the header dword for GGTT vs PPGTT */ -#define MI_GLOBAL_GTT (1<<22) - -#define MI_NOOP MI_INSTR(0, 0) -#define MI_USER_INTERRUPT MI_INSTR(0x02, 0) -#define MI_WAIT_FOR_EVENT MI_INSTR(0x03, 0) -#define MI_WAIT_FOR_OVERLAY_FLIP (1<<16) -#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6) -#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) -#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) -#define MI_FLUSH MI_INSTR(0x04, 0) -#define MI_READ_FLUSH (1 << 0) -#define MI_EXE_FLUSH (1 << 1) -#define MI_NO_WRITE_FLUSH (1 << 2) -#define MI_SCENE_COUNT (1 << 3) /* just increment scene count */ -#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ -#define MI_INVALIDATE_ISP (1 << 5) /* invalidate indirect state pointers */ -#define MI_REPORT_HEAD MI_INSTR(0x07, 0) -#define MI_ARB_ON_OFF MI_INSTR(0x08, 0) -#define MI_ARB_ENABLE (1<<0) -#define MI_ARB_DISABLE (0<<0) -#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) -#define MI_SUSPEND_FLUSH MI_INSTR(0x0b, 0) -#define MI_SUSPEND_FLUSH_EN (1<<0) -#define MI_SET_APPID MI_INSTR(0x0e, 0) -#define MI_OVERLAY_FLIP MI_INSTR(0x11, 0) -#define MI_OVERLAY_CONTINUE (0x0<<21) -#define MI_OVERLAY_ON (0x1<<21) -#define MI_OVERLAY_OFF (0x2<<21) -#define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0) -#define MI_DISPLAY_FLIP MI_INSTR(0x14, 2) -#define MI_DISPLAY_FLIP_I915 MI_INSTR(0x14, 1) -#define MI_DISPLAY_FLIP_PLANE(n) ((n) << 20) -/* IVB has funny definitions for which plane to flip. */ -#define MI_DISPLAY_FLIP_IVB_PLANE_A (0 << 19) -#define MI_DISPLAY_FLIP_IVB_PLANE_B (1 << 19) -#define MI_DISPLAY_FLIP_IVB_SPRITE_A (2 << 19) -#define MI_DISPLAY_FLIP_IVB_SPRITE_B (3 << 19) -#define MI_DISPLAY_FLIP_IVB_PLANE_C (4 << 19) -#define MI_DISPLAY_FLIP_IVB_SPRITE_C (5 << 19) -/* SKL ones */ -#define MI_DISPLAY_FLIP_SKL_PLANE_1_A (0 << 8) -#define MI_DISPLAY_FLIP_SKL_PLANE_1_B (1 << 8) -#define MI_DISPLAY_FLIP_SKL_PLANE_1_C (2 << 8) -#define MI_DISPLAY_FLIP_SKL_PLANE_2_A (4 << 8) -#define MI_DISPLAY_FLIP_SKL_PLANE_2_B (5 << 8) -#define MI_DISPLAY_FLIP_SKL_PLANE_2_C (6 << 8) -#define MI_DISPLAY_FLIP_SKL_PLANE_3_A (7 << 8) -#define MI_DISPLAY_FLIP_SKL_PLANE_3_B (8 << 8) -#define MI_DISPLAY_FLIP_SKL_PLANE_3_C (9 << 8) -#define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6, gen7 */ -#define MI_SEMAPHORE_GLOBAL_GTT (1<<22) -#define MI_SEMAPHORE_UPDATE (1<<21) -#define MI_SEMAPHORE_COMPARE (1<<20) -#define MI_SEMAPHORE_REGISTER (1<<18) -#define MI_SEMAPHORE_SYNC_VR (0<<16) /* RCS wait for VCS (RVSYNC) */ -#define MI_SEMAPHORE_SYNC_VER (1<<16) /* RCS wait for VECS (RVESYNC) */ -#define MI_SEMAPHORE_SYNC_BR (2<<16) /* RCS wait for BCS (RBSYNC) */ -#define MI_SEMAPHORE_SYNC_BV (0<<16) /* VCS wait for BCS (VBSYNC) */ -#define MI_SEMAPHORE_SYNC_VEV (1<<16) /* VCS wait for VECS (VVESYNC) */ -#define MI_SEMAPHORE_SYNC_RV (2<<16) /* VCS wait for RCS (VRSYNC) */ -#define MI_SEMAPHORE_SYNC_RB (0<<16) /* BCS wait for RCS (BRSYNC) */ -#define MI_SEMAPHORE_SYNC_VEB (1<<16) /* BCS wait for VECS (BVESYNC) */ -#define MI_SEMAPHORE_SYNC_VB (2<<16) /* BCS wait for VCS (BVSYNC) */ -#define MI_SEMAPHORE_SYNC_BVE (0<<16) /* VECS wait for BCS (VEBSYNC) */ -#define MI_SEMAPHORE_SYNC_VVE (1<<16) /* VECS wait for VCS (VEVSYNC) */ -#define MI_SEMAPHORE_SYNC_RVE (2<<16) /* VECS wait for RCS (VERSYNC) */ -#define MI_SEMAPHORE_SYNC_INVALID (3<<16) -#define MI_SEMAPHORE_SYNC_MASK (3<<16) -#define MI_SET_CONTEXT MI_INSTR(0x18, 0) -#define MI_MM_SPACE_GTT (1<<8) -#define MI_MM_SPACE_PHYSICAL (0<<8) -#define MI_SAVE_EXT_STATE_EN (1<<3) -#define MI_RESTORE_EXT_STATE_EN (1<<2) -#define MI_FORCE_RESTORE (1<<1) -#define MI_RESTORE_INHIBIT (1<<0) -#define HSW_MI_RS_SAVE_STATE_EN (1<<3) -#define HSW_MI_RS_RESTORE_STATE_EN (1<<2) -#define MI_SEMAPHORE_SIGNAL MI_INSTR(0x1b, 0) /* GEN8+ */ -#define MI_SEMAPHORE_TARGET(engine) ((engine)<<15) -#define MI_SEMAPHORE_WAIT MI_INSTR(0x1c, 2) /* GEN8+ */ -#define MI_SEMAPHORE_POLL (1<<15) -#define MI_SEMAPHORE_SAD_GTE_SDD (1<<12) -#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) -#define MI_STORE_DWORD_IMM_GEN4 MI_INSTR(0x20, 2) -#define MI_MEM_VIRTUAL (1 << 22) /* 945,g33,965 */ -#define MI_USE_GGTT (1 << 22) /* g4x+ */ -#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) -#define MI_STORE_DWORD_INDEX_SHIFT 2 -/* Official intel docs are somewhat sloppy concerning MI_LOAD_REGISTER_IMM: - * - Always issue a MI_NOOP _before_ the MI_LOAD_REGISTER_IMM - otherwise hw - * simply ignores the register load under certain conditions. - * - One can actually load arbitrary many arbitrary registers: Simply issue x - * address/value pairs. Don't overdue it, though, x <= 2^4 must hold! - */ -#define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*(x)-1) -#define MI_LRI_FORCE_POSTED (1<<12) -#define MI_STORE_REGISTER_MEM MI_INSTR(0x24, 1) -#define MI_STORE_REGISTER_MEM_GEN8 MI_INSTR(0x24, 2) -#define MI_SRM_LRM_GLOBAL_GTT (1<<22) -#define MI_FLUSH_DW MI_INSTR(0x26, 1) /* for GEN6 */ -#define MI_FLUSH_DW_STORE_INDEX (1<<21) -#define MI_INVALIDATE_TLB (1<<18) -#define MI_FLUSH_DW_OP_STOREDW (1<<14) -#define MI_FLUSH_DW_OP_MASK (3<<14) -#define MI_FLUSH_DW_NOTIFY (1<<8) -#define MI_INVALIDATE_BSD (1<<7) -#define MI_FLUSH_DW_USE_GTT (1<<2) -#define MI_FLUSH_DW_USE_PPGTT (0<<2) -#define MI_LOAD_REGISTER_MEM MI_INSTR(0x29, 1) -#define MI_LOAD_REGISTER_MEM_GEN8 MI_INSTR(0x29, 2) -#define MI_BATCH_BUFFER MI_INSTR(0x30, 1) -#define MI_BATCH_NON_SECURE (1) -/* for snb/ivb/vlv this also means "batch in ppgtt" when ppgtt is enabled. */ -#define MI_BATCH_NON_SECURE_I965 (1<<8) -#define MI_BATCH_PPGTT_HSW (1<<8) -#define MI_BATCH_NON_SECURE_HSW (1<<13) -#define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) -#define MI_BATCH_GTT (2<<6) /* aliased with (1<<7) on gen4 */ -#define MI_BATCH_BUFFER_START_GEN8 MI_INSTR(0x31, 1) -#define MI_BATCH_RESOURCE_STREAMER (1<<10) - #define MI_PREDICATE_SRC0 _MMIO(0x2400) #define MI_PREDICATE_SRC0_UDW _MMIO(0x2400 + 4) #define MI_PREDICATE_SRC1 _MMIO(0x2408) @@ -575,130 +436,6 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define LOWER_SLICE_ENABLED (1<<0) #define LOWER_SLICE_DISABLED (0<<0) -/* - * 3D instructions used by the kernel - */ -#define GFX_INSTR(opcode, flags) ((0x3 << 29) | ((opcode) << 24) | (flags)) - -#define GEN9_MEDIA_POOL_STATE ((0x3 << 29) | (0x2 << 27) | (0x5 << 16) | 4) -#define GEN9_MEDIA_POOL_ENABLE (1 << 31) -#define GFX_OP_RASTER_RULES ((0x3<<29)|(0x7<<24)) -#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) -#define SC_UPDATE_SCISSOR (0x1<<1) -#define SC_ENABLE_MASK (0x1<<0) -#define SC_ENABLE (0x1<<0) -#define GFX_OP_LOAD_INDIRECT ((0x3<<29)|(0x1d<<24)|(0x7<<16)) -#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) -#define SCI_YMIN_MASK (0xffff<<16) -#define SCI_XMIN_MASK (0xffff<<0) -#define SCI_YMAX_MASK (0xffff<<16) -#define SCI_XMAX_MASK (0xffff<<0) -#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19)) -#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1) -#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0) -#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) -#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4) -#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) -#define GFX_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) -#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) -#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) - -#define COLOR_BLT_CMD (2<<29 | 0x40<<22 | (5-2)) -#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|4) -#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) -#define XY_MONO_SRC_COPY_IMM_BLT ((2<<29)|(0x71<<22)|5) -#define BLT_WRITE_A (2<<20) -#define BLT_WRITE_RGB (1<<20) -#define BLT_WRITE_RGBA (BLT_WRITE_RGB | BLT_WRITE_A) -#define BLT_DEPTH_8 (0<<24) -#define BLT_DEPTH_16_565 (1<<24) -#define BLT_DEPTH_16_1555 (2<<24) -#define BLT_DEPTH_32 (3<<24) -#define BLT_ROP_SRC_COPY (0xcc<<16) -#define BLT_ROP_COLOR_COPY (0xf0<<16) -#define XY_SRC_COPY_BLT_SRC_TILED (1<<15) /* 965+ only */ -#define XY_SRC_COPY_BLT_DST_TILED (1<<11) /* 965+ only */ -#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2) -#define ASYNC_FLIP (1<<22) -#define DISPLAY_PLANE_A (0<<20) -#define DISPLAY_PLANE_B (1<<20) -#define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|((len)-2)) -#define PIPE_CONTROL_FLUSH_L3 (1<<27) -#define PIPE_CONTROL_GLOBAL_GTT_IVB (1<<24) /* gen7+ */ -#define PIPE_CONTROL_MMIO_WRITE (1<<23) -#define PIPE_CONTROL_STORE_DATA_INDEX (1<<21) -#define PIPE_CONTROL_CS_STALL (1<<20) -#define PIPE_CONTROL_TLB_INVALIDATE (1<<18) -#define PIPE_CONTROL_MEDIA_STATE_CLEAR (1<<16) -#define PIPE_CONTROL_QW_WRITE (1<<14) -#define PIPE_CONTROL_POST_SYNC_OP_MASK (3<<14) -#define PIPE_CONTROL_DEPTH_STALL (1<<13) -#define PIPE_CONTROL_WRITE_FLUSH (1<<12) -#define PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH (1<<12) /* gen6+ */ -#define PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE (1<<11) /* MBZ on Ironlake */ -#define PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE (1<<10) /* GM45+ only */ -#define PIPE_CONTROL_INDIRECT_STATE_DISABLE (1<<9) -#define PIPE_CONTROL_NOTIFY (1<<8) -#define PIPE_CONTROL_FLUSH_ENABLE (1<<7) /* gen7+ */ -#define PIPE_CONTROL_DC_FLUSH_ENABLE (1<<5) -#define PIPE_CONTROL_VF_CACHE_INVALIDATE (1<<4) -#define PIPE_CONTROL_CONST_CACHE_INVALIDATE (1<<3) -#define PIPE_CONTROL_STATE_CACHE_INVALIDATE (1<<2) -#define PIPE_CONTROL_STALL_AT_SCOREBOARD (1<<1) -#define PIPE_CONTROL_DEPTH_CACHE_FLUSH (1<<0) -#define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */ - -/* - * Commands used only by the command parser - */ -#define MI_SET_PREDICATE MI_INSTR(0x01, 0) -#define MI_ARB_CHECK MI_INSTR(0x05, 0) -#define MI_RS_CONTROL MI_INSTR(0x06, 0) -#define MI_URB_ATOMIC_ALLOC MI_INSTR(0x09, 0) -#define MI_PREDICATE MI_INSTR(0x0C, 0) -#define MI_RS_CONTEXT MI_INSTR(0x0F, 0) -#define MI_TOPOLOGY_FILTER MI_INSTR(0x0D, 0) -#define MI_LOAD_SCAN_LINES_EXCL MI_INSTR(0x13, 0) -#define MI_URB_CLEAR MI_INSTR(0x19, 0) -#define MI_UPDATE_GTT MI_INSTR(0x23, 0) -#define MI_CLFLUSH MI_INSTR(0x27, 0) -#define MI_REPORT_PERF_COUNT MI_INSTR(0x28, 0) -#define MI_REPORT_PERF_COUNT_GGTT (1<<0) -#define MI_LOAD_REGISTER_REG MI_INSTR(0x2A, 0) -#define MI_RS_STORE_DATA_IMM MI_INSTR(0x2B, 0) -#define MI_LOAD_URB_MEM MI_INSTR(0x2C, 0) -#define MI_STORE_URB_MEM MI_INSTR(0x2D, 0) -#define MI_CONDITIONAL_BATCH_BUFFER_END MI_INSTR(0x36, 0) - -#define PIPELINE_SELECT ((0x3<<29)|(0x1<<27)|(0x1<<24)|(0x4<<16)) -#define GFX_OP_3DSTATE_VF_STATISTICS ((0x3<<29)|(0x1<<27)|(0x0<<24)|(0xB<<16)) -#define MEDIA_VFE_STATE ((0x3<<29)|(0x2<<27)|(0x0<<24)|(0x0<<16)) -#define MEDIA_VFE_STATE_MMIO_ACCESS_MASK (0x18) -#define GPGPU_OBJECT ((0x3<<29)|(0x2<<27)|(0x1<<24)|(0x4<<16)) -#define GPGPU_WALKER ((0x3<<29)|(0x2<<27)|(0x1<<24)|(0x5<<16)) -#define GFX_OP_3DSTATE_DX9_CONSTANTF_VS \ - ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x39<<16)) -#define GFX_OP_3DSTATE_DX9_CONSTANTF_PS \ - ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x3A<<16)) -#define GFX_OP_3DSTATE_SO_DECL_LIST \ - ((0x3<<29)|(0x3<<27)|(0x1<<24)|(0x17<<16)) - -#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_VS \ - ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x43<<16)) -#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_GS \ - ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x44<<16)) -#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_HS \ - ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x45<<16)) -#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_DS \ - ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x46<<16)) -#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_PS \ - ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x47<<16)) - -#define MFX_WAIT ((0x3<<29)|(0x1<<27)|(0x0<<16)) - -#define COLOR_BLT ((0x2<<29)|(0x40<<22)) -#define SRC_COPY_BLT ((0x2<<29)|(0x43<<22)) - /* * Registers used only by the command parser */ diff --git a/drivers/gpu/drm/i915/intel_gpu_commands.h b/drivers/gpu/drm/i915/intel_gpu_commands.h new file mode 100644 index 000000000000..105e2a9e874a --- /dev/null +++ b/drivers/gpu/drm/i915/intel_gpu_commands.h @@ -0,0 +1,274 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright � 2003-2018 Intel Corporation + */ + +#ifndef _INTEL_GPU_COMMANDS_H_ +#define _INTEL_GPU_COMMANDS_H_ + +/* + * Instruction field definitions used by the command parser + */ +#define INSTR_CLIENT_SHIFT 29 +#define INSTR_MI_CLIENT 0x0 +#define INSTR_BC_CLIENT 0x2 +#define INSTR_RC_CLIENT 0x3 +#define INSTR_SUBCLIENT_SHIFT 27 +#define INSTR_SUBCLIENT_MASK 0x18000000 +#define INSTR_MEDIA_SUBCLIENT 0x2 +#define INSTR_26_TO_24_MASK 0x7000000 +#define INSTR_26_TO_24_SHIFT 24 + +/* + * Memory interface instructions used by the kernel + */ +#define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags)) +/* Many MI commands use bit 22 of the header dword for GGTT vs PPGTT */ +#define MI_GLOBAL_GTT (1<<22) + +#define MI_NOOP MI_INSTR(0, 0) +#define MI_USER_INTERRUPT MI_INSTR(0x02, 0) +#define MI_WAIT_FOR_EVENT MI_INSTR(0x03, 0) +#define MI_WAIT_FOR_OVERLAY_FLIP (1<<16) +#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6) +#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) +#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) +#define MI_FLUSH MI_INSTR(0x04, 0) +#define MI_READ_FLUSH (1 << 0) +#define MI_EXE_FLUSH (1 << 1) +#define MI_NO_WRITE_FLUSH (1 << 2) +#define MI_SCENE_COUNT (1 << 3) /* just increment scene count */ +#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ +#define MI_INVALIDATE_ISP (1 << 5) /* invalidate indirect state pointers */ +#define MI_REPORT_HEAD MI_INSTR(0x07, 0) +#define MI_ARB_ON_OFF MI_INSTR(0x08, 0) +#define MI_ARB_ENABLE (1<<0) +#define MI_ARB_DISABLE (0<<0) +#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) +#define MI_SUSPEND_FLUSH MI_INSTR(0x0b, 0) +#define MI_SUSPEND_FLUSH_EN (1<<0) +#define MI_SET_APPID MI_INSTR(0x0e, 0) +#define MI_OVERLAY_FLIP MI_INSTR(0x11, 0) +#define MI_OVERLAY_CONTINUE (0x0<<21) +#define MI_OVERLAY_ON (0x1<<21) +#define MI_OVERLAY_OFF (0x2<<21) +#define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0) +#define MI_DISPLAY_FLIP MI_INSTR(0x14, 2) +#define MI_DISPLAY_FLIP_I915 MI_INSTR(0x14, 1) +#define MI_DISPLAY_FLIP_PLANE(n) ((n) << 20) +/* IVB has funny definitions for which plane to flip. */ +#define MI_DISPLAY_FLIP_IVB_PLANE_A (0 << 19) +#define MI_DISPLAY_FLIP_IVB_PLANE_B (1 << 19) +#define MI_DISPLAY_FLIP_IVB_SPRITE_A (2 << 19) +#define MI_DISPLAY_FLIP_IVB_SPRITE_B (3 << 19) +#define MI_DISPLAY_FLIP_IVB_PLANE_C (4 << 19) +#define MI_DISPLAY_FLIP_IVB_SPRITE_C (5 << 19) +/* SKL ones */ +#define MI_DISPLAY_FLIP_SKL_PLANE_1_A (0 << 8) +#define MI_DISPLAY_FLIP_SKL_PLANE_1_B (1 << 8) +#define MI_DISPLAY_FLIP_SKL_PLANE_1_C (2 << 8) +#define MI_DISPLAY_FLIP_SKL_PLANE_2_A (4 << 8) +#define MI_DISPLAY_FLIP_SKL_PLANE_2_B (5 << 8) +#define MI_DISPLAY_FLIP_SKL_PLANE_2_C (6 << 8) +#define MI_DISPLAY_FLIP_SKL_PLANE_3_A (7 << 8) +#define MI_DISPLAY_FLIP_SKL_PLANE_3_B (8 << 8) +#define MI_DISPLAY_FLIP_SKL_PLANE_3_C (9 << 8) +#define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6, gen7 */ +#define MI_SEMAPHORE_GLOBAL_GTT (1<<22) +#define MI_SEMAPHORE_UPDATE (1<<21) +#define MI_SEMAPHORE_COMPARE (1<<20) +#define MI_SEMAPHORE_REGISTER (1<<18) +#define MI_SEMAPHORE_SYNC_VR (0<<16) /* RCS wait for VCS (RVSYNC) */ +#define MI_SEMAPHORE_SYNC_VER (1<<16) /* RCS wait for VECS (RVESYNC) */ +#define MI_SEMAPHORE_SYNC_BR (2<<16) /* RCS wait for BCS (RBSYNC) */ +#define MI_SEMAPHORE_SYNC_BV (0<<16) /* VCS wait for BCS (VBSYNC) */ +#define MI_SEMAPHORE_SYNC_VEV (1<<16) /* VCS wait for VECS (VVESYNC) */ +#define MI_SEMAPHORE_SYNC_RV (2<<16) /* VCS wait for RCS (VRSYNC) */ +#define MI_SEMAPHORE_SYNC_RB (0<<16) /* BCS wait for RCS (BRSYNC) */ +#define MI_SEMAPHORE_SYNC_VEB (1<<16) /* BCS wait for VECS (BVESYNC) */ +#define MI_SEMAPHORE_SYNC_VB (2<<16) /* BCS wait for VCS (BVSYNC) */ +#define MI_SEMAPHORE_SYNC_BVE (0<<16) /* VECS wait for BCS (VEBSYNC) */ +#define MI_SEMAPHORE_SYNC_VVE (1<<16) /* VECS wait for VCS (VEVSYNC) */ +#define MI_SEMAPHORE_SYNC_RVE (2<<16) /* VECS wait for RCS (VERSYNC) */ +#define MI_SEMAPHORE_SYNC_INVALID (3<<16) +#define MI_SEMAPHORE_SYNC_MASK (3<<16) +#define MI_SET_CONTEXT MI_INSTR(0x18, 0) +#define MI_MM_SPACE_GTT (1<<8) +#define MI_MM_SPACE_PHYSICAL (0<<8) +#define MI_SAVE_EXT_STATE_EN (1<<3) +#define MI_RESTORE_EXT_STATE_EN (1<<2) +#define MI_FORCE_RESTORE (1<<1) +#define MI_RESTORE_INHIBIT (1<<0) +#define HSW_MI_RS_SAVE_STATE_EN (1<<3) +#define HSW_MI_RS_RESTORE_STATE_EN (1<<2) +#define MI_SEMAPHORE_SIGNAL MI_INSTR(0x1b, 0) /* GEN8+ */ +#define MI_SEMAPHORE_TARGET(engine) ((engine)<<15) +#define MI_SEMAPHORE_WAIT MI_INSTR(0x1c, 2) /* GEN8+ */ +#define MI_SEMAPHORE_POLL (1<<15) +#define MI_SEMAPHORE_SAD_GTE_SDD (1<<12) +#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) +#define MI_STORE_DWORD_IMM_GEN4 MI_INSTR(0x20, 2) +#define MI_MEM_VIRTUAL (1 << 22) /* 945,g33,965 */ +#define MI_USE_GGTT (1 << 22) /* g4x+ */ +#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) +#define MI_STORE_DWORD_INDEX_SHIFT 2 +/* + * Official intel docs are somewhat sloppy concerning MI_LOAD_REGISTER_IMM: + * - Always issue a MI_NOOP _before_ the MI_LOAD_REGISTER_IMM - otherwise hw + * simply ignores the register load under certain conditions. + * - One can actually load arbitrary many arbitrary registers: Simply issue x + * address/value pairs. Don't overdue it, though, x <= 2^4 must hold! + */ +#define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*(x)-1) +#define MI_LRI_FORCE_POSTED (1<<12) +#define MI_STORE_REGISTER_MEM MI_INSTR(0x24, 1) +#define MI_STORE_REGISTER_MEM_GEN8 MI_INSTR(0x24, 2) +#define MI_SRM_LRM_GLOBAL_GTT (1<<22) +#define MI_FLUSH_DW MI_INSTR(0x26, 1) /* for GEN6 */ +#define MI_FLUSH_DW_STORE_INDEX (1<<21) +#define MI_INVALIDATE_TLB (1<<18) +#define MI_FLUSH_DW_OP_STOREDW (1<<14) +#define MI_FLUSH_DW_OP_MASK (3<<14) +#define MI_FLUSH_DW_NOTIFY (1<<8) +#define MI_INVALIDATE_BSD (1<<7) +#define MI_FLUSH_DW_USE_GTT (1<<2) +#define MI_FLUSH_DW_USE_PPGTT (0<<2) +#define MI_LOAD_REGISTER_MEM MI_INSTR(0x29, 1) +#define MI_LOAD_REGISTER_MEM_GEN8 MI_INSTR(0x29, 2) +#define MI_BATCH_BUFFER MI_INSTR(0x30, 1) +#define MI_BATCH_NON_SECURE (1) +/* for snb/ivb/vlv this also means "batch in ppgtt" when ppgtt is enabled. */ +#define MI_BATCH_NON_SECURE_I965 (1<<8) +#define MI_BATCH_PPGTT_HSW (1<<8) +#define MI_BATCH_NON_SECURE_HSW (1<<13) +#define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) +#define MI_BATCH_GTT (2<<6) /* aliased with (1<<7) on gen4 */ +#define MI_BATCH_BUFFER_START_GEN8 MI_INSTR(0x31, 1) +#define MI_BATCH_RESOURCE_STREAMER (1<<10) + +/* + * 3D instructions used by the kernel + */ +#define GFX_INSTR(opcode, flags) ((0x3 << 29) | ((opcode) << 24) | (flags)) + +#define GEN9_MEDIA_POOL_STATE ((0x3 << 29) | (0x2 << 27) | (0x5 << 16) | 4) +#define GEN9_MEDIA_POOL_ENABLE (1 << 31) +#define GFX_OP_RASTER_RULES ((0x3<<29)|(0x7<<24)) +#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define SC_UPDATE_SCISSOR (0x1<<1) +#define SC_ENABLE_MASK (0x1<<0) +#define SC_ENABLE (0x1<<0) +#define GFX_OP_LOAD_INDIRECT ((0x3<<29)|(0x1d<<24)|(0x7<<16)) +#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) +#define SCI_YMIN_MASK (0xffff<<16) +#define SCI_XMIN_MASK (0xffff<<0) +#define SCI_YMAX_MASK (0xffff<<16) +#define SCI_XMAX_MASK (0xffff<<0) +#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1) +#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0) +#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) +#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4) +#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) +#define GFX_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) +#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) +#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) + +#define COLOR_BLT_CMD (2<<29 | 0x40<<22 | (5-2)) +#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|4) +#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_MONO_SRC_COPY_IMM_BLT ((2<<29)|(0x71<<22)|5) +#define BLT_WRITE_A (2<<20) +#define BLT_WRITE_RGB (1<<20) +#define BLT_WRITE_RGBA (BLT_WRITE_RGB | BLT_WRITE_A) +#define BLT_DEPTH_8 (0<<24) +#define BLT_DEPTH_16_565 (1<<24) +#define BLT_DEPTH_16_1555 (2<<24) +#define BLT_DEPTH_32 (3<<24) +#define BLT_ROP_SRC_COPY (0xcc<<16) +#define BLT_ROP_COLOR_COPY (0xf0<<16) +#define XY_SRC_COPY_BLT_SRC_TILED (1<<15) /* 965+ only */ +#define XY_SRC_COPY_BLT_DST_TILED (1<<11) /* 965+ only */ +#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2) +#define ASYNC_FLIP (1<<22) +#define DISPLAY_PLANE_A (0<<20) +#define DISPLAY_PLANE_B (1<<20) +#define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|((len)-2)) +#define PIPE_CONTROL_FLUSH_L3 (1<<27) +#define PIPE_CONTROL_GLOBAL_GTT_IVB (1<<24) /* gen7+ */ +#define PIPE_CONTROL_MMIO_WRITE (1<<23) +#define PIPE_CONTROL_STORE_DATA_INDEX (1<<21) +#define PIPE_CONTROL_CS_STALL (1<<20) +#define PIPE_CONTROL_TLB_INVALIDATE (1<<18) +#define PIPE_CONTROL_MEDIA_STATE_CLEAR (1<<16) +#define PIPE_CONTROL_QW_WRITE (1<<14) +#define PIPE_CONTROL_POST_SYNC_OP_MASK (3<<14) +#define PIPE_CONTROL_DEPTH_STALL (1<<13) +#define PIPE_CONTROL_WRITE_FLUSH (1<<12) +#define PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH (1<<12) /* gen6+ */ +#define PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE (1<<11) /* MBZ on ILK */ +#define PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE (1<<10) /* GM45+ only */ +#define PIPE_CONTROL_INDIRECT_STATE_DISABLE (1<<9) +#define PIPE_CONTROL_NOTIFY (1<<8) +#define PIPE_CONTROL_FLUSH_ENABLE (1<<7) /* gen7+ */ +#define PIPE_CONTROL_DC_FLUSH_ENABLE (1<<5) +#define PIPE_CONTROL_VF_CACHE_INVALIDATE (1<<4) +#define PIPE_CONTROL_CONST_CACHE_INVALIDATE (1<<3) +#define PIPE_CONTROL_STATE_CACHE_INVALIDATE (1<<2) +#define PIPE_CONTROL_STALL_AT_SCOREBOARD (1<<1) +#define PIPE_CONTROL_DEPTH_CACHE_FLUSH (1<<0) +#define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */ + +/* + * Commands used only by the command parser + */ +#define MI_SET_PREDICATE MI_INSTR(0x01, 0) +#define MI_ARB_CHECK MI_INSTR(0x05, 0) +#define MI_RS_CONTROL MI_INSTR(0x06, 0) +#define MI_URB_ATOMIC_ALLOC MI_INSTR(0x09, 0) +#define MI_PREDICATE MI_INSTR(0x0C, 0) +#define MI_RS_CONTEXT MI_INSTR(0x0F, 0) +#define MI_TOPOLOGY_FILTER MI_INSTR(0x0D, 0) +#define MI_LOAD_SCAN_LINES_EXCL MI_INSTR(0x13, 0) +#define MI_URB_CLEAR MI_INSTR(0x19, 0) +#define MI_UPDATE_GTT MI_INSTR(0x23, 0) +#define MI_CLFLUSH MI_INSTR(0x27, 0) +#define MI_REPORT_PERF_COUNT MI_INSTR(0x28, 0) +#define MI_REPORT_PERF_COUNT_GGTT (1<<0) +#define MI_LOAD_REGISTER_REG MI_INSTR(0x2A, 0) +#define MI_RS_STORE_DATA_IMM MI_INSTR(0x2B, 0) +#define MI_LOAD_URB_MEM MI_INSTR(0x2C, 0) +#define MI_STORE_URB_MEM MI_INSTR(0x2D, 0) +#define MI_CONDITIONAL_BATCH_BUFFER_END MI_INSTR(0x36, 0) + +#define PIPELINE_SELECT ((0x3<<29)|(0x1<<27)|(0x1<<24)|(0x4<<16)) +#define GFX_OP_3DSTATE_VF_STATISTICS ((0x3<<29)|(0x1<<27)|(0x0<<24)|(0xB<<16)) +#define MEDIA_VFE_STATE ((0x3<<29)|(0x2<<27)|(0x0<<24)|(0x0<<16)) +#define MEDIA_VFE_STATE_MMIO_ACCESS_MASK (0x18) +#define GPGPU_OBJECT ((0x3<<29)|(0x2<<27)|(0x1<<24)|(0x4<<16)) +#define GPGPU_WALKER ((0x3<<29)|(0x2<<27)|(0x1<<24)|(0x5<<16)) +#define GFX_OP_3DSTATE_DX9_CONSTANTF_VS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x39<<16)) +#define GFX_OP_3DSTATE_DX9_CONSTANTF_PS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x3A<<16)) +#define GFX_OP_3DSTATE_SO_DECL_LIST \ + ((0x3<<29)|(0x3<<27)|(0x1<<24)|(0x17<<16)) + +#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_VS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x43<<16)) +#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_GS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x44<<16)) +#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_HS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x45<<16)) +#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_DS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x46<<16)) +#define GFX_OP_3DSTATE_BINDING_TABLE_EDIT_PS \ + ((0x3<<29)|(0x3<<27)|(0x0<<24)|(0x47<<16)) + +#define MFX_WAIT ((0x3<<29)|(0x1<<27)|(0x0<<16)) + +#define COLOR_BLT ((0x2<<29)|(0x40<<22)) +#define SRC_COPY_BLT ((0x2<<29)|(0x43<<22)) + +#endif /* _INTEL_GPU_COMMANDS_H_ */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 80fae806aec9..1f50727a5ddb 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -7,10 +7,11 @@ #include "i915_gem_batch_pool.h" #include "i915_gem_timeline.h" -#include "i915_reg.h" /* FIXME split out i915_gpu_commands.h */ +#include "i915_reg.h" #include "i915_pmu.h" #include "i915_request.h" #include "i915_selftest.h" +#include "intel_gpu_commands.h" struct drm_printer; -- cgit v1.2.3 From 56b9a8b083870162310fe37d4b1b5597eb983bae Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Wed, 14 Mar 2018 14:45:39 +0000 Subject: drm/i915/guc: Update syntax of GuC log functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We moved GuC log related data and code to separate files and definition but we didn't change functions syntax to follow object-verb pattern. Let's fix that before we continue with next round of code refactoring. v2: rebased Signed-off-by: Michal Wajdeczko Cc: Michal Winiarski Cc: Chris Wilson Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20180314144539.11152-1-michal.wajdeczko@intel.com [ickle: checkpatch booleans] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 4 +- drivers/gpu/drm/i915/intel_guc.c | 8 +- drivers/gpu/drm/i915/intel_guc_log.c | 203 +++++++++++++++++++---------------- drivers/gpu/drm/i915/intel_guc_log.h | 18 ++-- drivers/gpu/drm/i915/intel_uc.c | 4 +- 5 files changed, 126 insertions(+), 111 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 972014b2497d..298a3aa9513b 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2502,7 +2502,7 @@ static int i915_guc_log_control_get(void *data, u64 *val) if (!USES_GUC(dev_priv)) return -ENODEV; - *val = intel_guc_log_control_get(&dev_priv->guc); + *val = intel_guc_log_control_get(&dev_priv->guc.log); return 0; } @@ -2514,7 +2514,7 @@ static int i915_guc_log_control_set(void *data, u64 val) if (!USES_GUC(dev_priv)) return -ENODEV; - return intel_guc_log_control_set(&dev_priv->guc, val); + return intel_guc_log_control_set(&dev_priv->guc.log, val); } DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops, diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 3eb516e7c225..e70bf654d21e 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -64,7 +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); + intel_guc_log_init_early(&guc->log); mutex_init(&guc->send_mutex); guc->send = intel_guc_send_nop; @@ -169,7 +169,7 @@ int intel_guc_init(struct intel_guc *guc) return ret; GEM_BUG_ON(!guc->shared_data); - ret = intel_guc_log_create(guc); + ret = intel_guc_log_create(&guc->log); if (ret) goto err_shared; @@ -184,7 +184,7 @@ int intel_guc_init(struct intel_guc *guc) return 0; err_log: - intel_guc_log_destroy(guc); + intel_guc_log_destroy(&guc->log); err_shared: guc_shared_data_destroy(guc); return ret; @@ -196,7 +196,7 @@ void intel_guc_fini(struct intel_guc *guc) i915_ggtt_disable_guc(dev_priv); intel_guc_ads_destroy(guc); - intel_guc_log_destroy(guc); + intel_guc_log_destroy(&guc->log); guc_shared_data_destroy(guc); } diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index b9c7bd745565..bfb9a68fffef 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -22,13 +22,10 @@ * */ -#include -#include - #include "intel_guc_log.h" #include "i915_drv.h" -static void guc_log_capture_logs(struct intel_guc *guc); +static void guc_log_capture_logs(struct intel_guc_log *log); /** * DOC: GuC firmware log @@ -74,6 +71,11 @@ static int guc_log_control(struct intel_guc *guc, bool enable, u32 verbosity) return intel_guc_send(guc, action, ARRAY_SIZE(action)); } +static inline struct intel_guc *log_to_guc(struct intel_guc_log *log) +{ + return container_of(log, struct intel_guc, log); +} + /* * Sub buffer switch callback. Called whenever relay has to switch to a new * sub buffer, relay stays on the same sub buffer if 0 is returned. @@ -149,8 +151,9 @@ static struct rchan_callbacks relay_callbacks = { .remove_buf_file = remove_buf_file_callback, }; -static int guc_log_relay_file_create(struct intel_guc *guc) +static int guc_log_relay_file_create(struct intel_guc_log *log) { + struct intel_guc *guc = log_to_guc(log); struct drm_i915_private *dev_priv = guc_to_i915(guc); struct dentry *log_dir; int ret; @@ -158,7 +161,7 @@ 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); + mutex_lock(&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; @@ -181,7 +184,8 @@ static int guc_log_relay_file_create(struct intel_guc *guc) goto out_unlock; } - ret = relay_late_setup_files(guc->log.runtime.relay_chan, "guc_log", log_dir); + ret = relay_late_setup_files(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); goto out_unlock; @@ -190,18 +194,18 @@ static int guc_log_relay_file_create(struct intel_guc *guc) ret = 0; out_unlock: - mutex_unlock(&guc->log.runtime.relay_lock); + mutex_unlock(&log->runtime.relay_lock); return ret; } -static bool guc_log_has_relay(struct intel_guc *guc) +static bool guc_log_has_relay(struct intel_guc_log *log) { - lockdep_assert_held(&guc->log.runtime.relay_lock); + lockdep_assert_held(&log->runtime.relay_lock); - return guc->log.runtime.relay_chan != NULL; + return log->runtime.relay_chan; } -static void guc_move_to_next_buf(struct intel_guc *guc) +static void guc_move_to_next_buf(struct intel_guc_log *log) { /* * Make sure the updates made in the sub buffer are visible when @@ -209,19 +213,19 @@ static void guc_move_to_next_buf(struct intel_guc *guc) */ smp_wmb(); - if (!guc_log_has_relay(guc)) + if (!guc_log_has_relay(log)) 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); + relay_reserve(log->runtime.relay_chan, log->vma->obj->base.size); /* Switch to the next sub buffer */ - relay_flush(guc->log.runtime.relay_chan); + relay_flush(log->runtime.relay_chan); } -static void *guc_get_write_buffer(struct intel_guc *guc) +static void *guc_get_write_buffer(struct intel_guc_log *log) { - if (!guc_log_has_relay(guc)) + if (!guc_log_has_relay(log)) return NULL; /* @@ -233,25 +237,25 @@ static void *guc_get_write_buffer(struct intel_guc *guc) * done without using relay_reserve() along with relay_write(). So its * better to use relay_reserve() alone. */ - return relay_reserve(guc->log.runtime.relay_chan, 0); + return relay_reserve(log->runtime.relay_chan, 0); } -static bool guc_check_log_buf_overflow(struct intel_guc *guc, +static bool guc_check_log_buf_overflow(struct intel_guc_log *log, enum guc_log_buffer_type type, unsigned int full_cnt) { - unsigned int prev_full_cnt = guc->log.prev_overflow_count[type]; + unsigned int prev_full_cnt = log->prev_overflow_count[type]; bool overflow = false; if (full_cnt != prev_full_cnt) { overflow = true; - guc->log.prev_overflow_count[type] = full_cnt; - guc->log.total_overflow_count[type] += full_cnt - prev_full_cnt; + log->prev_overflow_count[type] = full_cnt; + log->total_overflow_count[type] += full_cnt - prev_full_cnt; if (full_cnt < prev_full_cnt) { /* buffer_full_cnt is a 4 bit counter */ - guc->log.total_overflow_count[type] += 16; + log->total_overflow_count[type] += 16; } DRM_ERROR_RATELIMITED("GuC log buffer overflow\n"); } @@ -275,7 +279,7 @@ static unsigned int guc_get_log_buffer_size(enum guc_log_buffer_type type) return 0; } -static void guc_read_update_log_buffer(struct intel_guc *guc) +static void guc_read_update_log_buffer(struct intel_guc_log *log) { unsigned int buffer_size, read_offset, write_offset, bytes_to_copy, full_cnt; struct guc_log_buffer_state *log_buf_state, *log_buf_snapshot_state; @@ -284,16 +288,16 @@ static void guc_read_update_log_buffer(struct intel_guc *guc) void *src_data, *dst_data; bool new_overflow; - if (WARN_ON(!guc->log.runtime.buf_addr)) + if (WARN_ON(!log->runtime.buf_addr)) return; /* Get the pointer to shared GuC log buffer */ - log_buf_state = src_data = guc->log.runtime.buf_addr; + log_buf_state = src_data = log->runtime.buf_addr; - mutex_lock(&guc->log.runtime.relay_lock); + mutex_lock(&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); + log_buf_snapshot_state = dst_data = guc_get_write_buffer(log); if (unlikely(!log_buf_snapshot_state)) { /* @@ -301,8 +305,8 @@ static void guc_read_update_log_buffer(struct intel_guc *guc) * 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); + log->capture_miss_count++; + mutex_unlock(&log->runtime.relay_lock); return; } @@ -325,8 +329,8 @@ static void guc_read_update_log_buffer(struct intel_guc *guc) full_cnt = log_buf_state_local.buffer_full_cnt; /* Bookkeeping stuff */ - guc->log.flush_count[type] += log_buf_state_local.flush_to_file; - new_overflow = guc_check_log_buf_overflow(guc, type, full_cnt); + log->flush_count[type] += log_buf_state_local.flush_to_file; + new_overflow = guc_check_log_buf_overflow(log, type, full_cnt); /* Update the state of shared log buffer */ log_buf_state->read_ptr = write_offset; @@ -373,38 +377,39 @@ static void guc_read_update_log_buffer(struct intel_guc *guc) dst_data += buffer_size; } - guc_move_to_next_buf(guc); + guc_move_to_next_buf(log); - mutex_unlock(&guc->log.runtime.relay_lock); + mutex_unlock(&log->runtime.relay_lock); } static void capture_logs_work(struct work_struct *work) { - struct intel_guc *guc = - container_of(work, struct intel_guc, log.runtime.flush_work); + struct intel_guc_log *log = + container_of(work, struct intel_guc_log, runtime.flush_work); - guc_log_capture_logs(guc); + guc_log_capture_logs(log); } -static bool guc_log_has_runtime(struct intel_guc *guc) +static bool guc_log_has_runtime(struct intel_guc_log *log) { - return guc->log.runtime.buf_addr != NULL; + return log->runtime.buf_addr; } -static int guc_log_runtime_create(struct intel_guc *guc) +static int guc_log_runtime_create(struct intel_guc_log *log) { + struct intel_guc *guc = log_to_guc(log); struct drm_i915_private *dev_priv = guc_to_i915(guc); void *vaddr; int ret; lockdep_assert_held(&dev_priv->drm.struct_mutex); - if (!guc->log.vma) + if (!log->vma) return -ENODEV; - GEM_BUG_ON(guc_log_has_runtime(guc)); + GEM_BUG_ON(guc_log_has_runtime(log)); - ret = i915_gem_object_set_to_wc_domain(guc->log.vma->obj, true); + ret = i915_gem_object_set_to_wc_domain(log->vma->obj, true); if (ret) return ret; @@ -413,38 +418,39 @@ static int guc_log_runtime_create(struct intel_guc *guc) * buffer pages, so that we can directly get the data * (up-to-date) from memory. */ - vaddr = i915_gem_object_pin_map(guc->log.vma->obj, I915_MAP_WC); + vaddr = i915_gem_object_pin_map(log->vma->obj, I915_MAP_WC); if (IS_ERR(vaddr)) { DRM_ERROR("Couldn't map log buffer pages %d\n", ret); return PTR_ERR(vaddr); } - guc->log.runtime.buf_addr = vaddr; + log->runtime.buf_addr = vaddr; return 0; } -static void guc_log_runtime_destroy(struct intel_guc *guc) +static void guc_log_runtime_destroy(struct intel_guc_log *log) { /* * 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)) + if (!guc_log_has_runtime(log)) return; - i915_gem_object_unpin_map(guc->log.vma->obj); - guc->log.runtime.buf_addr = NULL; + i915_gem_object_unpin_map(log->vma->obj); + log->runtime.buf_addr = NULL; } -void intel_guc_log_init_early(struct intel_guc *guc) +void intel_guc_log_init_early(struct intel_guc_log *log) { - mutex_init(&guc->log.runtime.relay_lock); - INIT_WORK(&guc->log.runtime.flush_work, capture_logs_work); + mutex_init(&log->runtime.relay_lock); + INIT_WORK(&log->runtime.flush_work, capture_logs_work); } -static int guc_log_relay_create(struct intel_guc *guc) +static int guc_log_relay_create(struct intel_guc_log *log) { + struct intel_guc *guc = log_to_guc(log); struct drm_i915_private *dev_priv = guc_to_i915(guc); struct rchan *guc_log_relay_chan; size_t n_subbufs, subbuf_size; @@ -453,9 +459,9 @@ static int guc_log_relay_create(struct intel_guc *guc) if (!i915_modparams.guc_log_level) return 0; - mutex_lock(&guc->log.runtime.relay_lock); + mutex_lock(&log->runtime.relay_lock); - GEM_BUG_ON(guc_log_has_relay(guc)); + GEM_BUG_ON(guc_log_has_relay(log)); /* Keep the size of sub buffers same as shared log buffer */ subbuf_size = GUC_LOG_SIZE; @@ -483,42 +489,43 @@ static int guc_log_relay_create(struct intel_guc *guc) } GEM_BUG_ON(guc_log_relay_chan->subbuf_size < subbuf_size); - guc->log.runtime.relay_chan = guc_log_relay_chan; + log->runtime.relay_chan = guc_log_relay_chan; - mutex_unlock(&guc->log.runtime.relay_lock); + mutex_unlock(&log->runtime.relay_lock); return 0; err: - mutex_unlock(&guc->log.runtime.relay_lock); + mutex_unlock(&log->runtime.relay_lock); /* logging will be off */ i915_modparams.guc_log_level = 0; return ret; } -static void guc_log_relay_destroy(struct intel_guc *guc) +static void guc_log_relay_destroy(struct intel_guc_log *log) { - mutex_lock(&guc->log.runtime.relay_lock); + mutex_lock(&log->runtime.relay_lock); /* * It's possible that the relay was never allocated because * GuC log was disabled at the boot time. */ - if (!guc_log_has_relay(guc)) + if (!guc_log_has_relay(log)) goto out_unlock; - relay_close(guc->log.runtime.relay_chan); - guc->log.runtime.relay_chan = NULL; + relay_close(log->runtime.relay_chan); + log->runtime.relay_chan = NULL; out_unlock: - mutex_unlock(&guc->log.runtime.relay_lock); + mutex_unlock(&log->runtime.relay_lock); } -static void guc_log_capture_logs(struct intel_guc *guc) +static void guc_log_capture_logs(struct intel_guc_log *log) { + struct intel_guc *guc = log_to_guc(log); struct drm_i915_private *dev_priv = guc_to_i915(guc); - guc_read_update_log_buffer(guc); + guc_read_update_log_buffer(log); /* * Generally device is expected to be active only at this @@ -529,15 +536,16 @@ static void guc_log_capture_logs(struct intel_guc *guc) intel_runtime_pm_put(dev_priv); } -static void guc_flush_logs(struct intel_guc *guc) +static void guc_flush_logs(struct intel_guc_log *log) { + struct intel_guc *guc = log_to_guc(log); struct drm_i915_private *dev_priv = guc_to_i915(guc); /* * 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); + flush_work(&log->runtime.flush_work); /* Ask GuC to update the log buffer state */ intel_runtime_pm_get(dev_priv); @@ -545,17 +553,18 @@ static void guc_flush_logs(struct intel_guc *guc) intel_runtime_pm_put(dev_priv); /* GuC would have updated log buffer by now, so capture it */ - guc_log_capture_logs(guc); + guc_log_capture_logs(log); } -int intel_guc_log_create(struct intel_guc *guc) +int intel_guc_log_create(struct intel_guc_log *log) { + struct intel_guc *guc = log_to_guc(log); struct i915_vma *vma; unsigned long offset; u32 flags; int ret; - GEM_BUG_ON(guc->log.vma); + GEM_BUG_ON(log->vma); /* * We require SSE 4.1 for fast reads from the GuC log buffer and @@ -573,7 +582,7 @@ int intel_guc_log_create(struct intel_guc *guc) goto err; } - guc->log.vma = vma; + log->vma = vma; /* each allocated unit is a page */ flags = GUC_LOG_VALID | GUC_LOG_NOTIFY_ON_HALF_FULL | @@ -582,7 +591,7 @@ int intel_guc_log_create(struct intel_guc *guc) (GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT); offset = intel_guc_ggtt_offset(guc, vma) >> PAGE_SHIFT; - guc->log.flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags; + log->flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags; return 0; @@ -592,15 +601,15 @@ err: return ret; } -void intel_guc_log_destroy(struct intel_guc *guc) +void intel_guc_log_destroy(struct intel_guc_log *log) { - guc_log_runtime_destroy(guc); - i915_vma_unpin_and_release(&guc->log.vma); + guc_log_runtime_destroy(log); + i915_vma_unpin_and_release(&log->vma); } -int intel_guc_log_control_get(struct intel_guc *guc) +int intel_guc_log_control_get(struct intel_guc_log *log) { - GEM_BUG_ON(!guc->log.vma); + GEM_BUG_ON(!log->vma); GEM_BUG_ON(i915_modparams.guc_log_level < 0); return i915_modparams.guc_log_level; @@ -613,14 +622,15 @@ int intel_guc_log_control_get(struct intel_guc *guc) LOG_LEVEL_TO_ENABLED(_x) ? _x - 1 : 0; \ }) #define VERBOSITY_TO_LOG_LEVEL(x) ((x) + 1) -int intel_guc_log_control_set(struct intel_guc *guc, u64 val) +int intel_guc_log_control_set(struct intel_guc_log *log, u64 val) { + struct intel_guc *guc = log_to_guc(log); struct drm_i915_private *dev_priv = guc_to_i915(guc); bool enabled = LOG_LEVEL_TO_ENABLED(val); int ret; BUILD_BUG_ON(GUC_LOG_VERBOSITY_MIN != 0); - GEM_BUG_ON(!guc->log.vma); + GEM_BUG_ON(!log->vma); GEM_BUG_ON(i915_modparams.guc_log_level < 0); /* @@ -650,15 +660,15 @@ int intel_guc_log_control_set(struct intel_guc *guc, u64 val) mutex_unlock(&dev_priv->drm.struct_mutex); - if (enabled && !guc_log_has_runtime(guc)) { - ret = intel_guc_log_register(guc); + if (enabled && !guc_log_has_runtime(log)) { + ret = intel_guc_log_register(log); if (ret) { /* logging will remain off */ i915_modparams.guc_log_level = 0; goto out; } - } else if (!enabled && guc_log_has_runtime(guc)) { - intel_guc_log_unregister(guc); + } else if (!enabled && guc_log_has_runtime(log)) { + intel_guc_log_unregister(log); } return 0; @@ -669,30 +679,31 @@ out: return ret; } -int intel_guc_log_register(struct intel_guc *guc) +int intel_guc_log_register(struct intel_guc_log *log) { + struct intel_guc *guc = log_to_guc(log); struct drm_i915_private *i915 = guc_to_i915(guc); int ret; - GEM_BUG_ON(guc_log_has_runtime(guc)); + GEM_BUG_ON(guc_log_has_runtime(log)); /* * 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_relay_create(guc); + ret = guc_log_relay_create(log); if (ret) goto err; mutex_lock(&i915->drm.struct_mutex); - ret = guc_log_runtime_create(guc); + ret = guc_log_runtime_create(log); mutex_unlock(&i915->drm.struct_mutex); if (ret) goto err_relay; - ret = guc_log_relay_file_create(guc); + ret = guc_log_relay_file_create(log); if (ret) goto err_runtime; @@ -707,16 +718,17 @@ int intel_guc_log_register(struct intel_guc *guc) err_runtime: mutex_lock(&i915->drm.struct_mutex); - guc_log_runtime_destroy(guc); + guc_log_runtime_destroy(log); mutex_unlock(&i915->drm.struct_mutex); err_relay: - guc_log_relay_destroy(guc); + guc_log_relay_destroy(log); err: return ret; } -void intel_guc_log_unregister(struct intel_guc *guc) +void intel_guc_log_unregister(struct intel_guc_log *log) { + struct intel_guc *guc = log_to_guc(log); struct drm_i915_private *i915 = guc_to_i915(guc); /* @@ -725,16 +737,17 @@ void intel_guc_log_unregister(struct intel_guc *guc) * which is yet to be captured. So request GuC to update the log * buffer state and then collect the left over logs. */ - guc_flush_logs(guc); + guc_flush_logs(log); mutex_lock(&i915->drm.struct_mutex); + /* GuC logging is currently the only user of Guc2Host interrupts */ intel_runtime_pm_get(i915); gen9_disable_guc_interrupts(i915); intel_runtime_pm_put(i915); - guc_log_runtime_destroy(guc); + guc_log_runtime_destroy(log); mutex_unlock(&i915->drm.struct_mutex); - guc_log_relay_destroy(guc); + guc_log_relay_destroy(log); } diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index 09dd2ef1933d..6264bd5ba080 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -25,11 +25,12 @@ #ifndef _INTEL_GUC_LOG_H_ #define _INTEL_GUC_LOG_H_ +#include +#include #include #include "intel_guc_fwif.h" -struct drm_i915_private; struct intel_guc; /* @@ -59,12 +60,13 @@ struct intel_guc_log { u32 flush_count[GUC_MAX_LOG_BUFFER]; }; -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_control_get(struct intel_guc *guc); -int intel_guc_log_control_set(struct intel_guc *guc, u64 control_val); -int intel_guc_log_register(struct intel_guc *guc); -void intel_guc_log_unregister(struct intel_guc *guc); +void intel_guc_log_init_early(struct intel_guc_log *log); +int intel_guc_log_create(struct intel_guc_log *log); +int intel_guc_log_register(struct intel_guc_log *log); +void intel_guc_log_unregister(struct intel_guc_log *log); +void intel_guc_log_destroy(struct intel_guc_log *log); + +int intel_guc_log_control_get(struct intel_guc_log *log); +int intel_guc_log_control_set(struct intel_guc_log *log, u64 control); #endif diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 6316548a1c78..104c03ae2742 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -229,7 +229,7 @@ int intel_uc_register(struct drm_i915_private *i915) return 0; if (i915_modparams.guc_log_level) - ret = intel_guc_log_register(&i915->guc); + ret = intel_guc_log_register(&i915->guc.log); return ret; } @@ -240,7 +240,7 @@ void intel_uc_unregister(struct drm_i915_private *i915) return; if (i915_modparams.guc_log_level) - intel_guc_log_unregister(&i915->guc); + intel_guc_log_unregister(&i915->guc.log); } static int guc_enable_communication(struct intel_guc *guc) -- cgit v1.2.3 From 7fb96dac6755d053d3a540aff55fe0064001bdf6 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 15 Mar 2018 15:28:47 +0000 Subject: drm/i915/guc: Fix build break on config without DEBUG_FS In commit 56b9a8b08387 ("drm/i915/guc: Update syntax of GuC log functions") we accidentally removed debugfs.h header where needed stub functions were defined. Reported-by: Mike Lothian Signed-off-by: Michal Wajdeczko Cc: Mike Lothian Cc: Chris Wilson Acked-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180315152848.40476-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc_log.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index bfb9a68fffef..1c2127bc3878 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -22,6 +22,8 @@ * */ +#include + #include "intel_guc_log.h" #include "i915_drv.h" -- cgit v1.2.3 From d9b13c4dde6cacd8f2c4385cd6d293b0ac622e0b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 15 Mar 2018 13:14:50 +0000 Subject: drm/i915: Trace GEM steps between submit and wedging We still have an odd race with wedging/unwedging as shown by igt/gem_eio that defies expectations. Add some more trace_printks to try and visualize the flow over the precipice. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Tvrtko Ursulin Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180315131451.4060-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 14 ++++++++++++++ drivers/gpu/drm/i915/i915_request.c | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 13d4b0e74641..2fbd622bba30 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3193,6 +3193,9 @@ void i915_gem_reset_finish(struct drm_i915_private *dev_priv) static void nop_submit_request(struct i915_request *request) { + GEM_TRACE("%s fence %llx:%d -> -EIO\n", + request->engine->name, + request->fence.context, request->fence.seqno); dma_fence_set_error(&request->fence, -EIO); i915_request_submit(request); @@ -3202,6 +3205,9 @@ static void nop_complete_submit_request(struct i915_request *request) { unsigned long flags; + GEM_TRACE("%s fence %llx:%d -> -EIO\n", + request->engine->name, + request->fence.context, request->fence.seqno); dma_fence_set_error(&request->fence, -EIO); spin_lock_irqsave(&request->engine->timeline->lock, flags); @@ -3215,6 +3221,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) struct intel_engine_cs *engine; enum intel_engine_id id; + GEM_TRACE("start\n"); + if (drm_debug & DRM_UT_DRIVER) { struct drm_printer p = drm_debug_printer(__func__); @@ -3279,6 +3287,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) i915_gem_reset_finish_engine(engine); } + GEM_TRACE("end\n"); + wake_up_all(&i915->gpu_error.reset_queue); } @@ -3291,6 +3301,8 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915) if (!test_bit(I915_WEDGED, &i915->gpu_error.flags)) return true; + GEM_TRACE("start\n"); + /* * Before unwedging, make sure that all pending operations * are flushed and errored out - we may have requests waiting upon @@ -3341,6 +3353,8 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915) intel_engines_reset_default_submission(i915); i915_gem_contexts_lost(i915); + GEM_TRACE("end\n"); + smp_mb__before_atomic(); /* complete takeover before enabling execbuf */ clear_bit(I915_WEDGED, &i915->gpu_error.flags); diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 1810fa1b81cb..43c7134a9b93 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -207,11 +207,16 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno) if (ret) return ret; + GEM_BUG_ON(i915->gt.active_requests); + /* If the seqno wraps around, we need to clear the breadcrumb rbtree */ for_each_engine(engine, i915, id) { struct i915_gem_timeline *timeline; struct intel_timeline *tl = engine->timeline; + GEM_TRACE("%s seqno %d -> %d\n", + engine->name, tl->seqno, seqno); + if (!i915_seqno_passed(seqno, tl->seqno)) { /* Flush any waiters before we reuse the seqno */ intel_engine_disarm_breadcrumbs(engine); @@ -381,6 +386,11 @@ static void i915_request_retire(struct i915_request *request) struct intel_engine_cs *engine = request->engine; struct i915_gem_active *active, *next; + GEM_TRACE("%s(%d) fence %llx:%d, global_seqno %d\n", + engine->name, intel_engine_get_seqno(engine), + request->fence.context, request->fence.seqno, + request->global_seqno); + lockdep_assert_held(&request->i915->drm.struct_mutex); GEM_BUG_ON(!i915_sw_fence_signaled(&request->submit)); GEM_BUG_ON(!i915_request_completed(request)); @@ -488,6 +498,11 @@ void __i915_request_submit(struct i915_request *request) struct intel_timeline *timeline; u32 seqno; + GEM_TRACE("%s fence %llx:%d -> global_seqno %d\n", + request->engine->name, + request->fence.context, request->fence.seqno, + engine->timeline->seqno); + GEM_BUG_ON(!irqs_disabled()); lockdep_assert_held(&engine->timeline->lock); @@ -537,6 +552,11 @@ void __i915_request_unsubmit(struct i915_request *request) struct intel_engine_cs *engine = request->engine; struct intel_timeline *timeline; + GEM_TRACE("%s fence %llx:%d <- global_seqno %d\n", + request->engine->name, + request->fence.context, request->fence.seqno, + request->global_seqno); + GEM_BUG_ON(!irqs_disabled()); lockdep_assert_held(&engine->timeline->lock); @@ -996,6 +1016,9 @@ void __i915_request_add(struct i915_request *request, bool flush_caches) u32 *cs; int err; + GEM_TRACE("%s fence %llx:%d\n", + engine->name, request->fence.context, request->fence.seqno); + lockdep_assert_held(&request->i915->drm.struct_mutex); trace_i915_request_add(request); -- cgit v1.2.3 From ac697ae8013a7c7301174c9c3b02a92fe418b7ea Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 15 Mar 2018 15:10:15 +0000 Subject: drm/i915: Stop engines when declaring the machine wedged MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we fail to reset the GPU, we declare the machine wedged. However, the GPU may well still be running in the background with an in-flight request. So despite our efforts in cleaning up the request queue and faking the breadcrumb in the HWSP, the GPU may eventually write the in-flght seqno there breaking all of our assumptions and throwing the driver into a deep turmoil, wedging beyond wedged. To avoid this we ideally want to reset the GPU. Since that has already failed, make sure the rings have the stop bit set instead. This is part of the normal GPU reset sequence, but that is actually disabled by igt/gem_eio to force the wedged state. If we assume the worst, we must poke at the bit again before we give up. v2: Move the intel_gpu_reset() from set-wedged in the reset error path into i915_gem_set_wedged() itself. Even if the reset fails (e.g. if it is disabled by gem_eio), it still tries to make sure the engines are stopped. For i915_gem_set_wedged() callers from outside of i915_reset(), this should make sure the GPU is disabled while the driver is marked as being wedged. Testcase: igt/gem_eio Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Michał Winiarski Cc: Michal Wajdeczko Cc: Michel Thierry Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180315151015.22741-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.c | 1 - drivers/gpu/drm/i915/i915_gem.c | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f03555efc520..3df5193487f3 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1995,7 +1995,6 @@ taint: error: i915_gem_set_wedged(i915); i915_retire_requests(i915); - intel_gpu_reset(i915, ALL_ENGINES); goto finish; } diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2fbd622bba30..802df8e1a544 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3246,6 +3246,9 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) } i915->caps.scheduler = 0; + /* Even if the GPU reset fails, it should still stop the engines */ + intel_gpu_reset(i915, ALL_ENGINES); + /* * Make sure no one is running the old callback before we proceed with * cancelling requests and resetting the completion tracking. Otherwise -- cgit v1.2.3 From 0c65dfd1a84142887c810fc11573e2edb8df87f6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 12 Mar 2018 16:52:04 +0000 Subject: drm/i915/stolen: Switch from DEBUG_KMS to DEBUG_DRIVER MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i915_gem_stolen is an allocator for the reserved portion of memory ("stolen" from the system by the BIOS). It is not tied to KMS but central to the driver, so prefer DRM_DEBUG_DRIVER. Signed-off-by: Chris Wilson Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180312165206.31772-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_stolen.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 62aa67960bf4..f11a4b908aaf 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -121,8 +121,8 @@ static int i915_adjust_stolen(struct drm_i915_private *dev_priv, if (stolen[0].start != stolen[1].start || stolen[0].end != stolen[1].end) { - DRM_DEBUG_KMS("GTT within stolen memory at %pR\n", &ggtt_res); - DRM_DEBUG_KMS("Stolen memory adjusted to %pR\n", dsm); + DRM_DEBUG_DRIVER("GTT within stolen memory at %pR\n", &ggtt_res); + DRM_DEBUG_DRIVER("Stolen memory adjusted to %pR\n", dsm); } } @@ -406,9 +406,9 @@ int i915_gem_init_stolen(struct drm_i915_private *dev_priv) * memory, so just consider the start. */ reserved_total = stolen_top - reserved_base; - DRM_DEBUG_KMS("Memory reserved for graphics device: %lluK, usable: %lluK\n", - (u64)resource_size(&dev_priv->dsm) >> 10, - ((u64)resource_size(&dev_priv->dsm) - reserved_total) >> 10); + DRM_DEBUG_DRIVER("Memory reserved for graphics device: %lluK, usable: %lluK\n", + (u64)resource_size(&dev_priv->dsm) >> 10, + ((u64)resource_size(&dev_priv->dsm) - reserved_total) >> 10); stolen_usable_start = 0; /* WaSkipStolenMemoryFirstPage:bdw+ */ @@ -580,8 +580,8 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv lockdep_assert_held(&dev_priv->drm.struct_mutex); - DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%pa, gtt_offset=%pa, size=%pa\n", - &stolen_offset, >t_offset, &size); + DRM_DEBUG_DRIVER("creating preallocated stolen object: stolen_offset=%pa, gtt_offset=%pa, size=%pa\n", + &stolen_offset, >t_offset, &size); /* KISS and expect everything to be page-aligned */ if (WARN_ON(size == 0) || @@ -599,14 +599,14 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv ret = drm_mm_reserve_node(&dev_priv->mm.stolen, stolen); mutex_unlock(&dev_priv->mm.stolen_lock); if (ret) { - DRM_DEBUG_KMS("failed to allocate stolen space\n"); + DRM_DEBUG_DRIVER("failed to allocate stolen space\n"); kfree(stolen); return NULL; } obj = _i915_gem_object_create_stolen(dev_priv, stolen); if (obj == NULL) { - DRM_DEBUG_KMS("failed to allocate stolen object\n"); + DRM_DEBUG_DRIVER("failed to allocate stolen object\n"); i915_gem_stolen_remove_node(dev_priv, stolen); kfree(stolen); return NULL; @@ -635,7 +635,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv size, gtt_offset, obj->cache_level, 0); if (ret) { - DRM_DEBUG_KMS("failed to allocate stolen GTT space\n"); + DRM_DEBUG_DRIVER("failed to allocate stolen GTT space\n"); goto err_pages; } -- cgit v1.2.3 From 0efb656147e04f26433de5a399d1b03bf00e4ed6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 12 Mar 2018 16:52:05 +0000 Subject: drm/i915/stolen: Checkpatch cleansing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the next patch, we will introduce a new vlv_get_stolen_reserved, so before we do, make sure checkpatch is happy with the surrounding code. Sneak in some debug output while we are here. Signed-off-by: Chris Wilson Cc: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180312165206.31772-2-chris@chris-wilson.co.uk Reviewed-by: Ville Syrjälä --- drivers/gpu/drm/i915/i915_gem_stolen.c | 40 ++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index f11a4b908aaf..5a57a1773fa7 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -174,13 +174,17 @@ void i915_gem_cleanup_stolen(struct drm_device *dev) } static void g4x_get_stolen_reserved(struct drm_i915_private *dev_priv, - resource_size_t *base, resource_size_t *size) + resource_size_t *base, + resource_size_t *size) { - uint32_t reg_val = I915_READ(IS_GM45(dev_priv) ? - CTG_STOLEN_RESERVED : - ELK_STOLEN_RESERVED); + u32 reg_val = I915_READ(IS_GM45(dev_priv) ? + CTG_STOLEN_RESERVED : + ELK_STOLEN_RESERVED); resource_size_t stolen_top = dev_priv->dsm.end + 1; + DRM_DEBUG_DRIVER("%s_STOLEN_RESERVED = %08x\n", + IS_GM45(dev_priv) ? "CTG" : "ELK", reg_val); + if ((reg_val & G4X_STOLEN_RESERVED_ENABLE) == 0) { *base = 0; *size = 0; @@ -208,9 +212,12 @@ static void g4x_get_stolen_reserved(struct drm_i915_private *dev_priv, } static void gen6_get_stolen_reserved(struct drm_i915_private *dev_priv, - resource_size_t *base, resource_size_t *size) + resource_size_t *base, + resource_size_t *size) { - uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED); + u32 reg_val = I915_READ(GEN6_STOLEN_RESERVED); + + DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val); if ((reg_val & GEN6_STOLEN_RESERVED_ENABLE) == 0) { *base = 0; @@ -240,9 +247,12 @@ static void gen6_get_stolen_reserved(struct drm_i915_private *dev_priv, } static void gen7_get_stolen_reserved(struct drm_i915_private *dev_priv, - resource_size_t *base, resource_size_t *size) + resource_size_t *base, + resource_size_t *size) { - uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED); + u32 reg_val = I915_READ(GEN6_STOLEN_RESERVED); + + DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val); if ((reg_val & GEN6_STOLEN_RESERVED_ENABLE) == 0) { *base = 0; @@ -266,9 +276,12 @@ static void gen7_get_stolen_reserved(struct drm_i915_private *dev_priv, } static void chv_get_stolen_reserved(struct drm_i915_private *dev_priv, - resource_size_t *base, resource_size_t *size) + resource_size_t *base, + resource_size_t *size) { - uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED); + u32 reg_val = I915_READ(GEN6_STOLEN_RESERVED); + + DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val); if ((reg_val & GEN6_STOLEN_RESERVED_ENABLE) == 0) { *base = 0; @@ -298,11 +311,14 @@ static void chv_get_stolen_reserved(struct drm_i915_private *dev_priv, } static void bdw_get_stolen_reserved(struct drm_i915_private *dev_priv, - resource_size_t *base, resource_size_t *size) + resource_size_t *base, + resource_size_t *size) { - uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED); + u32 reg_val = I915_READ(GEN6_STOLEN_RESERVED); resource_size_t stolen_top; + DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val); + if ((reg_val & GEN6_STOLEN_RESERVED_ENABLE) == 0) { *base = 0; *size = 0; -- cgit v1.2.3 From 957d32feaf04d2a67fd506743e5789359480d574 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 12 Mar 2018 16:52:06 +0000 Subject: drm/i915/stolen: Deduce base of reserved portion as top-size on vlv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Valleyview, the HW deduces the base of the reserved portion of stolen memory as being (top - size) and the address field within GEN6_STOLEN_RESERVED is set to 0. Add yet another GEN6_STOLEN_RESERVED reader to cope with the subtly different path required for vlv. v2: Avoid using reserved_base = reserved_size = 0 as the invalid condition as that typically falls outside of the stolen region, provoking a consistency error. Signed-off-by: Chris Wilson Cc: Ville Syrjälä Cc: Imre Deak Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180312165206.31772-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_stolen.c | 103 ++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 5a57a1773fa7..af915d041281 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -185,11 +185,8 @@ static void g4x_get_stolen_reserved(struct drm_i915_private *dev_priv, DRM_DEBUG_DRIVER("%s_STOLEN_RESERVED = %08x\n", IS_GM45(dev_priv) ? "CTG" : "ELK", reg_val); - if ((reg_val & G4X_STOLEN_RESERVED_ENABLE) == 0) { - *base = 0; - *size = 0; + if ((reg_val & G4X_STOLEN_RESERVED_ENABLE) == 0) return; - } /* * Whether ILK really reuses the ELK register for this is unclear. @@ -197,18 +194,13 @@ static void g4x_get_stolen_reserved(struct drm_i915_private *dev_priv, */ WARN(IS_GEN5(dev_priv), "ILK stolen reserved found? 0x%08x\n", reg_val); - *base = (reg_val & G4X_STOLEN_RESERVED_ADDR2_MASK) << 16; + if (!(reg_val & G4X_STOLEN_RESERVED_ADDR2_MASK)) + return; + *base = (reg_val & G4X_STOLEN_RESERVED_ADDR2_MASK) << 16; WARN_ON((reg_val & G4X_STOLEN_RESERVED_ADDR1_MASK) < *base); - /* On these platforms, the register doesn't have a size field, so the - * size is the distance between the base and the top of the stolen - * memory. We also have the genuine case where base is zero and there's - * nothing reserved. */ - if (*base == 0) - *size = 0; - else - *size = stolen_top - *base; + *size = stolen_top - *base; } static void gen6_get_stolen_reserved(struct drm_i915_private *dev_priv, @@ -219,11 +211,8 @@ static void gen6_get_stolen_reserved(struct drm_i915_private *dev_priv, DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val); - if ((reg_val & GEN6_STOLEN_RESERVED_ENABLE) == 0) { - *base = 0; - *size = 0; + if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE)) return; - } *base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK; @@ -246,6 +235,33 @@ static void gen6_get_stolen_reserved(struct drm_i915_private *dev_priv, } } +static void vlv_get_stolen_reserved(struct drm_i915_private *dev_priv, + resource_size_t *base, + resource_size_t *size) +{ + u32 reg_val = I915_READ(GEN6_STOLEN_RESERVED); + resource_size_t stolen_top = dev_priv->dsm.end + 1; + + DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val); + + if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE)) + return; + + switch (reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK) { + default: + MISSING_CASE(reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK); + case GEN7_STOLEN_RESERVED_1M: + *size = 1024 * 1024; + break; + } + + /* + * On vlv, the ADDR_MASK portion is left as 0 and HW deduces the + * reserved location as (top - size). + */ + *base = stolen_top - *size; +} + static void gen7_get_stolen_reserved(struct drm_i915_private *dev_priv, resource_size_t *base, resource_size_t *size) @@ -254,11 +270,8 @@ static void gen7_get_stolen_reserved(struct drm_i915_private *dev_priv, DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val); - if ((reg_val & GEN6_STOLEN_RESERVED_ENABLE) == 0) { - *base = 0; - *size = 0; + if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE)) return; - } *base = reg_val & GEN7_STOLEN_RESERVED_ADDR_MASK; @@ -283,11 +296,8 @@ static void chv_get_stolen_reserved(struct drm_i915_private *dev_priv, DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val); - if ((reg_val & GEN6_STOLEN_RESERVED_ENABLE) == 0) { - *base = 0; - *size = 0; + if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE)) return; - } *base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK; @@ -315,28 +325,18 @@ static void bdw_get_stolen_reserved(struct drm_i915_private *dev_priv, resource_size_t *size) { u32 reg_val = I915_READ(GEN6_STOLEN_RESERVED); - resource_size_t stolen_top; + resource_size_t stolen_top = dev_priv->dsm.end + 1; DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = %08x\n", reg_val); - if ((reg_val & GEN6_STOLEN_RESERVED_ENABLE) == 0) { - *base = 0; - *size = 0; + if (!(reg_val & GEN6_STOLEN_RESERVED_ENABLE)) return; - } - stolen_top = dev_priv->dsm.end + 1; + if (!(reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK)) + return; *base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK; - - /* On these platforms, the register doesn't have a size field, so the - * size is the distance between the base and the top of the stolen - * memory. We also have the genuine case where base is zero and there's - * nothing reserved. */ - if (*base == 0) - *size = 0; - else - *size = stolen_top - *base; + *size = stolen_top - *base; } int i915_gem_init_stolen(struct drm_i915_private *dev_priv) @@ -369,7 +369,7 @@ int i915_gem_init_stolen(struct drm_i915_private *dev_priv) GEM_BUG_ON(dev_priv->dsm.end <= dev_priv->dsm.start); stolen_top = dev_priv->dsm.end + 1; - reserved_base = 0; + reserved_base = stolen_top; reserved_size = 0; switch (INTEL_GEN(dev_priv)) { @@ -389,8 +389,12 @@ int i915_gem_init_stolen(struct drm_i915_private *dev_priv) &reserved_base, &reserved_size); break; case 7: - gen7_get_stolen_reserved(dev_priv, - &reserved_base, &reserved_size); + if (IS_VALLEYVIEW(dev_priv)) + vlv_get_stolen_reserved(dev_priv, + &reserved_base, &reserved_size); + else + gen7_get_stolen_reserved(dev_priv, + &reserved_base, &reserved_size); break; default: if (IS_LP(dev_priv)) @@ -402,11 +406,16 @@ int i915_gem_init_stolen(struct drm_i915_private *dev_priv) break; } - /* It is possible for the reserved base to be zero, but the register - * field for size doesn't have a zero option. */ - if (reserved_base == 0) { - reserved_size = 0; + /* + * Our expectation is that the reserved space is at the top of the + * stolen region and *never* at the bottom. If we see !reserved_base, + * it likely means we failed to read the registers correctly. + */ + if (!reserved_base) { + DRM_ERROR("inconsistent reservation %pa + %pa; ignoring\n", + &reserved_base, &reserved_size); reserved_base = stolen_top; + reserved_size = 0; } dev_priv->dsm_reserved = -- cgit v1.2.3 From 1947fd133cf0f58b171adc8565685c1a06de07b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 5 Mar 2018 19:41:22 +0200 Subject: drm/i915: Don't initialize plane_to_crtc_mapping[] on SKL+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't use the enum i9xx_plane_id namespace on SKL+ anymore, so do not initialize the related plane_to_crtc_mapping[] table either. Actually the only remaining user of that table is the pre-g4x watermark code, but no harm in initializing the table on all pre-SKL platforms. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180305174122.17273-1-ville.syrjala@linux.intel.com Reviewed-by: Dhinakaran Pandiyan --- drivers/gpu/drm/i915/intel_display.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a7bfa238054c..b31b80643f87 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13570,10 +13570,17 @@ static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) /* initialize shared scalers */ intel_crtc_init_scalers(intel_crtc, crtc_state); - BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) || - dev_priv->plane_to_crtc_mapping[primary->i9xx_plane] != NULL); - dev_priv->plane_to_crtc_mapping[primary->i9xx_plane] = intel_crtc; - dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = intel_crtc; + BUG_ON(pipe >= ARRAY_SIZE(dev_priv->pipe_to_crtc_mapping) || + dev_priv->pipe_to_crtc_mapping[pipe] != NULL); + dev_priv->pipe_to_crtc_mapping[pipe] = intel_crtc; + + if (INTEL_GEN(dev_priv) < 9) { + enum i9xx_plane_id i9xx_plane = primary->i9xx_plane; + + BUG_ON(i9xx_plane >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) || + dev_priv->plane_to_crtc_mapping[i9xx_plane] != NULL); + dev_priv->plane_to_crtc_mapping[i9xx_plane] = intel_crtc; + } drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); -- cgit v1.2.3 From e4006713d16567c203ba710f6a2b709ed6107db5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 16 Mar 2018 16:12:13 +0200 Subject: i915: Re-use DEFINE_SHOW_ATTRIBUTE() macro ...instead of open coding file operations followed by custom ->open() callbacks per each attribute. Reviewed-by: Chris Wilson Signed-off-by: Andy Shevchenko Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180316141213.38774-1-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/i915/gvt/debugfs.c | 13 +------ drivers/gpu/drm/i915/i915_debugfs.c | 76 ++++++------------------------------- 2 files changed, 12 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/gvt/debugfs.c b/drivers/gpu/drm/i915/gvt/debugfs.c index 32a66dfdf112..f7d0078eb61b 100644 --- a/drivers/gpu/drm/i915/gvt/debugfs.c +++ b/drivers/gpu/drm/i915/gvt/debugfs.c @@ -122,18 +122,7 @@ static int vgpu_mmio_diff_show(struct seq_file *s, void *unused) seq_printf(s, "Total: %d, Diff: %d\n", param.total, param.diff); return 0; } - -static int vgpu_mmio_diff_open(struct inode *inode, struct file *file) -{ - return single_open(file, vgpu_mmio_diff_show, inode->i_private); -} - -static const struct file_operations vgpu_mmio_diff_fops = { - .open = vgpu_mmio_diff_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(vgpu_mmio_diff); /** * intel_gvt_debugfs_add_vgpu - register debugfs entries for a vGPU diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 298a3aa9513b..5378863e3238 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3562,7 +3562,8 @@ static ssize_t i915_displayport_test_active_write(struct file *file, static int i915_displayport_test_active_show(struct seq_file *m, void *data) { - struct drm_device *dev = m->private; + struct drm_i915_private *dev_priv = m->private; + struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; struct intel_dp *intel_dp; @@ -3596,10 +3597,8 @@ static int i915_displayport_test_active_show(struct seq_file *m, void *data) static int i915_displayport_test_active_open(struct inode *inode, struct file *file) { - struct drm_i915_private *dev_priv = inode->i_private; - return single_open(file, i915_displayport_test_active_show, - &dev_priv->drm); + inode->i_private); } static const struct file_operations i915_displayport_test_active_fops = { @@ -3613,7 +3612,8 @@ static const struct file_operations i915_displayport_test_active_fops = { static int i915_displayport_test_data_show(struct seq_file *m, void *data) { - struct drm_device *dev = m->private; + struct drm_i915_private *dev_priv = m->private; + struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; struct intel_dp *intel_dp; @@ -3652,26 +3652,12 @@ static int i915_displayport_test_data_show(struct seq_file *m, void *data) return 0; } -static int i915_displayport_test_data_open(struct inode *inode, - struct file *file) -{ - struct drm_i915_private *dev_priv = inode->i_private; - - return single_open(file, i915_displayport_test_data_show, - &dev_priv->drm); -} - -static const struct file_operations i915_displayport_test_data_fops = { - .owner = THIS_MODULE, - .open = i915_displayport_test_data_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release -}; +DEFINE_SHOW_ATTRIBUTE(i915_displayport_test_data); static int i915_displayport_test_type_show(struct seq_file *m, void *data) { - struct drm_device *dev = m->private; + struct drm_i915_private *dev_priv = m->private; + struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; struct intel_dp *intel_dp; @@ -3698,23 +3684,7 @@ static int i915_displayport_test_type_show(struct seq_file *m, void *data) return 0; } - -static int i915_displayport_test_type_open(struct inode *inode, - struct file *file) -{ - struct drm_i915_private *dev_priv = inode->i_private; - - return single_open(file, i915_displayport_test_type_show, - &dev_priv->drm); -} - -static const struct file_operations i915_displayport_test_type_fops = { - .owner = THIS_MODULE, - .open = i915_displayport_test_type_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release -}; +DEFINE_SHOW_ATTRIBUTE(i915_displayport_test_type); static void wm_latency_show(struct seq_file *m, const uint16_t wm[8]) { @@ -4875,19 +4845,7 @@ static int i915_dpcd_show(struct seq_file *m, void *data) return 0; } - -static int i915_dpcd_open(struct inode *inode, struct file *file) -{ - return single_open(file, i915_dpcd_show, inode->i_private); -} - -static const struct file_operations i915_dpcd_fops = { - .owner = THIS_MODULE, - .open = i915_dpcd_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(i915_dpcd); static int i915_panel_show(struct seq_file *m, void *data) { @@ -4909,19 +4867,7 @@ static int i915_panel_show(struct seq_file *m, void *data) return 0; } - -static int i915_panel_open(struct inode *inode, struct file *file) -{ - return single_open(file, i915_panel_show, inode->i_private); -} - -static const struct file_operations i915_panel_fops = { - .owner = THIS_MODULE, - .open = i915_panel_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(i915_panel); /** * i915_debugfs_connector_add - add i915 specific connector debugfs files -- cgit v1.2.3 From 3b358cdaf3319521efdf19ff07918bcc4d57013e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 2 Mar 2018 11:56:56 +0200 Subject: drm/i915: Kill the remaining CHV HBR2 leftovers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AFAIK CHV was supposed to have HBR2 originally, but in the end the feature was dropped. We still have some code leftovers from those early days. Eliminate them. The extra bit for the training pattern seems to be dead in the hardware. I can set it (in fact I can set almost any reserved bit in the registers) but it doesn't seem to interfere with the operation of the hardware. Either that or I'm very lucky that my displays complete link training with the incorrect pattern being sent out. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180302095656.19662-1-ville.syrjala@linux.intel.com Reviewed-by: Dhinakaran Pandiyan --- drivers/gpu/drm/i915/i915_reg.h | 2 -- drivers/gpu/drm/i915/intel_dp.c | 20 ++++---------------- 2 files changed, 4 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index dbcb8829faba..1b48d50dfcf1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4943,8 +4943,6 @@ enum { #define DP_LINK_TRAIN_OFF (3 << 28) #define DP_LINK_TRAIN_MASK (3 << 28) #define DP_LINK_TRAIN_SHIFT 28 -#define DP_LINK_TRAIN_PAT_3_CHV (1 << 14) -#define DP_LINK_TRAIN_MASK_CHV ((3 << 28)|(1<<14)) /* CPT Link training mode */ #define DP_LINK_TRAIN_PAT_1_CPT (0 << 8) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 4dd1b2287dd6..62f82c4298ac 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -91,8 +91,6 @@ static const struct dp_link_dpll chv_dpll[] = { { .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a } }, { 270000, /* m2_int = 27, m2_fraction = 0 */ { .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } }, - { 540000, /* m2_int = 27, m2_fraction = 0 */ - { .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } } }; /** @@ -2900,10 +2898,7 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp, } } else { - if (IS_CHERRYVIEW(dev_priv)) - *DP &= ~DP_LINK_TRAIN_MASK_CHV; - else - *DP &= ~DP_LINK_TRAIN_MASK; + *DP &= ~DP_LINK_TRAIN_MASK; switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { case DP_TRAINING_PATTERN_DISABLE: @@ -2916,12 +2911,8 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp, *DP |= DP_LINK_TRAIN_PAT_2; break; case DP_TRAINING_PATTERN_3: - if (IS_CHERRYVIEW(dev_priv)) { - *DP |= DP_LINK_TRAIN_PAT_3_CHV; - } else { - DRM_DEBUG_KMS("TPS3 not supported, using TPS2 instead\n"); - *DP |= DP_LINK_TRAIN_PAT_2; - } + DRM_DEBUG_KMS("TPS3 not supported, using TPS2 instead\n"); + *DP |= DP_LINK_TRAIN_PAT_2; break; } } @@ -3660,10 +3651,7 @@ intel_dp_link_down(struct intel_encoder *encoder, DP &= ~DP_LINK_TRAIN_MASK_CPT; DP |= DP_LINK_TRAIN_PAT_IDLE_CPT; } else { - if (IS_CHERRYVIEW(dev_priv)) - DP &= ~DP_LINK_TRAIN_MASK_CHV; - else - DP &= ~DP_LINK_TRAIN_MASK; + DP &= ~DP_LINK_TRAIN_MASK; DP |= DP_LINK_TRAIN_PAT_IDLE; } I915_WRITE(intel_dp->output_reg, DP); -- cgit v1.2.3 From ad260ab32a4d94fa974f58262f8000472d34fd5b Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Tue, 13 Mar 2018 22:48:25 -0700 Subject: drm/i915/dp: Write to SET_POWER dpcd to enable MST hub. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If bios sets up an MST output and hardware state readout code sees this is an SST configuration, when disabling the encoder we end up calling ->post_disable_dp() hook instead of the MST version. Consequently, we write to the DP_SET_POWER dpcd to set it D3 state. Further along when we try enable the encoder in MST mode, POWER_UP_PHY transaction fails to power up the MST hub. This results in continuous link training failures which keep the system busy delaying boot. We could identify bios MST boot discrepancy and handle it accordingly but a simple way to solve this is to write to the DP_SET_POWER dpcd for MST too. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105470 Cc: Ville Syrjälä Cc: Jani Nikula Reviewed-by: Ville Syrjälä Reported-by: Laura Abbott Cc: stable@vger.kernel.org Fixes: 5ea2355a100a ("drm/i915/mst: Use MST sideband message transactions for dpms control") Tested-by: Laura Abbott Signed-off-by: Dhinakaran Pandiyan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180314054825.1718-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_ddi.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index dbcf1a0586f9..8c2d778560f0 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2205,8 +2205,7 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder, intel_prepare_dp_ddi_buffers(encoder, crtc_state); intel_ddi_init_dp_buf_reg(encoder); - if (!is_mst) - intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_start_link_train(intel_dp); if (port != PORT_A || INTEL_GEN(dev_priv) >= 9) intel_dp_stop_link_train(intel_dp); @@ -2304,14 +2303,12 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); struct intel_dp *intel_dp = &dig_port->dp; - bool is_mst = intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST); /* * Power down sink before disabling the port, otherwise we end * up getting interrupts from the sink on detecting link loss. */ - if (!is_mst) - intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); intel_disable_ddi_buf(encoder); -- cgit v1.2.3 From eacd8391f977d3800cc41a026f9f81fce210a78c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 19 Mar 2018 10:53:36 +0100 Subject: drm/i915/guc: Keep GuC interrupts enabled when using GuC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GuC log contains a separate space used for crash dump. We even get a separate notification for it. While we're not handling crash differently yet, it makes sense to decouple the two right now to simplify the following patches. v2: Move guc_log_flush_irq_disable up to avoid movement in following patches (Sagar). v3: s/guc_log_flush_irq_*/guc_flush_log_msg_*, rebase after mass rename Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Michal Wajdeczko Reviewed-by: Sagar Arun Kamble (v2) Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180319095348.9716-1-michal.winiarski@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 25 ++++++++++--------------- drivers/gpu/drm/i915/intel_guc.h | 2 ++ drivers/gpu/drm/i915/intel_guc_log.c | 31 +++++++++++++++++++------------ drivers/gpu/drm/i915/intel_uc.c | 14 +++++--------- 4 files changed, 36 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index e70bf654d21e..3af603536b1b 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -67,6 +67,7 @@ void intel_guc_init_early(struct intel_guc *guc) intel_guc_log_init_early(&guc->log); mutex_init(&guc->send_mutex); + spin_lock_init(&guc->irq_lock); guc->send = intel_guc_send_nop; guc->notify = gen8_guc_raise_irq; } @@ -368,7 +369,7 @@ int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len) void intel_guc_to_host_event_handler(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); - u32 msg, flush; + u32 msg, val; /* * Sample the log buffer flush related bits & clear them out now @@ -381,24 +382,18 @@ void intel_guc_to_host_event_handler(struct intel_guc *guc) * could happen that GuC sets the bit for 2nd interrupt but Host * clears out the bit on handling the 1st interrupt. */ - - msg = I915_READ(SOFT_SCRATCH(15)); - flush = msg & (INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED | - INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER); - if (flush) { - /* Clear the message bits that are handled */ - I915_WRITE(SOFT_SCRATCH(15), msg & ~flush); - - /* Handle flush interrupt in bottom half */ + spin_lock(&guc->irq_lock); + val = I915_READ(SOFT_SCRATCH(15)); + msg = val & guc->msg_enabled_mask; + I915_WRITE(SOFT_SCRATCH(15), val & ~msg); + spin_unlock(&guc->irq_lock); + + if (msg & (INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER | + INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED)) { queue_work(guc->log.runtime.flush_wq, &guc->log.runtime.flush_work); guc->log.flush_interrupt_count++; - } else { - /* - * Not clearing of unhandled event bits won't result in - * re-triggering of the interrupt. - */ } } diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index cdb649a9a4cf..9a95d1518aa9 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -56,7 +56,9 @@ struct intel_guc { struct drm_i915_gem_object *load_err_log; /* intel_guc_recv interrupt related state */ + spinlock_t irq_lock; bool interrupts_enabled; + unsigned int msg_enabled_mask; struct i915_vma *ads_vma; struct i915_vma *stage_desc_pool; diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 1c2127bc3878..1e209fcf90e1 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -73,6 +73,22 @@ static int guc_log_control(struct intel_guc *guc, bool enable, u32 verbosity) return intel_guc_send(guc, action, ARRAY_SIZE(action)); } +static void guc_flush_log_msg_enable(struct intel_guc *guc) +{ + spin_lock_irq(&guc->irq_lock); + guc->msg_enabled_mask |= INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER | + INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED; + spin_unlock_irq(&guc->irq_lock); +} + +static void guc_flush_log_msg_disable(struct intel_guc *guc) +{ + spin_lock_irq(&guc->irq_lock); + guc->msg_enabled_mask &= ~(INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER | + INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED); + spin_unlock_irq(&guc->irq_lock); +} + static inline struct intel_guc *log_to_guc(struct intel_guc_log *log) { return container_of(log, struct intel_guc, log); @@ -709,12 +725,7 @@ int intel_guc_log_register(struct intel_guc_log *log) if (ret) goto err_runtime; - /* GuC logging is currently the only user of Guc2Host interrupts */ - mutex_lock(&i915->drm.struct_mutex); - intel_runtime_pm_get(i915); - gen9_enable_guc_interrupts(i915); - intel_runtime_pm_put(i915); - mutex_unlock(&i915->drm.struct_mutex); + guc_flush_log_msg_enable(guc); return 0; @@ -733,6 +744,8 @@ void intel_guc_log_unregister(struct intel_guc_log *log) struct intel_guc *guc = log_to_guc(log); struct drm_i915_private *i915 = guc_to_i915(guc); + guc_flush_log_msg_disable(guc); + /* * Once logging is disabled, GuC won't generate logs & send an * interrupt. But there could be some data in the log buffer @@ -742,12 +755,6 @@ void intel_guc_log_unregister(struct intel_guc_log *log) guc_flush_logs(log); mutex_lock(&i915->drm.struct_mutex); - - /* GuC logging is currently the only user of Guc2Host interrupts */ - intel_runtime_pm_get(i915); - gen9_disable_guc_interrupts(i915); - intel_runtime_pm_put(i915); - guc_log_runtime_destroy(log); mutex_unlock(&i915->drm.struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 104c03ae2742..765b86a53f19 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -247,6 +247,8 @@ static int guc_enable_communication(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); + gen9_enable_guc_interrupts(dev_priv); + if (HAS_GUC_CT(dev_priv)) return intel_guc_enable_ct(guc); @@ -261,6 +263,8 @@ static void guc_disable_communication(struct intel_guc *guc) if (HAS_GUC_CT(dev_priv)) intel_guc_disable_ct(guc); + gen9_disable_guc_interrupts(dev_priv); + guc->send = intel_guc_send_nop; } @@ -413,12 +417,9 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) } if (USES_GUC_SUBMISSION(dev_priv)) { - if (i915_modparams.guc_log_level) - gen9_enable_guc_interrupts(dev_priv); - ret = intel_guc_submission_enable(guc); if (ret) - goto err_interrupts; + goto err_communication; } dev_info(dev_priv->drm.dev, "GuC firmware version %u.%u\n", @@ -433,8 +434,6 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) /* * We've failed to load the firmware :( */ -err_interrupts: - gen9_disable_guc_interrupts(dev_priv); err_communication: guc_disable_communication(guc); err_log_capture: @@ -464,9 +463,6 @@ void intel_uc_fini_hw(struct drm_i915_private *dev_priv) intel_guc_submission_disable(guc); guc_disable_communication(guc); - - if (USES_GUC_SUBMISSION(dev_priv)) - gen9_disable_guc_interrupts(dev_priv); } int intel_uc_suspend(struct drm_i915_private *i915) -- cgit v1.2.3 From b813d50e869aeda09ccf22e8d869e61b63389e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 19 Mar 2018 10:53:37 +0100 Subject: drm/i915/guc: Log runtime should consist of both mapping and relay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, we're treating relay and mapping of GuC log as a separate concepts. We're also using inconsistent locking, sometimes using relay_lock, sometimes using struct mutex. Let's correct that. Anything touching the runtime is now serialized using runtime.lock, while we're still using struct mutex as inner lock for mapping. We're still racy in setting the log level - but we'll take care of that in the following patches. v2: Tidy locking (Sagar) v3: Remove obsoleted comment (Sagar) Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Michal Wajdeczko Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180319095348.9716-2-michal.winiarski@intel.com --- drivers/gpu/drm/i915/intel_guc_log.c | 125 +++++++++++------------------------ drivers/gpu/drm/i915/intel_guc_log.h | 3 +- 2 files changed, 38 insertions(+), 90 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 1e209fcf90e1..b82866bfbef5 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -176,10 +176,7 @@ static int guc_log_relay_file_create(struct intel_guc_log *log) struct dentry *log_dir; int ret; - if (!i915_modparams.guc_log_level) - return 0; - - mutex_lock(&log->runtime.relay_lock); + lockdep_assert_held(&log->runtime.lock); /* For now create the log file in /sys/kernel/debug/dri/0 dir */ log_dir = dev_priv->drm.primary->debugfs_root; @@ -198,29 +195,17 @@ static int guc_log_relay_file_create(struct intel_guc_log *log) */ if (!log_dir) { DRM_ERROR("Debugfs dir not available yet for GuC log file\n"); - ret = -ENODEV; - goto out_unlock; + return -ENODEV; } ret = relay_late_setup_files(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); - goto out_unlock; + return ret; } - ret = 0; - -out_unlock: - mutex_unlock(&log->runtime.relay_lock); - return ret; -} - -static bool guc_log_has_relay(struct intel_guc_log *log) -{ - lockdep_assert_held(&log->runtime.relay_lock); - - return log->runtime.relay_chan; + return 0; } static void guc_move_to_next_buf(struct intel_guc_log *log) @@ -231,9 +216,6 @@ static void guc_move_to_next_buf(struct intel_guc_log *log) */ smp_wmb(); - if (!guc_log_has_relay(log)) - return; - /* All data has been written, so now move the offset of sub buffer. */ relay_reserve(log->runtime.relay_chan, log->vma->obj->base.size); @@ -243,9 +225,6 @@ static void guc_move_to_next_buf(struct intel_guc_log *log) static void *guc_get_write_buffer(struct intel_guc_log *log) { - if (!guc_log_has_relay(log)) - return NULL; - /* * 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 @@ -306,14 +285,14 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log) void *src_data, *dst_data; bool new_overflow; + mutex_lock(&log->runtime.lock); + if (WARN_ON(!log->runtime.buf_addr)) - return; + goto out_unlock; /* Get the pointer to shared GuC log buffer */ log_buf_state = src_data = log->runtime.buf_addr; - mutex_lock(&log->runtime.relay_lock); - /* Get the pointer to local buffer to store the logs */ log_buf_snapshot_state = dst_data = guc_get_write_buffer(log); @@ -324,9 +303,8 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log) */ DRM_ERROR_RATELIMITED("no sub-buffer to capture logs\n"); log->capture_miss_count++; - mutex_unlock(&log->runtime.relay_lock); - return; + goto out_unlock; } /* Actual logs are present from the 2nd page */ @@ -397,7 +375,8 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log) guc_move_to_next_buf(log); - mutex_unlock(&log->runtime.relay_lock); +out_unlock: + mutex_unlock(&log->runtime.lock); } static void capture_logs_work(struct work_struct *work) @@ -413,21 +392,21 @@ static bool guc_log_has_runtime(struct intel_guc_log *log) return log->runtime.buf_addr; } -static int guc_log_runtime_create(struct intel_guc_log *log) +static int guc_log_map(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); struct drm_i915_private *dev_priv = guc_to_i915(guc); void *vaddr; int ret; - lockdep_assert_held(&dev_priv->drm.struct_mutex); + lockdep_assert_held(&log->runtime.lock); if (!log->vma) return -ENODEV; - GEM_BUG_ON(guc_log_has_runtime(log)); - + mutex_lock(&dev_priv->drm.struct_mutex); ret = i915_gem_object_set_to_wc_domain(log->vma->obj, true); + mutex_unlock(&dev_priv->drm.struct_mutex); if (ret) return ret; @@ -447,14 +426,9 @@ static int guc_log_runtime_create(struct intel_guc_log *log) return 0; } -static void guc_log_runtime_destroy(struct intel_guc_log *log) +static void guc_log_unmap(struct intel_guc_log *log) { - /* - * It's possible that the runtime stuff was never allocated because - * GuC log was disabled at the boot time. - */ - if (!guc_log_has_runtime(log)) - return; + lockdep_assert_held(&log->runtime.lock); i915_gem_object_unpin_map(log->vma->obj); log->runtime.buf_addr = NULL; @@ -462,7 +436,7 @@ static void guc_log_runtime_destroy(struct intel_guc_log *log) void intel_guc_log_init_early(struct intel_guc_log *log) { - mutex_init(&log->runtime.relay_lock); + mutex_init(&log->runtime.lock); INIT_WORK(&log->runtime.flush_work, capture_logs_work); } @@ -474,12 +448,7 @@ static int guc_log_relay_create(struct intel_guc_log *log) size_t n_subbufs, subbuf_size; int ret; - if (!i915_modparams.guc_log_level) - return 0; - - mutex_lock(&log->runtime.relay_lock); - - GEM_BUG_ON(guc_log_has_relay(log)); + lockdep_assert_held(&log->runtime.lock); /* Keep the size of sub buffers same as shared log buffer */ subbuf_size = GUC_LOG_SIZE; @@ -509,12 +478,9 @@ static int guc_log_relay_create(struct intel_guc_log *log) GEM_BUG_ON(guc_log_relay_chan->subbuf_size < subbuf_size); log->runtime.relay_chan = guc_log_relay_chan; - mutex_unlock(&log->runtime.relay_lock); - return 0; err: - mutex_unlock(&log->runtime.relay_lock); /* logging will be off */ i915_modparams.guc_log_level = 0; return ret; @@ -522,20 +488,10 @@ err: static void guc_log_relay_destroy(struct intel_guc_log *log) { - mutex_lock(&log->runtime.relay_lock); - - /* - * It's possible that the relay was never allocated because - * GuC log was disabled at the boot time. - */ - if (!guc_log_has_relay(log)) - goto out_unlock; + lockdep_assert_held(&log->runtime.lock); relay_close(log->runtime.relay_chan); log->runtime.relay_chan = NULL; - -out_unlock: - mutex_unlock(&log->runtime.relay_lock); } static void guc_log_capture_logs(struct intel_guc_log *log) @@ -621,7 +577,6 @@ err: void intel_guc_log_destroy(struct intel_guc_log *log) { - guc_log_runtime_destroy(log); i915_vma_unpin_and_release(&log->vma); } @@ -699,52 +654,43 @@ out: int intel_guc_log_register(struct intel_guc_log *log) { - struct intel_guc *guc = log_to_guc(log); - struct drm_i915_private *i915 = guc_to_i915(guc); int ret; + mutex_lock(&log->runtime.lock); + GEM_BUG_ON(guc_log_has_runtime(log)); - /* - * 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_relay_create(log); if (ret) goto err; - mutex_lock(&i915->drm.struct_mutex); - ret = guc_log_runtime_create(log); - mutex_unlock(&i915->drm.struct_mutex); - + ret = guc_log_map(log); if (ret) goto err_relay; ret = guc_log_relay_file_create(log); if (ret) - goto err_runtime; + goto err_unmap; - guc_flush_log_msg_enable(guc); + guc_flush_log_msg_enable(log_to_guc(log)); + + mutex_unlock(&log->runtime.lock); return 0; -err_runtime: - mutex_lock(&i915->drm.struct_mutex); - guc_log_runtime_destroy(log); - mutex_unlock(&i915->drm.struct_mutex); +err_unmap: + guc_log_unmap(log); err_relay: guc_log_relay_destroy(log); err: + mutex_unlock(&log->runtime.lock); + return ret; } void intel_guc_log_unregister(struct intel_guc_log *log) { - struct intel_guc *guc = log_to_guc(log); - struct drm_i915_private *i915 = guc_to_i915(guc); - - guc_flush_log_msg_disable(guc); + guc_flush_log_msg_disable(log_to_guc(log)); /* * Once logging is disabled, GuC won't generate logs & send an @@ -754,9 +700,12 @@ void intel_guc_log_unregister(struct intel_guc_log *log) */ guc_flush_logs(log); - mutex_lock(&i915->drm.struct_mutex); - guc_log_runtime_destroy(log); - mutex_unlock(&i915->drm.struct_mutex); + mutex_lock(&log->runtime.lock); + + GEM_BUG_ON(!guc_log_has_runtime(log)); + guc_log_unmap(log); guc_log_relay_destroy(log); + + mutex_unlock(&log->runtime.lock); } diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index 6264bd5ba080..e0ea625032fb 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -49,8 +49,7 @@ 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; + struct mutex lock; } runtime; /* logging related stats */ u32 capture_miss_count; -- cgit v1.2.3 From 2b47733045aaf883c275c3bdbe3b503137144f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 19 Mar 2018 10:53:38 +0100 Subject: drm/i915/guc: Merge log relay file and channel creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have all the information we need at relay_open call time. Since there's no reason to split the process into relay_open and relay_late_setup_files, let's remove the extra code. v2: Remove obsoleted comments (Sagar) v3: There was one obsolete comment left (Sagar) Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Michal Wajdeczko Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180319095348.9716-3-michal.winiarski@intel.com --- drivers/gpu/drm/i915/intel_guc_log.c | 65 +++--------------------------------- 1 file changed, 5 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index b82866bfbef5..767c0d00fca6 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -141,14 +141,7 @@ 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 - * 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 - * name need not be same as the filename passed as an argument. - */ - buf_file = debugfs_create_file("guc_log", mode, + buf_file = debugfs_create_file(filename, mode, parent, buf, &relay_file_operations); return buf_file; } @@ -169,45 +162,6 @@ static struct rchan_callbacks relay_callbacks = { .remove_buf_file = remove_buf_file_callback, }; -static int guc_log_relay_file_create(struct intel_guc_log *log) -{ - struct intel_guc *guc = log_to_guc(log); - struct drm_i915_private *dev_priv = guc_to_i915(guc); - struct dentry *log_dir; - int ret; - - lockdep_assert_held(&log->runtime.lock); - - /* 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 - * 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 - * straightforward/clean manner :- - * i) Need the associated dentry pointer of the file, while opening the - * relay channel. - * ii) Should be able to use 'relay_file_operations' fops for the file. - * iii) Set the 'i_private' field of file's inode to the pointer of - * relay channel buffer. - */ - if (!log_dir) { - DRM_ERROR("Debugfs dir not available yet for GuC log file\n"); - return -ENODEV; - } - - ret = relay_late_setup_files(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; - } - - return 0; -} - static void guc_move_to_next_buf(struct intel_guc_log *log) { /* @@ -461,13 +415,10 @@ static int guc_log_relay_create(struct intel_guc_log *log) */ n_subbufs = 8; - /* - * 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. - */ - guc_log_relay_chan = relay_open(NULL, NULL, subbuf_size, - n_subbufs, &relay_callbacks, dev_priv); + guc_log_relay_chan = relay_open("guc_log", + dev_priv->drm.primary->debugfs_root, + subbuf_size, n_subbufs, + &relay_callbacks, dev_priv); if (!guc_log_relay_chan) { DRM_ERROR("Couldn't create relay chan for GuC logging\n"); @@ -668,18 +619,12 @@ int intel_guc_log_register(struct intel_guc_log *log) if (ret) goto err_relay; - ret = guc_log_relay_file_create(log); - if (ret) - goto err_unmap; - guc_flush_log_msg_enable(log_to_guc(log)); mutex_unlock(&log->runtime.lock); return 0; -err_unmap: - guc_log_unmap(log); err_relay: guc_log_relay_destroy(log); err: -- cgit v1.2.3 From d3fbf9437b22bd663e292d5d5e9f8e37c8eed208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 19 Mar 2018 10:53:39 +0100 Subject: drm/i915/guc: Flush directly in log unregister MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having both guc_flush_logs and guc_log_flush functions is confusing. While we could just rename things, guc_flush_logs implementation is quite simple. Let's get rid of it and move its content to unregister. v2: s/dev_priv/i915 (Sagar) Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Michal Wajdeczko Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180319095348.9716-4-michal.winiarski@intel.com --- drivers/gpu/drm/i915/intel_guc_log.c | 38 +++++++++++++++--------------------- 1 file changed, 16 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 767c0d00fca6..72a71bc94adf 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -461,26 +461,6 @@ static void guc_log_capture_logs(struct intel_guc_log *log) intel_runtime_pm_put(dev_priv); } -static void guc_flush_logs(struct intel_guc_log *log) -{ - struct intel_guc *guc = log_to_guc(log); - struct drm_i915_private *dev_priv = guc_to_i915(guc); - - /* - * Before initiating the forceful flush, wait for any pending/ongoing - * flush to complete otherwise forceful flush may not actually happen. - */ - flush_work(&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(log); -} - int intel_guc_log_create(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); @@ -635,7 +615,16 @@ err: void intel_guc_log_unregister(struct intel_guc_log *log) { - guc_flush_log_msg_disable(log_to_guc(log)); + struct intel_guc *guc = log_to_guc(log); + struct drm_i915_private *i915 = guc_to_i915(guc); + + guc_flush_log_msg_disable(guc); + + /* + * Before initiating the forceful flush, wait for any pending/ongoing + * flush to complete otherwise forceful flush may not actually happen. + */ + flush_work(&log->runtime.flush_work); /* * Once logging is disabled, GuC won't generate logs & send an @@ -643,7 +632,12 @@ void intel_guc_log_unregister(struct intel_guc_log *log) * which is yet to be captured. So request GuC to update the log * buffer state and then collect the left over logs. */ - guc_flush_logs(log); + intel_runtime_pm_get(i915); + guc_log_flush(guc); + intel_runtime_pm_put(i915); + + /* GuC would have updated log buffer by now, so capture it */ + guc_log_capture_logs(log); mutex_lock(&log->runtime.lock); -- cgit v1.2.3 From 4977a287b9e7c3dbe156bf28f8771b758060ee3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 19 Mar 2018 10:53:40 +0100 Subject: drm/i915/guc: Split relay control and GuC log level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those two concepts are really separate. Since GuC is writing data into its own buffer and we even provide a way for userspace to read directly from it using i915_guc_log_dump debugfs, there's no real reason to tie log level with relay creation. Let's create a separate debugfs, giving userspace a way to create a relay on demand, when it wants to read a continuous log rather than a snapshot. v2: Don't touch guc_log_level on relay creation error, adjust locking after rebase, s/dev_priv/i915, pass guc to file->private_data (Sagar) Use struct_mutex rather than runtime.lock for set_log_level v3: Tidy ordering of definitions (Sagar) Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Michal Wajdeczko Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180319095348.9716-5-michal.winiarski@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 56 +++++++++++++++++++++++---- drivers/gpu/drm/i915/i915_drv.c | 4 -- drivers/gpu/drm/i915/intel_guc_log.c | 75 +++++++++++++++--------------------- drivers/gpu/drm/i915/intel_guc_log.h | 9 +++-- drivers/gpu/drm/i915/intel_uc.c | 22 ----------- drivers/gpu/drm/i915/intel_uc.h | 2 - 6 files changed, 84 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 5378863e3238..e857a9493b6f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2495,32 +2495,73 @@ static int i915_guc_log_dump(struct seq_file *m, void *data) return 0; } -static int i915_guc_log_control_get(void *data, u64 *val) +static int i915_guc_log_level_get(void *data, u64 *val) { struct drm_i915_private *dev_priv = data; if (!USES_GUC(dev_priv)) return -ENODEV; - *val = intel_guc_log_control_get(&dev_priv->guc.log); + *val = intel_guc_log_level_get(&dev_priv->guc.log); return 0; } -static int i915_guc_log_control_set(void *data, u64 val) +static int i915_guc_log_level_set(void *data, u64 val) { struct drm_i915_private *dev_priv = data; if (!USES_GUC(dev_priv)) return -ENODEV; - return intel_guc_log_control_set(&dev_priv->guc.log, val); + return intel_guc_log_level_set(&dev_priv->guc.log, val); } -DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops, - i915_guc_log_control_get, i915_guc_log_control_set, +DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_level_fops, + i915_guc_log_level_get, i915_guc_log_level_set, "%lld\n"); +static int i915_guc_log_relay_open(struct inode *inode, struct file *file) +{ + struct drm_i915_private *dev_priv = inode->i_private; + + if (!USES_GUC(dev_priv)) + return -ENODEV; + + file->private_data = &dev_priv->guc.log; + + return intel_guc_log_relay_open(&dev_priv->guc.log); +} + +static ssize_t +i915_guc_log_relay_write(struct file *filp, + const char __user *ubuf, + size_t cnt, + loff_t *ppos) +{ + struct intel_guc_log *log = filp->private_data; + + intel_guc_log_relay_flush(log); + + return cnt; +} + +static int i915_guc_log_relay_release(struct inode *inode, struct file *file) +{ + struct drm_i915_private *dev_priv = inode->i_private; + + intel_guc_log_relay_close(&dev_priv->guc.log); + + return 0; +} + +static const struct file_operations i915_guc_log_relay_fops = { + .owner = THIS_MODULE, + .open = i915_guc_log_relay_open, + .write = i915_guc_log_relay_write, + .release = i915_guc_log_relay_release, +}; + static const char *psr2_live_status(u32 val) { static const char * const live_status[] = { @@ -4748,7 +4789,8 @@ static const struct i915_debugfs_files { {"i915_dp_test_data", &i915_displayport_test_data_fops}, {"i915_dp_test_type", &i915_displayport_test_type_fops}, {"i915_dp_test_active", &i915_displayport_test_active_fops}, - {"i915_guc_log_control", &i915_guc_log_control_fops}, + {"i915_guc_log_level", &i915_guc_log_level_fops}, + {"i915_guc_log_relay", &i915_guc_log_relay_fops}, {"i915_hpd_storm_ctl", &i915_hpd_storm_ctl_fops}, {"i915_ipc_status", &i915_ipc_status_fops}, {"i915_drrs_ctl", &i915_drrs_ctl_fops} diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 3df5193487f3..1021bf40e236 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1239,9 +1239,6 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) i915_debugfs_register(dev_priv); i915_setup_sysfs(dev_priv); - /* Depends on debugfs having been initialized */ - intel_uc_register(dev_priv); - /* Depends on sysfs having been initialized */ i915_perf_register(dev_priv); } else @@ -1299,7 +1296,6 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) i915_pmu_unregister(dev_priv); i915_teardown_sysfs(dev_priv); - intel_uc_unregister(dev_priv); drm_dev_unregister(&dev_priv->drm); i915_gem_shrinker_unregister(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 72a71bc94adf..20254dde172c 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -423,18 +423,13 @@ static int guc_log_relay_create(struct intel_guc_log *log) DRM_ERROR("Couldn't create relay chan for GuC logging\n"); ret = -ENOMEM; - goto err; + return ret; } GEM_BUG_ON(guc_log_relay_chan->subbuf_size < subbuf_size); log->runtime.relay_chan = guc_log_relay_chan; return 0; - -err: - /* logging will be off */ - i915_modparams.guc_log_level = 0; - return ret; } static void guc_log_relay_destroy(struct intel_guc_log *log) @@ -511,7 +506,7 @@ void intel_guc_log_destroy(struct intel_guc_log *log) i915_vma_unpin_and_release(&log->vma); } -int intel_guc_log_control_get(struct intel_guc_log *log) +int intel_guc_log_level_get(struct intel_guc_log *log) { GEM_BUG_ON(!log->vma); GEM_BUG_ON(i915_modparams.guc_log_level < 0); @@ -526,11 +521,10 @@ int intel_guc_log_control_get(struct intel_guc_log *log) LOG_LEVEL_TO_ENABLED(_x) ? _x - 1 : 0; \ }) #define VERBOSITY_TO_LOG_LEVEL(x) ((x) + 1) -int intel_guc_log_control_set(struct intel_guc_log *log, u64 val) +int intel_guc_log_level_set(struct intel_guc_log *log, u64 val) { struct intel_guc *guc = log_to_guc(log); struct drm_i915_private *dev_priv = guc_to_i915(guc); - bool enabled = LOG_LEVEL_TO_ENABLED(val); int ret; BUILD_BUG_ON(GUC_LOG_VERBOSITY_MIN != 0); @@ -553,7 +547,8 @@ int intel_guc_log_control_set(struct intel_guc_log *log, u64 val) } intel_runtime_pm_get(dev_priv); - ret = guc_log_control(guc, enabled, LOG_LEVEL_TO_VERBOSITY(val)); + ret = guc_log_control(guc, LOG_LEVEL_TO_ENABLED(val), + LOG_LEVEL_TO_VERBOSITY(val)); intel_runtime_pm_put(dev_priv); if (ret) { DRM_DEBUG_DRIVER("guc_log_control action failed %d\n", ret); @@ -562,89 +557,79 @@ int intel_guc_log_control_set(struct intel_guc_log *log, u64 val) i915_modparams.guc_log_level = val; - mutex_unlock(&dev_priv->drm.struct_mutex); - - if (enabled && !guc_log_has_runtime(log)) { - ret = intel_guc_log_register(log); - if (ret) { - /* logging will remain off */ - i915_modparams.guc_log_level = 0; - goto out; - } - } else if (!enabled && guc_log_has_runtime(log)) { - intel_guc_log_unregister(log); - } - - return 0; - out_unlock: mutex_unlock(&dev_priv->drm.struct_mutex); -out: + return ret; } -int intel_guc_log_register(struct intel_guc_log *log) +int intel_guc_log_relay_open(struct intel_guc_log *log) { int ret; mutex_lock(&log->runtime.lock); - GEM_BUG_ON(guc_log_has_runtime(log)); + if (guc_log_has_runtime(log)) { + ret = -EEXIST; + goto out_unlock; + } ret = guc_log_relay_create(log); if (ret) - goto err; + goto out_unlock; ret = guc_log_map(log); if (ret) - goto err_relay; + goto out_relay; + + mutex_unlock(&log->runtime.lock); guc_flush_log_msg_enable(log_to_guc(log)); - mutex_unlock(&log->runtime.lock); + /* + * When GuC is logging without us relaying to userspace, we're ignoring + * the flush notification. This means that we need to unconditionally + * flush on relay enabling, since GuC only notifies us once. + */ + queue_work(log->runtime.flush_wq, &log->runtime.flush_work); return 0; -err_relay: +out_relay: guc_log_relay_destroy(log); -err: +out_unlock: mutex_unlock(&log->runtime.lock); return ret; } -void intel_guc_log_unregister(struct intel_guc_log *log) +void intel_guc_log_relay_flush(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); struct drm_i915_private *i915 = guc_to_i915(guc); - guc_flush_log_msg_disable(guc); - /* * Before initiating the forceful flush, wait for any pending/ongoing * flush to complete otherwise forceful flush may not actually happen. */ flush_work(&log->runtime.flush_work); - /* - * 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. - */ intel_runtime_pm_get(i915); guc_log_flush(guc); intel_runtime_pm_put(i915); /* GuC would have updated log buffer by now, so capture it */ guc_log_capture_logs(log); +} - mutex_lock(&log->runtime.lock); +void intel_guc_log_relay_close(struct intel_guc_log *log) +{ + guc_flush_log_msg_disable(log_to_guc(log)); + flush_work(&log->runtime.flush_work); + mutex_lock(&log->runtime.lock); GEM_BUG_ON(!guc_log_has_runtime(log)); - guc_log_unmap(log); guc_log_relay_destroy(log); - mutex_unlock(&log->runtime.lock); } diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index e0ea625032fb..3cf911eef3a8 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -61,11 +61,12 @@ struct intel_guc_log { void intel_guc_log_init_early(struct intel_guc_log *log); int intel_guc_log_create(struct intel_guc_log *log); -int intel_guc_log_register(struct intel_guc_log *log); -void intel_guc_log_unregister(struct intel_guc_log *log); void intel_guc_log_destroy(struct intel_guc_log *log); -int intel_guc_log_control_get(struct intel_guc_log *log); -int intel_guc_log_control_set(struct intel_guc_log *log, u64 control); +int intel_guc_log_level_get(struct intel_guc_log *log); +int intel_guc_log_level_set(struct intel_guc_log *log, u64 control_val); +int intel_guc_log_relay_open(struct intel_guc_log *log); +void intel_guc_log_relay_flush(struct intel_guc_log *log); +void intel_guc_log_relay_close(struct intel_guc_log *log); #endif diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 765b86a53f19..9bb40cd047a0 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -221,28 +221,6 @@ static void guc_free_load_err_log(struct intel_guc *guc) i915_gem_object_put(guc->load_err_log); } -int intel_uc_register(struct drm_i915_private *i915) -{ - int ret = 0; - - if (!USES_GUC(i915)) - return 0; - - if (i915_modparams.guc_log_level) - ret = intel_guc_log_register(&i915->guc.log); - - return ret; -} - -void intel_uc_unregister(struct drm_i915_private *i915) -{ - if (!USES_GUC(i915)) - return; - - if (i915_modparams.guc_log_level) - intel_guc_log_unregister(&i915->guc.log); -} - static int guc_enable_communication(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); diff --git a/drivers/gpu/drm/i915/intel_uc.h b/drivers/gpu/drm/i915/intel_uc.h index 0a2b413e9cd0..937e61175258 100644 --- a/drivers/gpu/drm/i915/intel_uc.h +++ b/drivers/gpu/drm/i915/intel_uc.h @@ -30,8 +30,6 @@ void intel_uc_init_early(struct drm_i915_private *dev_priv); void intel_uc_init_mmio(struct drm_i915_private *dev_priv); -int intel_uc_register(struct drm_i915_private *dev_priv); -void intel_uc_unregister(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_misc(struct drm_i915_private *dev_priv); -- cgit v1.2.3 From b8299c71d4e15972ba507a9b8cdba5653cd247d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 19 Mar 2018 10:53:41 +0100 Subject: drm/i915/guc: Move check for fast memcpy_wc to relay creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only need those fast memcpy_wc when we're using relay to read continuous GuC log. Let's prevent the user from creating a relay if we know we won't be able to keep up with GuC. v2: Adjust the return value (Michał) Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Michal Wajdeczko Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180319095348.9716-6-michal.winiarski@intel.com --- drivers/gpu/drm/i915/intel_guc_log.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 20254dde172c..db89999a84e8 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -466,16 +466,6 @@ int intel_guc_log_create(struct intel_guc_log *log) GEM_BUG_ON(log->vma); - /* - * 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. - */ - if (WARN_ON(!i915_has_memcpy_from_wc())) { - ret = -EINVAL; - goto err; - } - vma = intel_guc_allocate_vma(guc, GUC_LOG_SIZE); if (IS_ERR(vma)) { ret = PTR_ERR(vma); @@ -574,6 +564,16 @@ int intel_guc_log_relay_open(struct intel_guc_log *log) goto out_unlock; } + /* + * 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. + */ + if (!i915_has_memcpy_from_wc()) { + ret = -ENXIO; + goto out_unlock; + } + ret = guc_log_relay_create(log); if (ret) goto out_unlock; -- cgit v1.2.3 From 6a96be2448a446efb1ac67974535fd4b33df3d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 19 Mar 2018 10:53:42 +0100 Subject: drm/i915/guc: Get rid of GuC log runtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runtime is not a very good name. Let's also move counting relay overflows inside relay struct. v2: Rename things rather than remove the struct (Chris) Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Michal Wajdeczko Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180319095348.9716-7-michal.winiarski@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 4 +-- drivers/gpu/drm/i915/intel_guc.c | 15 +++++---- drivers/gpu/drm/i915/intel_guc_log.c | 64 ++++++++++++++++++------------------ drivers/gpu/drm/i915/intel_guc_log.h | 7 ++-- 4 files changed, 45 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e857a9493b6f..d3d4d1b29112 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2347,8 +2347,8 @@ static void i915_guc_log_info(struct seq_file *m, seq_printf(m, "\tTotal flush interrupt count: %u\n", guc->log.flush_interrupt_count); - seq_printf(m, "\tCapture miss count: %u\n", - guc->log.capture_miss_count); + seq_printf(m, "\tRelay full count: %u\n", + guc->log.relay.full_count); } static void i915_guc_client_info(struct seq_file *m, diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 3af603536b1b..70d118bb0a1a 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -87,9 +87,10 @@ int intel_guc_init_wq(struct intel_guc *guc) * or scheduled later on resume. This way the handling of work * item can be kept same between system suspend & rpm suspend. */ - guc->log.runtime.flush_wq = alloc_ordered_workqueue("i915-guc_log", - WQ_HIGHPRI | WQ_FREEZABLE); - if (!guc->log.runtime.flush_wq) { + guc->log.relay.flush_wq = + alloc_ordered_workqueue("i915-guc_log", + WQ_HIGHPRI | WQ_FREEZABLE); + if (!guc->log.relay.flush_wq) { DRM_ERROR("Couldn't allocate workqueue for GuC log\n"); return -ENOMEM; } @@ -112,7 +113,7 @@ int intel_guc_init_wq(struct intel_guc *guc) guc->preempt_wq = alloc_ordered_workqueue("i915-guc_preempt", WQ_HIGHPRI); if (!guc->preempt_wq) { - destroy_workqueue(guc->log.runtime.flush_wq); + destroy_workqueue(guc->log.relay.flush_wq); DRM_ERROR("Couldn't allocate workqueue for GuC " "preemption\n"); return -ENOMEM; @@ -130,7 +131,7 @@ void intel_guc_fini_wq(struct intel_guc *guc) USES_GUC_SUBMISSION(dev_priv)) destroy_workqueue(guc->preempt_wq); - destroy_workqueue(guc->log.runtime.flush_wq); + destroy_workqueue(guc->log.relay.flush_wq); } static int guc_shared_data_create(struct intel_guc *guc) @@ -390,8 +391,8 @@ void intel_guc_to_host_event_handler(struct intel_guc *guc) if (msg & (INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER | INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED)) { - queue_work(guc->log.runtime.flush_wq, - &guc->log.runtime.flush_work); + queue_work(guc->log.relay.flush_wq, + &guc->log.relay.flush_work); guc->log.flush_interrupt_count++; } diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index db89999a84e8..c220c2893d2c 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -171,10 +171,10 @@ static void guc_move_to_next_buf(struct intel_guc_log *log) smp_wmb(); /* All data has been written, so now move the offset of sub buffer. */ - relay_reserve(log->runtime.relay_chan, log->vma->obj->base.size); + relay_reserve(log->relay.channel, log->vma->obj->base.size); /* Switch to the next sub buffer */ - relay_flush(log->runtime.relay_chan); + relay_flush(log->relay.channel); } static void *guc_get_write_buffer(struct intel_guc_log *log) @@ -188,7 +188,7 @@ static void *guc_get_write_buffer(struct intel_guc_log *log) * done without using relay_reserve() along with relay_write(). So its * better to use relay_reserve() alone. */ - return relay_reserve(log->runtime.relay_chan, 0); + return relay_reserve(log->relay.channel, 0); } static bool guc_check_log_buf_overflow(struct intel_guc_log *log, @@ -239,13 +239,13 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log) void *src_data, *dst_data; bool new_overflow; - mutex_lock(&log->runtime.lock); + mutex_lock(&log->relay.lock); - if (WARN_ON(!log->runtime.buf_addr)) + if (WARN_ON(!log->relay.buf_addr)) goto out_unlock; /* Get the pointer to shared GuC log buffer */ - log_buf_state = src_data = log->runtime.buf_addr; + log_buf_state = src_data = log->relay.buf_addr; /* Get the pointer to local buffer to store the logs */ log_buf_snapshot_state = dst_data = guc_get_write_buffer(log); @@ -256,7 +256,7 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log) * getting consumed by User at a slow rate. */ DRM_ERROR_RATELIMITED("no sub-buffer to capture logs\n"); - log->capture_miss_count++; + log->relay.full_count++; goto out_unlock; } @@ -330,20 +330,20 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log) guc_move_to_next_buf(log); out_unlock: - mutex_unlock(&log->runtime.lock); + mutex_unlock(&log->relay.lock); } static void capture_logs_work(struct work_struct *work) { struct intel_guc_log *log = - container_of(work, struct intel_guc_log, runtime.flush_work); + container_of(work, struct intel_guc_log, relay.flush_work); guc_log_capture_logs(log); } -static bool guc_log_has_runtime(struct intel_guc_log *log) +static bool guc_log_relay_enabled(struct intel_guc_log *log) { - return log->runtime.buf_addr; + return log->relay.buf_addr; } static int guc_log_map(struct intel_guc_log *log) @@ -353,7 +353,7 @@ static int guc_log_map(struct intel_guc_log *log) void *vaddr; int ret; - lockdep_assert_held(&log->runtime.lock); + lockdep_assert_held(&log->relay.lock); if (!log->vma) return -ENODEV; @@ -375,23 +375,23 @@ static int guc_log_map(struct intel_guc_log *log) return PTR_ERR(vaddr); } - log->runtime.buf_addr = vaddr; + log->relay.buf_addr = vaddr; return 0; } static void guc_log_unmap(struct intel_guc_log *log) { - lockdep_assert_held(&log->runtime.lock); + lockdep_assert_held(&log->relay.lock); i915_gem_object_unpin_map(log->vma->obj); - log->runtime.buf_addr = NULL; + log->relay.buf_addr = NULL; } void intel_guc_log_init_early(struct intel_guc_log *log) { - mutex_init(&log->runtime.lock); - INIT_WORK(&log->runtime.flush_work, capture_logs_work); + mutex_init(&log->relay.lock); + INIT_WORK(&log->relay.flush_work, capture_logs_work); } static int guc_log_relay_create(struct intel_guc_log *log) @@ -402,7 +402,7 @@ static int guc_log_relay_create(struct intel_guc_log *log) size_t n_subbufs, subbuf_size; int ret; - lockdep_assert_held(&log->runtime.lock); + lockdep_assert_held(&log->relay.lock); /* Keep the size of sub buffers same as shared log buffer */ subbuf_size = GUC_LOG_SIZE; @@ -427,17 +427,17 @@ static int guc_log_relay_create(struct intel_guc_log *log) } GEM_BUG_ON(guc_log_relay_chan->subbuf_size < subbuf_size); - log->runtime.relay_chan = guc_log_relay_chan; + log->relay.channel = guc_log_relay_chan; return 0; } static void guc_log_relay_destroy(struct intel_guc_log *log) { - lockdep_assert_held(&log->runtime.lock); + lockdep_assert_held(&log->relay.lock); - relay_close(log->runtime.relay_chan); - log->runtime.relay_chan = NULL; + relay_close(log->relay.channel); + log->relay.channel = NULL; } static void guc_log_capture_logs(struct intel_guc_log *log) @@ -557,9 +557,9 @@ int intel_guc_log_relay_open(struct intel_guc_log *log) { int ret; - mutex_lock(&log->runtime.lock); + mutex_lock(&log->relay.lock); - if (guc_log_has_runtime(log)) { + if (guc_log_relay_enabled(log)) { ret = -EEXIST; goto out_unlock; } @@ -582,7 +582,7 @@ int intel_guc_log_relay_open(struct intel_guc_log *log) if (ret) goto out_relay; - mutex_unlock(&log->runtime.lock); + mutex_unlock(&log->relay.lock); guc_flush_log_msg_enable(log_to_guc(log)); @@ -591,14 +591,14 @@ int intel_guc_log_relay_open(struct intel_guc_log *log) * the flush notification. This means that we need to unconditionally * flush on relay enabling, since GuC only notifies us once. */ - queue_work(log->runtime.flush_wq, &log->runtime.flush_work); + queue_work(log->relay.flush_wq, &log->relay.flush_work); return 0; out_relay: guc_log_relay_destroy(log); out_unlock: - mutex_unlock(&log->runtime.lock); + mutex_unlock(&log->relay.lock); return ret; } @@ -612,7 +612,7 @@ void intel_guc_log_relay_flush(struct intel_guc_log *log) * Before initiating the forceful flush, wait for any pending/ongoing * flush to complete otherwise forceful flush may not actually happen. */ - flush_work(&log->runtime.flush_work); + flush_work(&log->relay.flush_work); intel_runtime_pm_get(i915); guc_log_flush(guc); @@ -625,11 +625,11 @@ void intel_guc_log_relay_flush(struct intel_guc_log *log) void intel_guc_log_relay_close(struct intel_guc_log *log) { guc_flush_log_msg_disable(log_to_guc(log)); - flush_work(&log->runtime.flush_work); + flush_work(&log->relay.flush_work); - mutex_lock(&log->runtime.lock); - GEM_BUG_ON(!guc_log_has_runtime(log)); + mutex_lock(&log->relay.lock); + GEM_BUG_ON(!guc_log_relay_enabled(log)); guc_log_unmap(log); guc_log_relay_destroy(log); - mutex_unlock(&log->runtime.lock); + mutex_unlock(&log->relay.lock); } diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index 3cf911eef3a8..db35e548d2ed 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -43,16 +43,15 @@ struct intel_guc; struct intel_guc_log { u32 flags; struct i915_vma *vma; - /* The runtime stuff gets created only when GuC logging gets enabled */ struct { void *buf_addr; struct workqueue_struct *flush_wq; struct work_struct flush_work; - struct rchan *relay_chan; + struct rchan *channel; struct mutex lock; - } runtime; + u32 full_count; + } relay; /* logging related stats */ - u32 capture_miss_count; u32 flush_interrupt_count; u32 prev_overflow_count[GUC_MAX_LOG_BUFFER]; u32 total_overflow_count[GUC_MAX_LOG_BUFFER]; -- cgit v1.2.3 From db5579934f2fc8d916fe29355ac0c716acf1d921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 19 Mar 2018 10:53:43 +0100 Subject: drm/i915/guc: Always print log stats in i915_guc_info when using GuC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While some of the content in this file is related to GuC submission only, that's not the case with log related statistics. Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Michal Wajdeczko Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180319095348.9716-8-michal.winiarski@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d3d4d1b29112..5584736a4293 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2330,7 +2330,7 @@ static void i915_guc_log_info(struct seq_file *m, { struct intel_guc *guc = &dev_priv->guc; - seq_puts(m, "\nGuC logging stats:\n"); + seq_puts(m, "GuC logging stats:\n"); seq_printf(m, "\tISR: flush count %10u, overflow count %10u\n", guc->log.flush_count[GUC_ISR_LOG_BUFFER], @@ -2378,14 +2378,19 @@ static int i915_guc_info(struct seq_file *m, void *data) struct drm_i915_private *dev_priv = node_to_i915(m->private); const struct intel_guc *guc = &dev_priv->guc; - if (!USES_GUC_SUBMISSION(dev_priv)) + if (!USES_GUC(dev_priv)) return -ENODEV; + i915_guc_log_info(m, dev_priv); + + if (!USES_GUC_SUBMISSION(dev_priv)) + return 0; + GEM_BUG_ON(!guc->execbuf_client); - seq_printf(m, "Doorbell map:\n"); + seq_printf(m, "\nDoorbell map:\n"); seq_printf(m, "\t%*pb\n", GUC_NUM_DOORBELLS, guc->doorbell_bitmap); - seq_printf(m, "Doorbell next cacheline: 0x%x\n\n", guc->db_cacheline); + seq_printf(m, "Doorbell next cacheline: 0x%x\n", guc->db_cacheline); seq_printf(m, "\nGuC execbuf client @ %p:\n", guc->execbuf_client); i915_guc_client_info(m, dev_priv, guc->execbuf_client); @@ -2395,8 +2400,6 @@ static int i915_guc_info(struct seq_file *m, void *data) i915_guc_client_info(m, dev_priv, guc->preempt_client); } - i915_guc_log_info(m, dev_priv); - /* Add more as required ... */ return 0; -- cgit v1.2.3 From 5e24e4a240770008ed46d90d6571ec27b5e2bd5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 19 Mar 2018 10:53:44 +0100 Subject: drm/i915/guc: Don't print out relay statistics when relay is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If nobody has enabled the relay, we're not comunicating with GuC, which means that the stats don't have any meaning. Let's also remove interrupt counter and tidy the debugfs formatting. v2: Correct stats accounting (Sagar) v3: Corrected one more error in stats accounting, move relay_enabled (Sagar) Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Michal Wajdeczko Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180319095348.9716-9-michal.winiarski@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 49 +++++++++++++++++++++++------------- drivers/gpu/drm/i915/intel_guc.c | 5 +--- drivers/gpu/drm/i915/intel_guc_log.c | 26 +++++++++---------- drivers/gpu/drm/i915/intel_guc_log.h | 10 +++++--- 4 files changed, 52 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 5584736a4293..964ea1a12357 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2325,30 +2325,45 @@ static int i915_guc_load_status_info(struct seq_file *m, void *data) return 0; } -static void i915_guc_log_info(struct seq_file *m, - struct drm_i915_private *dev_priv) +static const char * +stringify_guc_log_type(enum guc_log_buffer_type type) { - struct intel_guc *guc = &dev_priv->guc; - - seq_puts(m, "GuC logging stats:\n"); + switch (type) { + case GUC_ISR_LOG_BUFFER: + return "ISR"; + case GUC_DPC_LOG_BUFFER: + return "DPC"; + case GUC_CRASH_DUMP_LOG_BUFFER: + return "CRASH"; + default: + MISSING_CASE(type); + } - seq_printf(m, "\tISR: flush count %10u, overflow count %10u\n", - guc->log.flush_count[GUC_ISR_LOG_BUFFER], - guc->log.total_overflow_count[GUC_ISR_LOG_BUFFER]); + return ""; +} - seq_printf(m, "\tDPC: flush count %10u, overflow count %10u\n", - guc->log.flush_count[GUC_DPC_LOG_BUFFER], - guc->log.total_overflow_count[GUC_DPC_LOG_BUFFER]); +static void i915_guc_log_info(struct seq_file *m, + struct drm_i915_private *dev_priv) +{ + struct intel_guc_log *log = &dev_priv->guc.log; + enum guc_log_buffer_type type; - seq_printf(m, "\tCRASH: flush count %10u, overflow count %10u\n", - guc->log.flush_count[GUC_CRASH_DUMP_LOG_BUFFER], - guc->log.total_overflow_count[GUC_CRASH_DUMP_LOG_BUFFER]); + if (!intel_guc_log_relay_enabled(log)) { + seq_puts(m, "GuC log relay disabled\n"); + return; + } - seq_printf(m, "\tTotal flush interrupt count: %u\n", - guc->log.flush_interrupt_count); + seq_puts(m, "GuC logging stats:\n"); seq_printf(m, "\tRelay full count: %u\n", - guc->log.relay.full_count); + log->relay.full_count); + + for (type = GUC_ISR_LOG_BUFFER; type < GUC_MAX_LOG_BUFFER; type++) { + seq_printf(m, "\t%s:\tflush count %10u, overflow count %10u\n", + stringify_guc_log_type(type), + log->stats[type].flush, + log->stats[type].sampled_overflow); + } } static void i915_guc_client_info(struct seq_file *m, diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 70d118bb0a1a..eeda1aa2afe6 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -390,12 +390,9 @@ void intel_guc_to_host_event_handler(struct intel_guc *guc) spin_unlock(&guc->irq_lock); if (msg & (INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER | - INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED)) { + INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED)) queue_work(guc->log.relay.flush_wq, &guc->log.relay.flush_work); - - guc->log.flush_interrupt_count++; - } } int intel_guc_sample_forcewake(struct intel_guc *guc) diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index c220c2893d2c..3180645b9642 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -195,18 +195,18 @@ static bool guc_check_log_buf_overflow(struct intel_guc_log *log, enum guc_log_buffer_type type, unsigned int full_cnt) { - unsigned int prev_full_cnt = log->prev_overflow_count[type]; + unsigned int prev_full_cnt = log->stats[type].sampled_overflow; bool overflow = false; if (full_cnt != prev_full_cnt) { overflow = true; - log->prev_overflow_count[type] = full_cnt; - log->total_overflow_count[type] += full_cnt - prev_full_cnt; + log->stats[type].overflow = full_cnt; + log->stats[type].sampled_overflow += full_cnt - prev_full_cnt; if (full_cnt < prev_full_cnt) { /* buffer_full_cnt is a 4 bit counter */ - log->total_overflow_count[type] += 16; + log->stats[type].sampled_overflow += 16; } DRM_ERROR_RATELIMITED("GuC log buffer overflow\n"); } @@ -241,7 +241,7 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log) mutex_lock(&log->relay.lock); - if (WARN_ON(!log->relay.buf_addr)) + if (WARN_ON(!intel_guc_log_relay_enabled(log))) goto out_unlock; /* Get the pointer to shared GuC log buffer */ @@ -279,7 +279,7 @@ static void guc_read_update_log_buffer(struct intel_guc_log *log) full_cnt = log_buf_state_local.buffer_full_cnt; /* Bookkeeping stuff */ - log->flush_count[type] += log_buf_state_local.flush_to_file; + log->stats[type].flush += log_buf_state_local.flush_to_file; new_overflow = guc_check_log_buf_overflow(log, type, full_cnt); /* Update the state of shared log buffer */ @@ -341,11 +341,6 @@ static void capture_logs_work(struct work_struct *work) guc_log_capture_logs(log); } -static bool guc_log_relay_enabled(struct intel_guc_log *log) -{ - return log->relay.buf_addr; -} - static int guc_log_map(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); @@ -553,13 +548,18 @@ out_unlock: return ret; } +bool intel_guc_log_relay_enabled(const struct intel_guc_log *log) +{ + return log->relay.buf_addr; +} + int intel_guc_log_relay_open(struct intel_guc_log *log) { int ret; mutex_lock(&log->relay.lock); - if (guc_log_relay_enabled(log)) { + if (intel_guc_log_relay_enabled(log)) { ret = -EEXIST; goto out_unlock; } @@ -628,7 +628,7 @@ void intel_guc_log_relay_close(struct intel_guc_log *log) flush_work(&log->relay.flush_work); mutex_lock(&log->relay.lock); - GEM_BUG_ON(!guc_log_relay_enabled(log)); + GEM_BUG_ON(!intel_guc_log_relay_enabled(log)); guc_log_unmap(log); guc_log_relay_destroy(log); mutex_unlock(&log->relay.lock); diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index db35e548d2ed..9ec5703d712c 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -52,10 +52,11 @@ struct intel_guc_log { u32 full_count; } relay; /* logging related stats */ - u32 flush_interrupt_count; - u32 prev_overflow_count[GUC_MAX_LOG_BUFFER]; - u32 total_overflow_count[GUC_MAX_LOG_BUFFER]; - u32 flush_count[GUC_MAX_LOG_BUFFER]; + struct { + u32 sampled_overflow; + u32 overflow; + u32 flush; + } stats[GUC_MAX_LOG_BUFFER]; }; void intel_guc_log_init_early(struct intel_guc_log *log); @@ -64,6 +65,7 @@ void intel_guc_log_destroy(struct intel_guc_log *log); int intel_guc_log_level_get(struct intel_guc_log *log); int intel_guc_log_level_set(struct intel_guc_log *log, u64 control_val); +bool intel_guc_log_relay_enabled(const struct intel_guc_log *log); int intel_guc_log_relay_open(struct intel_guc_log *log); void intel_guc_log_relay_flush(struct intel_guc_log *log); void intel_guc_log_relay_close(struct intel_guc_log *log); -- cgit v1.2.3 From cb5d64e9f13e0dd817c3ae2dbe73c3b8c6c13f95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 19 Mar 2018 10:53:45 +0100 Subject: drm/i915/guc: Allow user to control default GuC logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While both naming and actual log enable logic in GuC interface are confusing, we can simply expose the default log as yet another log level. GuC logic aside, from i915 point of view we now have the following GuC log levels: 0 Log disabled 1 Non-verbose log 2-5 Verbose log v2: Adjust naming after rebase. v3: Fixed the log_level logic error introduced on rebase. Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Michal Wajdeczko Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180319095348.9716-10-michal.winiarski@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 24 +++++++++++++++--------- drivers/gpu/drm/i915/intel_guc_fwif.h | 5 +++-- drivers/gpu/drm/i915/intel_guc_log.c | 18 +++++++----------- drivers/gpu/drm/i915/intel_guc_log.h | 15 +++++++++++++++ drivers/gpu/drm/i915/intel_uc.c | 14 +++++++++----- 5 files changed, 49 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index eeda1aa2afe6..dc16392c4c3a 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -222,17 +222,23 @@ static u32 get_core_family(struct drm_i915_private *dev_priv) } } -static u32 get_log_verbosity_flags(void) +static u32 get_log_control_flags(void) { - if (i915_modparams.guc_log_level > 0) { - u32 verbosity = i915_modparams.guc_log_level - 1; + u32 level = i915_modparams.guc_log_level; + u32 flags = 0; - GEM_BUG_ON(verbosity > GUC_LOG_VERBOSITY_MAX); - return verbosity << GUC_LOG_VERBOSITY_SHIFT; - } + GEM_BUG_ON(level < 0); + + if (!GUC_LOG_LEVEL_TO_ENABLED(level)) + flags |= GUC_LOG_DEFAULT_DISABLED; + + if (!GUC_LOG_LEVEL_TO_VERBOSE(level)) + flags |= GUC_LOG_DISABLED; + else + flags |= GUC_LOG_LEVEL_TO_VERBOSITY(level) << + GUC_LOG_VERBOSITY_SHIFT; - GEM_BUG_ON(i915_modparams.enable_guc < 0); - return GUC_LOG_DISABLED; + return flags; } /* @@ -267,7 +273,7 @@ void intel_guc_init_params(struct intel_guc *guc) params[GUC_CTL_LOG_PARAMS] = guc->log.flags; - params[GUC_CTL_DEBUG] = get_log_verbosity_flags(); + params[GUC_CTL_DEBUG] = get_log_control_flags(); /* If GuC submission is enabled, set up additional parameters here */ if (USES_GUC_SUBMISSION(dev_priv)) { diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h index 6a10aa6f04d3..4971685a2ea8 100644 --- a/drivers/gpu/drm/i915/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -127,7 +127,7 @@ #define GUC_PROFILE_ENABLED (1 << 7) #define GUC_WQ_TRACK_ENABLED (1 << 8) #define GUC_ADS_ENABLED (1 << 9) -#define GUC_DEBUG_RESERVED (1 << 10) +#define GUC_LOG_DEFAULT_DISABLED (1 << 10) #define GUC_ADS_ADDR_SHIFT 11 #define GUC_ADS_ADDR_MASK 0xfffff800 @@ -539,7 +539,8 @@ union guc_log_control { u32 logging_enabled:1; u32 reserved1:3; u32 verbosity:4; - u32 reserved2:24; + u32 default_logging:1; + u32 reserved2:23; }; u32 value; } __packed; diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 3180645b9642..4cb422ceb283 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -57,12 +57,14 @@ 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, bool enable, u32 verbosity) +static int guc_log_control(struct intel_guc *guc, bool enable, + bool default_logging, u32 verbosity) { union guc_log_control control_val = { { .logging_enabled = enable, .verbosity = verbosity, + .default_logging = default_logging, }, }; u32 action[] = { @@ -499,13 +501,6 @@ int intel_guc_log_level_get(struct intel_guc_log *log) return i915_modparams.guc_log_level; } -#define GUC_LOG_LEVEL_DISABLED 0 -#define LOG_LEVEL_TO_ENABLED(x) ((x) > 0) -#define LOG_LEVEL_TO_VERBOSITY(x) ({ \ - typeof(x) _x = (x); \ - LOG_LEVEL_TO_ENABLED(_x) ? _x - 1 : 0; \ -}) -#define VERBOSITY_TO_LOG_LEVEL(x) ((x) + 1) int intel_guc_log_level_set(struct intel_guc_log *log, u64 val) { struct intel_guc *guc = log_to_guc(log); @@ -521,7 +516,7 @@ int intel_guc_log_level_set(struct intel_guc_log *log, u64 val) * as indication that logging should be disabled. */ if (val < GUC_LOG_LEVEL_DISABLED || - val > VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX)) + val > GUC_VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX)) return -EINVAL; mutex_lock(&dev_priv->drm.struct_mutex); @@ -532,8 +527,9 @@ int intel_guc_log_level_set(struct intel_guc_log *log, u64 val) } intel_runtime_pm_get(dev_priv); - ret = guc_log_control(guc, LOG_LEVEL_TO_ENABLED(val), - LOG_LEVEL_TO_VERBOSITY(val)); + ret = guc_log_control(guc, GUC_LOG_LEVEL_TO_VERBOSE(val), + GUC_LOG_LEVEL_TO_ENABLED(val), + GUC_LOG_LEVEL_TO_VERBOSITY(val)); intel_runtime_pm_put(dev_priv); if (ret) { DRM_DEBUG_DRIVER("guc_log_control action failed %d\n", ret); diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index 9ec5703d712c..af1532c0d3e4 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -40,6 +40,21 @@ struct intel_guc; #define GUC_LOG_SIZE ((1 + GUC_LOG_DPC_PAGES + 1 + GUC_LOG_ISR_PAGES + \ 1 + GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT) +/* + * While we're using plain log level in i915, GuC controls are much more... + * "elaborate"? We have a couple of bits for verbosity, separate bit for actual + * log enabling, and separate bit for default logging - which "conveniently" + * ignores the enable bit. + */ +#define GUC_LOG_LEVEL_DISABLED 0 +#define GUC_LOG_LEVEL_TO_ENABLED(x) ((x) > 0) +#define GUC_LOG_LEVEL_TO_VERBOSE(x) ((x) > 1) +#define GUC_LOG_LEVEL_TO_VERBOSITY(x) ({ \ + typeof(x) _x = (x); \ + GUC_LOG_LEVEL_TO_VERBOSE(_x) ? _x - 2 : 0; \ +}) +#define GUC_VERBOSITY_TO_LOG_LEVEL(x) ((x) + 2) + struct intel_guc_log { u32 flags; struct i915_vma *vma; diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 9bb40cd047a0..ad1785522497 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -75,7 +75,8 @@ static int __get_default_guc_log_level(struct drm_i915_private *dev_priv) 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; + guc_log_level = + GUC_VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX); /* Any platform specific fine-tuning can be done here */ @@ -142,17 +143,20 @@ static void sanitize_options_early(struct drm_i915_private *dev_priv) i915_modparams.guc_log_level = 0; } - if (i915_modparams.guc_log_level > 1 + GUC_LOG_VERBOSITY_MAX) { + if (i915_modparams.guc_log_level > + GUC_VERBOSITY_TO_LOG_LEVEL(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; + i915_modparams.guc_log_level = + GUC_VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX); } - DRM_DEBUG_DRIVER("guc_log_level=%d (enabled:%s verbosity:%d)\n", + DRM_DEBUG_DRIVER("guc_log_level=%d (enabled:%s, verbose:%s, verbosity:%d)\n", i915_modparams.guc_log_level, yesno(i915_modparams.guc_log_level), - i915_modparams.guc_log_level - 1); + yesno(GUC_LOG_LEVEL_TO_VERBOSE(i915_modparams.guc_log_level)), + GUC_LOG_LEVEL_TO_VERBOSITY(i915_modparams.guc_log_level)); /* Make sure that sanitization was done */ GEM_BUG_ON(i915_modparams.enable_guc < 0); -- cgit v1.2.3 From 9605d1ce7c6bcb673b6893ac12b565f1bde8f0bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 19 Mar 2018 10:53:46 +0100 Subject: drm/i915/guc: Default to non-verbose GuC logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we've decoupled logging from relay, GuC log level is only controlling the GuC behavior - there shouldn't be any impact on i915 behaviour. We're only going to see a single extra interrupt when log will get half full. That, and the fact that we're seeing igt/gem_exec_nop/basic-series failing with non-verbose logging being disabled. v2: Bring back the "auto" guc_log_level, now that we fixed the log Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Michal Wajdeczko Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180319095348.9716-11-michal.winiarski@intel.com --- drivers/gpu/drm/i915/i915_params.h | 2 +- drivers/gpu/drm/i915/intel_uc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 430f5f9d0ff4..c96360398072 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, 0) \ + param(int, guc_log_level, -1) \ param(char *, guc_firmware_path, NULL) \ param(char *, huc_firmware_path, NULL) \ param(int, mmio_debug, 0) \ diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index ad1785522497..34e847d0ee4c 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -69,7 +69,7 @@ static int __get_platform_enable_guc(struct drm_i915_private *dev_priv) static int __get_default_guc_log_level(struct drm_i915_private *dev_priv) { - int guc_log_level = 0; /* disabled */ + int guc_log_level = 1; /* non-verbose */ /* Enable if we're running on platform with GuC and debug config */ if (HAS_GUC(dev_priv) && intel_uc_is_using_guc() && -- cgit v1.2.3 From feb06c151fade9ecaa3dd410d792cce26e8b10de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Mon, 19 Mar 2018 10:53:47 +0100 Subject: drm/i915/guc: Demote GuC error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're using those functions in selftests, and the callers are expected to do the error handling anyways. Let's demote all GuC actions and doorbell creation to DEBUG_DRIVER. Signed-off-by: Michał Winiarski Cc: Michal Wajdeczko Cc: Michel Thierry Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180319095348.9716-12-michal.winiarski@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 7 ++++--- drivers/gpu/drm/i915/intel_guc_submission.c | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index dc16392c4c3a..ee5230cc722e 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -362,9 +362,10 @@ int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len) if (ret != -ETIMEDOUT) ret = -EIO; - DRM_WARN("INTEL_GUC_SEND: Action 0x%X failed;" - " ret=%d status=0x%08X response=0x%08X\n", - action[0], ret, status, I915_READ(SOFT_SCRATCH(15))); + DRM_DEBUG_DRIVER("INTEL_GUC_SEND: Action 0x%X failed;" + " ret=%d status=0x%08X response=0x%08X\n", + action[0], ret, status, + I915_READ(SOFT_SCRATCH(15))); } intel_uncore_forcewake_put(dev_priv, guc->send_regs.fw_domains); diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 33af2930fc79..207cda062626 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -231,8 +231,8 @@ static int create_doorbell(struct intel_guc_client *client) if (ret) { __destroy_doorbell(client); __update_doorbell_desc(client, GUC_DOORBELL_INVALID); - DRM_ERROR("Couldn't create client %u doorbell: %d\n", - client->stage_id, ret); + DRM_DEBUG_DRIVER("Couldn't create client %u doorbell: %d\n", + client->stage_id, ret); return ret; } -- cgit v1.2.3 From 46b863325c2f58b564463c4d6e66ee0d4f2f3244 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 19 Mar 2018 12:35:28 +0000 Subject: drm/i915: Prefer memset64() when filling the iomap As the ringbuffer may exist inside stolen memory, our access to it may be via the GTT iomap. This implies we may only have WC access for which the conventional memset() substitution of rep stos performs very badly, so switch to the rep mov[dq] variants when available. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Matthew Auld Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20180319123528.28249-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 72d6167c519a..04d9d9a946a7 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1693,17 +1693,18 @@ u32 *intel_ring_begin(struct i915_request *rq, unsigned int num_dwords) need_wrap &= ~1; GEM_BUG_ON(need_wrap > ring->space); GEM_BUG_ON(ring->emit + need_wrap > ring->size); + GEM_BUG_ON(!IS_ALIGNED(need_wrap, sizeof(u64))); /* Fill the tail with MI_NOOP */ - memset(ring->vaddr + ring->emit, 0, need_wrap); - ring->emit = 0; + memset64(ring->vaddr + ring->emit, 0, need_wrap / sizeof(u64)); ring->space -= need_wrap; + ring->emit = 0; } GEM_BUG_ON(ring->emit > ring->size - bytes); GEM_BUG_ON(ring->space < bytes); cs = ring->vaddr + ring->emit; - GEM_DEBUG_EXEC(memset(cs, POISON_INUSE, bytes)); + GEM_DEBUG_EXEC(memset32(cs, POISON_INUSE, bytes / sizeof(*cs))); ring->emit += bytes; ring->space -= bytes; -- cgit v1.2.3 From 873d66fb9b1d4f4cd441f84068abb5457c60f127 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 16 Mar 2018 21:49:59 +0000 Subject: drm/i915: Trim error mask to known engines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the convenience of userspace passing in an arbitrary reset mask, remove unknown engines from the set of engines that are to be reset. This means that we always follow a per-engine reset with a full-device reset when userspace writes -1 into debugfs/i915_wedged. Reported-by: Michał Winiarski Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20180316215001.12391-1-chris@chris-wilson.co.uk Reviewed-by: Michel Thierry --- drivers/gpu/drm/i915/i915_irq.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 828f3104488c..44eef355e12c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2985,6 +2985,7 @@ void i915_handle_error(struct drm_i915_private *dev_priv, */ intel_runtime_pm_get(dev_priv); + engine_mask &= INTEL_INFO(dev_priv)->ring_mask; i915_capture_error_state(dev_priv, engine_mask, error_msg); i915_clear_error_registers(dev_priv); -- cgit v1.2.3 From 91b00dff56856ea4f87aa9fb3f6c90dbb5adfc55 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 20 Mar 2018 13:50:09 +0100 Subject: drm/i915: Select STACKDEPOT for DRM_I915_DEBUG select in Kconfig isn't recursive, we need to select the stuff our selects select, too. Fix that. Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180320125009.2305-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/i915/Kconfig.debug | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug index 108d21f34777..dd5bf6389ead 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -25,6 +25,7 @@ config DRM_I915_DEBUG select X86_MSR # used by igt/pm_rpm select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks) select DRM_DEBUG_MM if DRM=y + select STACKDEPOT if DRM=y # for DRM_DEBUG_MM select DRM_DEBUG_MM_SELFTEST select SW_SYNC # signaling validation framework (igt/syncobj*) select DRM_I915_SW_FENCE_DEBUG_OBJECTS -- cgit v1.2.3 From 26376a7e74d2deff445a72a2cfbfef084c28e4bc Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Fri, 16 Mar 2018 14:14:49 +0200 Subject: drm/i915/icl: Check for fused-off VDBOX and VEBOX instances In Gen11, the Video Decode engines (aka VDBOX, aka VCS, aka BSD) and the Video Enhancement engines (aka VEBOX, aka VECS) could be fused off. Also, each VDBOX and VEBOX has its own power well, which only exist if the related engine exists in the HW. Unfortunately, we have a Catch-22 situation going on: we need the blitter forcewake to read the register with the fuse info, but we cannot initialize the forcewake domains without knowin about the engines present in the HW. We workaround this problem by allowing the initialization of all forcewake domains and then pruning the fused off ones, as per the fuse information. Bspec: 20680 v2: We were shifting incorrectly for vebox disable (Vinay) v3: Assert mmio is ready and warn if we have attempted to initialize forcewake for fused-off engines (Paulo) v4: - Use INTEL_GEN in new code (Tvrtko) - Shorter local variable (Tvrtko, Michal) - Keep "if (!...) continue" style (Tvrtko) - No unnecessary BUG_ON (Tvrtko) - WARN_ON and cleanup if wrong mask (Tvrtko, Michal) - Use I915_READ_FW (Michal) - Use I915_MAX_VCS/VECS macros (Michal) v5: Rebased by Rodrigo fixing conflicts on top of: "drm/i915: Simplify intel_engines_init" v6: Fix v5. Remove info->num_rings. (by Oscar) v7: Rebase (Rodrigo). v8: - s/intel_device_info_fused_off_engines/ intel_device_info_init_mmio (Chris) - Make vdbox_disable & vebox_disable local variables (Chris) v9: - Move function declaration to intel_device_info.h (Michal) - Missing indent in bit fields definitions (Michal) - When RC6 is enabled by BIOS, the fuse register cannot be read until the blitter powerwell is awake. Shuffle where the fuse is read, prune the forcewake domains after the fact and change the commit message accordingly (Vinay, Sagar, Chris). v10: - Improved commit message (Sagar) - New line in header file (Sagar) - Specify the message in fw_domain_reset applies to ICL+ (Sagar) Cc: Paulo Zanoni Cc: Vinay Belgaumkar Cc: Tvrtko Ursulin Cc: Michal Wajdeczko Cc: Chris Wilson Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Signed-off-by: Rodrigo Vivi Signed-off-by: Oscar Mateo Reviewed-by: Sagar Arun Kamble Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-1-mika.kuoppala@linux.intel.com [Mika: soothe checkpatch on commit msg] Signed-off-by: Mika Kuoppala --- drivers/gpu/drm/i915/i915_drv.c | 4 +++ drivers/gpu/drm/i915/i915_reg.h | 5 +++ drivers/gpu/drm/i915/intel_device_info.c | 47 +++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_device_info.h | 2 ++ drivers/gpu/drm/i915/intel_uncore.c | 56 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_uncore.h | 1 + 6 files changed, 115 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 1021bf40e236..ba5f150a29c0 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1033,6 +1033,10 @@ static int i915_driver_init_mmio(struct drm_i915_private *dev_priv) intel_uncore_init(dev_priv); + intel_device_info_init_mmio(dev_priv); + + intel_uncore_prune(dev_priv); + intel_uc_init_mmio(dev_priv); ret = intel_engines_init_mmio(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1b48d50dfcf1..429de0ad6cd4 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2545,6 +2545,11 @@ enum i915_power_well_id { #define GEN10_EU_DISABLE3 _MMIO(0x9140) #define GEN10_EU_DIS_SS_MASK 0xff +#define GEN11_GT_VEBOX_VDBOX_DISABLE _MMIO(0x9140) +#define GEN11_GT_VDBOX_DISABLE_MASK 0xff +#define GEN11_GT_VEBOX_DISABLE_SHIFT 16 +#define GEN11_GT_VEBOX_DISABLE_MASK (0xff << GEN11_GT_VEBOX_DISABLE_SHIFT) + #define GEN6_BSD_SLEEP_PSMI_CONTROL _MMIO(0x12050) #define GEN6_BSD_SLEEP_MSG_DISABLE (1 << 0) #define GEN6_BSD_SLEEP_FLUSH_DISABLE (1 << 2) diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 3dd350f7b8e6..4babfc6ee45b 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -780,3 +780,50 @@ void intel_driver_caps_print(const struct intel_driver_caps *caps, { drm_printf(p, "scheduler: %x\n", caps->scheduler); } + +/* + * Determine which engines are fused off in our particular hardware. Since the + * fuse register is in the blitter powerwell, we need forcewake to be ready at + * this point (but later we need to prune the forcewake domains for engines that + * are indeed fused off). + */ +void intel_device_info_init_mmio(struct drm_i915_private *dev_priv) +{ + struct intel_device_info *info = mkwrite_device_info(dev_priv); + u8 vdbox_disable, vebox_disable; + u32 media_fuse; + int i; + + if (INTEL_GEN(dev_priv) < 11) + return; + + media_fuse = I915_READ(GEN11_GT_VEBOX_VDBOX_DISABLE); + + vdbox_disable = media_fuse & GEN11_GT_VDBOX_DISABLE_MASK; + vebox_disable = (media_fuse & GEN11_GT_VEBOX_DISABLE_MASK) >> + GEN11_GT_VEBOX_DISABLE_SHIFT; + + DRM_DEBUG_DRIVER("vdbox disable: %04x\n", vdbox_disable); + for (i = 0; i < I915_MAX_VCS; i++) { + if (!HAS_ENGINE(dev_priv, _VCS(i))) + continue; + + if (!(BIT(i) & vdbox_disable)) + continue; + + info->ring_mask &= ~ENGINE_MASK(_VCS(i)); + DRM_DEBUG_DRIVER("vcs%u fused off\n", i); + } + + DRM_DEBUG_DRIVER("vebox disable: %04x\n", vebox_disable); + for (i = 0; i < I915_MAX_VECS; i++) { + if (!HAS_ENGINE(dev_priv, _VECS(i))) + continue; + + if (!(BIT(i) & vebox_disable)) + continue; + + info->ring_mask &= ~ENGINE_MASK(_VECS(i)); + DRM_DEBUG_DRIVER("vecs%u fused off\n", i); + } +} diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index 0835752c8b22..0cbb92223013 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -247,6 +247,8 @@ void intel_device_info_dump_runtime(const struct intel_device_info *info, void intel_device_info_dump_topology(const struct sseu_dev_info *sseu, struct drm_printer *p); +void intel_device_info_init_mmio(struct drm_i915_private *dev_priv); + void intel_driver_caps_print(const struct intel_driver_caps *caps, struct drm_printer *p); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 4df7c2ef8576..4c616d074a97 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -62,6 +62,11 @@ static inline void fw_domain_reset(struct drm_i915_private *i915, const struct intel_uncore_forcewake_domain *d) { + /* + * We don't really know if the powerwell for the forcewake domain we are + * trying to reset here does exist at this point (engines could be fused + * off in ICL+), so no waiting for acks + */ __raw_i915_write32(i915, d->reg_set, i915->uncore.fw_reset); } @@ -1353,6 +1358,23 @@ static void fw_domain_init(struct drm_i915_private *dev_priv, fw_domain_reset(dev_priv, d); } +static void fw_domain_fini(struct drm_i915_private *dev_priv, + enum forcewake_domain_id domain_id) +{ + struct intel_uncore_forcewake_domain *d; + + if (WARN_ON(domain_id >= FW_DOMAIN_ID_COUNT)) + return; + + d = &dev_priv->uncore.fw_domain[domain_id]; + + WARN_ON(d->wake_count); + WARN_ON(hrtimer_cancel(&d->timer)); + memset(d, 0, sizeof(*d)); + + dev_priv->uncore.fw_domains &= ~BIT(domain_id); +} + static void intel_uncore_fw_domains_init(struct drm_i915_private *dev_priv) { if (INTEL_GEN(dev_priv) <= 5 || intel_vgpu_active(dev_priv)) @@ -1565,6 +1587,40 @@ void intel_uncore_init(struct drm_i915_private *dev_priv) &dev_priv->uncore.pmic_bus_access_nb); } +/* + * We might have detected that some engines are fused off after we initialized + * the forcewake domains. Prune them, to make sure they only reference existing + * engines. + */ +void intel_uncore_prune(struct drm_i915_private *dev_priv) +{ + if (INTEL_GEN(dev_priv) >= 11) { + enum forcewake_domains fw_domains = dev_priv->uncore.fw_domains; + enum forcewake_domain_id domain_id; + int i; + + for (i = 0; i < I915_MAX_VCS; i++) { + domain_id = FW_DOMAIN_ID_MEDIA_VDBOX0 + i; + + if (HAS_ENGINE(dev_priv, _VCS(i))) + continue; + + if (fw_domains & BIT(domain_id)) + fw_domain_fini(dev_priv, domain_id); + } + + for (i = 0; i < I915_MAX_VECS; i++) { + domain_id = FW_DOMAIN_ID_MEDIA_VEBOX0 + i; + + if (HAS_ENGINE(dev_priv, _VECS(i))) + continue; + + if (fw_domains & BIT(domain_id)) + fw_domain_fini(dev_priv, domain_id); + } + } +} + void intel_uncore_fini(struct drm_i915_private *dev_priv) { /* Paranoia: make sure we have disabled everything before we exit. */ diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h index dfdf444e4bcc..47478d609630 100644 --- a/drivers/gpu/drm/i915/intel_uncore.h +++ b/drivers/gpu/drm/i915/intel_uncore.h @@ -140,6 +140,7 @@ struct intel_uncore { void intel_uncore_sanitize(struct drm_i915_private *dev_priv); void intel_uncore_init(struct drm_i915_private *dev_priv); +void intel_uncore_prune(struct drm_i915_private *dev_priv); bool intel_uncore_unclaimed_mmio(struct drm_i915_private *dev_priv); bool intel_uncore_arm_unclaimed_mmio_detection(struct drm_i915_private *dev_priv); void intel_uncore_fini(struct drm_i915_private *dev_priv); -- cgit v1.2.3 From d53d5ffb9b937ae08402d5aec5c44fb9be409afb Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Fri, 16 Mar 2018 14:14:50 +0200 Subject: drm/i915/icl: Enable the extra video decode and enhancement boxes for Icelake 11 Icelake 11 has one vebox and two vdboxes (0 and 2). Bspec: 21140 v2: Split out in two (Daniele) Cc: Daniele Ceraolo Spurio Signed-off-by: Oscar Mateo Reviewed-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-2-mika.kuoppala@linux.intel.com Signed-off-by: Mika Kuoppala --- drivers/gpu/drm/i915/i915_pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 062e91b39085..4364922e935d 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -602,6 +602,7 @@ static const struct intel_device_info intel_icelake_11_info = { PLATFORM(INTEL_ICELAKE), .is_alpha_support = 1, .has_resource_streamer = 0, + .ring_mask = RENDER_RING | BLT_RING | VEBOX_RING | BSD_RING | BSD3_RING, }; #undef GEN -- cgit v1.2.3 From d3d57927995f872e5786ff6ae517a6c3e7a94d75 Mon Sep 17 00:00:00 2001 From: Kelvin Gardiner Date: Fri, 16 Mar 2018 14:14:51 +0200 Subject: drm/i915/icl: Update subslice define for ICL 11 ICL 11 has a greater number of maximum subslices. This patch reflects this. v2: GEN11 updates to MCR_SELECTOR (Oscar) v3: Copypasta error in the new defines (Lionel) Bspec: 21139 BSpec: 21108 Signed-off-by: Kelvin Gardiner Reviewed-by: Oscar Mateo (v1) Reviewed-by: Daniele Ceraolo Spurio (v1) Signed-off-by: Oscar Mateo Reviewed-by: Lionel Landwerlin Link: https://patchwork.freedesktop.org/patch/msgid/20180316121456.11577-3-mika.kuoppala@linux.intel.com Signed-off-by: Mika Kuoppala --- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ drivers/gpu/drm/i915/intel_engine_cs.c | 22 ++++++++++++++++++---- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 3 files changed, 23 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 429de0ad6cd4..699292eae02e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2151,6 +2151,10 @@ enum i915_power_well_id { #define GEN8_MCR_SLICE_MASK GEN8_MCR_SLICE(3) #define GEN8_MCR_SUBSLICE(subslice) (((subslice) & 3) << 24) #define GEN8_MCR_SUBSLICE_MASK GEN8_MCR_SUBSLICE(3) +#define GEN11_MCR_SLICE(slice) (((slice) & 0xf) << 27) +#define GEN11_MCR_SLICE_MASK GEN11_MCR_SLICE(0xf) +#define GEN11_MCR_SUBSLICE(subslice) (((subslice) & 0x7) << 24) +#define GEN11_MCR_SUBSLICE_MASK GEN11_MCR_SUBSLICE(0x7) #define RING_IPEIR(base) _MMIO((base)+0x64) #define RING_IPEHR(base) _MMIO((base)+0x68) /* diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 337dfa56a738..de09fa42a509 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -800,10 +800,24 @@ static inline uint32_t read_subslice_reg(struct drm_i915_private *dev_priv, int slice, int subslice, i915_reg_t reg) { + uint32_t mcr_slice_subslice_mask; + uint32_t mcr_slice_subslice_select; uint32_t mcr; uint32_t ret; enum forcewake_domains fw_domains; + if (INTEL_GEN(dev_priv) >= 11) { + mcr_slice_subslice_mask = GEN11_MCR_SLICE_MASK | + GEN11_MCR_SUBSLICE_MASK; + mcr_slice_subslice_select = GEN11_MCR_SLICE(slice) | + GEN11_MCR_SUBSLICE(subslice); + } else { + mcr_slice_subslice_mask = GEN8_MCR_SLICE_MASK | + GEN8_MCR_SUBSLICE_MASK; + mcr_slice_subslice_select = GEN8_MCR_SLICE(slice) | + GEN8_MCR_SUBSLICE(subslice); + } + fw_domains = intel_uncore_forcewake_for_reg(dev_priv, reg, FW_REG_READ); fw_domains |= intel_uncore_forcewake_for_reg(dev_priv, @@ -818,14 +832,14 @@ read_subslice_reg(struct drm_i915_private *dev_priv, int slice, * The HW expects the slice and sublice selectors to be reset to 0 * after reading out the registers. */ - WARN_ON_ONCE(mcr & (GEN8_MCR_SLICE_MASK | GEN8_MCR_SUBSLICE_MASK)); - mcr &= ~(GEN8_MCR_SLICE_MASK | GEN8_MCR_SUBSLICE_MASK); - mcr |= GEN8_MCR_SLICE(slice) | GEN8_MCR_SUBSLICE(subslice); + WARN_ON_ONCE(mcr & mcr_slice_subslice_mask); + mcr &= ~mcr_slice_subslice_mask; + mcr |= mcr_slice_subslice_select; I915_WRITE_FW(GEN8_MCR_SELECTOR, mcr); ret = I915_READ_FW(reg); - mcr &= ~(GEN8_MCR_SLICE_MASK | GEN8_MCR_SUBSLICE_MASK); + mcr &= ~mcr_slice_subslice_mask; I915_WRITE_FW(GEN8_MCR_SELECTOR, mcr); intel_uncore_forcewake_put__locked(dev_priv, fw_domains); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 1f50727a5ddb..a02c7b3b9d55 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -86,7 +86,7 @@ hangcheck_action_to_str(const enum intel_engine_hangcheck_action a) } #define I915_MAX_SLICES 3 -#define I915_MAX_SUBSLICES 3 +#define I915_MAX_SUBSLICES 8 #define instdone_slice_mask(dev_priv__) \ (INTEL_GEN(dev_priv__) == 7 ? \ -- cgit v1.2.3 From 03380d173a697475c747e4cd6ea2be739005dedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= Date: Tue, 20 Mar 2018 12:55:17 +0100 Subject: drm/i915/guc: Don't try to enable GuC logging when we're not using GuC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When changing the default values for guc_log_level, we accidentally left the log enabled on non-guc platforms. Let's fix that. v2: Define the levels used and remove (now obsolete) comments (Chris) v3: Use "IS" rather than "TO" for booleans (Chris) Fixes: 9605d1ce7c6b ("drm/i915/guc: Default to non-verbose GuC logging") Reported-by: Chris Wilson Signed-off-by: Michał Winiarski Cc: Chris Wilson Cc: Sagar Arun Kamble Cc: Michal Wajdeczko Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180320115517.20423-1-michal.winiarski@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 4 ++-- drivers/gpu/drm/i915/intel_guc_log.c | 7 +++---- drivers/gpu/drm/i915/intel_guc_log.h | 12 +++++++----- drivers/gpu/drm/i915/intel_uc.c | 23 +++++++++++------------ 4 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index ee5230cc722e..4b7c9c6415dd 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -229,10 +229,10 @@ static u32 get_log_control_flags(void) GEM_BUG_ON(level < 0); - if (!GUC_LOG_LEVEL_TO_ENABLED(level)) + if (!GUC_LOG_LEVEL_IS_ENABLED(level)) flags |= GUC_LOG_DEFAULT_DISABLED; - if (!GUC_LOG_LEVEL_TO_VERBOSE(level)) + if (!GUC_LOG_LEVEL_IS_VERBOSE(level)) flags |= GUC_LOG_DISABLED; else flags |= GUC_LOG_LEVEL_TO_VERBOSITY(level) << diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 4cb422ceb283..ae9b2569adab 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -515,8 +515,7 @@ int intel_guc_log_level_set(struct intel_guc_log *log, u64 val) * GuC is recognizing log levels starting from 0 to max, we're using 0 * as indication that logging should be disabled. */ - if (val < GUC_LOG_LEVEL_DISABLED || - val > GUC_VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX)) + if (val < GUC_LOG_LEVEL_DISABLED || val > GUC_LOG_LEVEL_MAX) return -EINVAL; mutex_lock(&dev_priv->drm.struct_mutex); @@ -527,8 +526,8 @@ int intel_guc_log_level_set(struct intel_guc_log *log, u64 val) } intel_runtime_pm_get(dev_priv); - ret = guc_log_control(guc, GUC_LOG_LEVEL_TO_VERBOSE(val), - GUC_LOG_LEVEL_TO_ENABLED(val), + ret = guc_log_control(guc, GUC_LOG_LEVEL_IS_VERBOSE(val), + GUC_LOG_LEVEL_IS_ENABLED(val), GUC_LOG_LEVEL_TO_VERBOSITY(val)); intel_runtime_pm_put(dev_priv); if (ret) { diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index af1532c0d3e4..1b0d2fa4c0b6 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -46,14 +46,16 @@ struct intel_guc; * log enabling, and separate bit for default logging - which "conveniently" * ignores the enable bit. */ -#define GUC_LOG_LEVEL_DISABLED 0 -#define GUC_LOG_LEVEL_TO_ENABLED(x) ((x) > 0) -#define GUC_LOG_LEVEL_TO_VERBOSE(x) ((x) > 1) +#define GUC_LOG_LEVEL_DISABLED 0 +#define GUC_LOG_LEVEL_NON_VERBOSE 1 +#define GUC_LOG_LEVEL_IS_ENABLED(x) ((x) > GUC_LOG_LEVEL_DISABLED) +#define GUC_LOG_LEVEL_IS_VERBOSE(x) ((x) > GUC_LOG_LEVEL_NON_VERBOSE) #define GUC_LOG_LEVEL_TO_VERBOSITY(x) ({ \ typeof(x) _x = (x); \ - GUC_LOG_LEVEL_TO_VERBOSE(_x) ? _x - 2 : 0; \ + GUC_LOG_LEVEL_IS_VERBOSE(_x) ? _x - 2 : 0; \ }) -#define GUC_VERBOSITY_TO_LOG_LEVEL(x) ((x) + 2) +#define GUC_VERBOSITY_TO_LOG_LEVEL(x) ((x) + 2) +#define GUC_LOG_LEVEL_MAX GUC_VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX) struct intel_guc_log { u32 flags; diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 34e847d0ee4c..2befcafbaabe 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -69,14 +69,15 @@ static int __get_platform_enable_guc(struct drm_i915_private *dev_priv) static int __get_default_guc_log_level(struct drm_i915_private *dev_priv) { - int guc_log_level = 1; /* non-verbose */ + int guc_log_level; - /* 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 = - GUC_VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX); + if (!HAS_GUC(dev_priv) || !intel_uc_is_using_guc()) + guc_log_level = GUC_LOG_LEVEL_DISABLED; + else if (IS_ENABLED(CONFIG_DRM_I915_DEBUG) || + IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) + guc_log_level = GUC_LOG_LEVEL_MAX; + else + guc_log_level = GUC_LOG_LEVEL_NON_VERBOSE; /* Any platform specific fine-tuning can be done here */ @@ -143,19 +144,17 @@ static void sanitize_options_early(struct drm_i915_private *dev_priv) i915_modparams.guc_log_level = 0; } - if (i915_modparams.guc_log_level > - GUC_VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX)) { + if (i915_modparams.guc_log_level > GUC_LOG_LEVEL_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 = - GUC_VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX); + i915_modparams.guc_log_level = GUC_LOG_LEVEL_MAX; } DRM_DEBUG_DRIVER("guc_log_level=%d (enabled:%s, verbose:%s, verbosity:%d)\n", i915_modparams.guc_log_level, yesno(i915_modparams.guc_log_level), - yesno(GUC_LOG_LEVEL_TO_VERBOSE(i915_modparams.guc_log_level)), + yesno(GUC_LOG_LEVEL_IS_VERBOSE(i915_modparams.guc_log_level)), GUC_LOG_LEVEL_TO_VERBOSITY(i915_modparams.guc_log_level)); /* Make sure that sanitization was done */ -- cgit v1.2.3 From ca98317b89428e6ac17be0938b467ed78654dd56 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 20 Mar 2018 10:04:48 +0000 Subject: drm/i915: Specify which engines to reset following semaphore/event lockups If the GPU is stuck waiting for an event or for a semaphore, we need to reset the GPU in order to recover. We have to tell the reset routine which engines we want reset, but we were still using the old interface and declaring it as "not-fatal". Fixes: 14b730fcb8d9 ("drm/i915/tdr: Prepare error handler to accept mask of hung engines") Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Michel Thierry Reviewed-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180320100449.1360-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_hangcheck.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hangcheck.c b/drivers/gpu/drm/i915/intel_hangcheck.c index 42e45ae87393..c8ea510629fa 100644 --- a/drivers/gpu/drm/i915/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/intel_hangcheck.c @@ -246,7 +246,7 @@ engine_stuck(struct intel_engine_cs *engine, u64 acthd) */ tmp = I915_READ_CTL(engine); if (tmp & RING_WAIT) { - i915_handle_error(dev_priv, 0, + i915_handle_error(dev_priv, BIT(engine->id), "Kicking stuck wait on %s", engine->name); I915_WRITE_CTL(engine, tmp); @@ -258,7 +258,7 @@ engine_stuck(struct intel_engine_cs *engine, u64 acthd) default: return ENGINE_DEAD; case 1: - i915_handle_error(dev_priv, 0, + i915_handle_error(dev_priv, ALL_ENGINES, "Kicking stuck semaphore on %s", engine->name); I915_WRITE_CTL(engine, tmp); -- cgit v1.2.3 From ce80075470f6328e487389262c95af092d421ffc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 20 Mar 2018 10:04:49 +0000 Subject: drm/i915: Add control flags to i915_handle_error() Not all callers want the GPU error to handled in the same way, so expose a control parameter. In the first instance, some callers do not want the heavyweight error capture so add a bit to request the state to be captured and saved. v2: Pass msg down to i915_reset/i915_reset_engine so that we include the reason for the reset in the dev_notice(), superseding the earlier option to not print that notice. v3: Stash the reason inside the i915->gpu_error to handover to the direct reset from the blocking waiter. Signed-off-by: Chris Wilson Cc: Jeff McGee Cc: Mika Kuoppala Cc: Michel Thierry Reviewed-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180320100449.1360-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_debugfs.c | 4 +- drivers/gpu/drm/i915/i915_drv.c | 17 ++++---- drivers/gpu/drm/i915/i915_drv.h | 10 ++--- drivers/gpu/drm/i915/i915_gpu_error.h | 3 ++ drivers/gpu/drm/i915/i915_irq.c | 55 ++++++++++++++---------- drivers/gpu/drm/i915/i915_request.c | 2 +- drivers/gpu/drm/i915/intel_hangcheck.c | 13 +++--- drivers/gpu/drm/i915/selftests/intel_hangcheck.c | 13 +++--- 8 files changed, 62 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 964ea1a12357..7816cd53100a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4011,8 +4011,8 @@ i915_wedged_set(void *data, u64 val) engine->hangcheck.stalled = true; } - i915_handle_error(i915, val, "Manually set wedged engine mask = %llx", - val); + i915_handle_error(i915, val, I915_ERROR_CAPTURE, + "Manually set wedged engine mask = %llx", val); wait_on_bit(&i915->gpu_error.flags, I915_RESET_HANDOFF, diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ba5f150a29c0..3f637ab89e51 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1873,7 +1873,6 @@ static int i915_resume_switcheroo(struct drm_device *dev) /** * i915_reset - reset chip after a hang * @i915: #drm_i915_private to reset - * @flags: Instructions * * Reset the chip. Useful if a hang is detected. Marks the device as wedged * on failure. @@ -1888,7 +1887,7 @@ static int i915_resume_switcheroo(struct drm_device *dev) * - re-init interrupt state * - re-init display */ -void i915_reset(struct drm_i915_private *i915, unsigned int flags) +void i915_reset(struct drm_i915_private *i915) { struct i915_gpu_error *error = &i915->gpu_error; int ret; @@ -1905,8 +1904,9 @@ void i915_reset(struct drm_i915_private *i915, unsigned int flags) if (!i915_gem_unset_wedged(i915)) goto wakeup; - if (!(flags & I915_RESET_QUIET)) - dev_notice(i915->drm.dev, "Resetting chip after gpu hang\n"); + if (error->reason) + dev_notice(i915->drm.dev, + "Resetting chip for %s\n", error->reason); error->reset_count++; disable_irq(i915->drm.irq); @@ -2007,7 +2007,7 @@ static inline int intel_gt_reset_engine(struct drm_i915_private *dev_priv, /** * i915_reset_engine - reset GPU engine to recover from a hang * @engine: engine to reset - * @flags: options + * @msg: reason for GPU reset; or NULL for no dev_notice() * * Reset a specific GPU engine. Useful if a hang is detected. * Returns zero on successful reset or otherwise an error code. @@ -2017,7 +2017,7 @@ static inline int intel_gt_reset_engine(struct drm_i915_private *dev_priv, * - reset engine (which will force the engine to idle) * - re-init/configure engine */ -int i915_reset_engine(struct intel_engine_cs *engine, unsigned int flags) +int i915_reset_engine(struct intel_engine_cs *engine, const char *msg) { struct i915_gpu_error *error = &engine->i915->gpu_error; struct i915_request *active_request; @@ -2032,10 +2032,9 @@ int i915_reset_engine(struct intel_engine_cs *engine, unsigned int flags) goto out; } - if (!(flags & I915_RESET_QUIET)) { + if (msg) dev_notice(engine->i915->drm.dev, - "Resetting %s after gpu hang\n", engine->name); - } + "Resetting %s for %s\n", engine->name, msg); error->reset_engine_count[engine->id]++; if (!engine->i915->guc.execbuf_client) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e27ba8fb64e6..c9c3b2ba6a86 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2700,10 +2700,8 @@ extern void i915_driver_unload(struct drm_device *dev); extern int intel_gpu_reset(struct drm_i915_private *dev_priv, u32 engine_mask); extern bool intel_has_gpu_reset(struct drm_i915_private *dev_priv); -#define I915_RESET_QUIET BIT(0) -extern void i915_reset(struct drm_i915_private *i915, unsigned int flags); -extern int i915_reset_engine(struct intel_engine_cs *engine, - unsigned int flags); +extern void i915_reset(struct drm_i915_private *i915); +extern int i915_reset_engine(struct intel_engine_cs *engine, const char *msg); extern bool intel_has_reset_engine(struct drm_i915_private *dev_priv); extern int intel_reset_guc(struct drm_i915_private *dev_priv); @@ -2751,10 +2749,12 @@ static inline void i915_queue_hangcheck(struct drm_i915_private *dev_priv) &dev_priv->gpu_error.hangcheck_work, delay); } -__printf(3, 4) +__printf(4, 5) void i915_handle_error(struct drm_i915_private *dev_priv, u32 engine_mask, + unsigned long flags, const char *fmt, ...); +#define I915_ERROR_CAPTURE BIT(0) extern void intel_irq_init(struct drm_i915_private *dev_priv); extern void intel_irq_fini(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index ebbdf37e2879..ac5760673cc9 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -269,6 +269,9 @@ struct i915_gpu_error { /** Number of times an engine has been reset */ u32 reset_engine_count[I915_NUM_ENGINES]; + /** Reason for the current *global* reset */ + const char *reason; + /** * Waitqueue to signal when a hang is detected. Used to for waiters * to release the struct_mutex for the reset to procede. diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 44eef355e12c..fa7310766217 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2877,15 +2877,10 @@ static irqreturn_t gen11_irq_handler(int irq, void *arg) return IRQ_HANDLED; } -/** - * i915_reset_device - do process context error handling work - * @dev_priv: i915 device private - * - * Fire an error uevent so userspace can see that a hang or error - * was detected. - */ -static void i915_reset_device(struct drm_i915_private *dev_priv) +static void i915_reset_device(struct drm_i915_private *dev_priv, + const char *msg) { + struct i915_gpu_error *error = &dev_priv->gpu_error; struct kobject *kobj = &dev_priv->drm.primary->kdev->kobj; char *error_event[] = { I915_ERROR_UEVENT "=1", NULL }; char *reset_event[] = { I915_RESET_UEVENT "=1", NULL }; @@ -2901,29 +2896,32 @@ static void i915_reset_device(struct drm_i915_private *dev_priv) i915_wedge_on_timeout(&w, dev_priv, 5*HZ) { intel_prepare_reset(dev_priv); + error->reason = msg; + /* Signal that locked waiters should reset the GPU */ - set_bit(I915_RESET_HANDOFF, &dev_priv->gpu_error.flags); - wake_up_all(&dev_priv->gpu_error.wait_queue); + set_bit(I915_RESET_HANDOFF, &error->flags); + wake_up_all(&error->wait_queue); /* Wait for anyone holding the lock to wakeup, without * blocking indefinitely on struct_mutex. */ do { if (mutex_trylock(&dev_priv->drm.struct_mutex)) { - i915_reset(dev_priv, 0); + i915_reset(dev_priv); mutex_unlock(&dev_priv->drm.struct_mutex); } - } while (wait_on_bit_timeout(&dev_priv->gpu_error.flags, + } while (wait_on_bit_timeout(&error->flags, I915_RESET_HANDOFF, TASK_UNINTERRUPTIBLE, 1)); + error->reason = NULL; + intel_finish_reset(dev_priv); } - if (!test_bit(I915_WEDGED, &dev_priv->gpu_error.flags)) - kobject_uevent_env(kobj, - KOBJ_CHANGE, reset_done_event); + if (!test_bit(I915_WEDGED, &error->flags)) + kobject_uevent_env(kobj, KOBJ_CHANGE, reset_done_event); } static void i915_clear_error_registers(struct drm_i915_private *dev_priv) @@ -2955,6 +2953,7 @@ static void i915_clear_error_registers(struct drm_i915_private *dev_priv) * i915_handle_error - handle a gpu error * @dev_priv: i915 device private * @engine_mask: mask representing engines that are hung + * @flags: control flags * @fmt: Error message format string * * Do some basic checking of register state at error time and @@ -2965,16 +2964,23 @@ static void i915_clear_error_registers(struct drm_i915_private *dev_priv) */ void i915_handle_error(struct drm_i915_private *dev_priv, u32 engine_mask, + unsigned long flags, const char *fmt, ...) { struct intel_engine_cs *engine; unsigned int tmp; - va_list args; char error_msg[80]; + char *msg = NULL; - va_start(args, fmt); - vscnprintf(error_msg, sizeof(error_msg), fmt, args); - va_end(args); + if (fmt) { + va_list args; + + va_start(args, fmt); + vscnprintf(error_msg, sizeof(error_msg), fmt, args); + va_end(args); + + msg = error_msg; + } /* * In most cases it's guaranteed that we get here with an RPM @@ -2986,8 +2992,11 @@ void i915_handle_error(struct drm_i915_private *dev_priv, intel_runtime_pm_get(dev_priv); engine_mask &= INTEL_INFO(dev_priv)->ring_mask; - i915_capture_error_state(dev_priv, engine_mask, error_msg); - i915_clear_error_registers(dev_priv); + + if (flags & I915_ERROR_CAPTURE) { + i915_capture_error_state(dev_priv, engine_mask, msg); + i915_clear_error_registers(dev_priv); + } /* * Try engine reset when available. We fall back to full reset if @@ -3000,7 +3009,7 @@ void i915_handle_error(struct drm_i915_private *dev_priv, &dev_priv->gpu_error.flags)) continue; - if (i915_reset_engine(engine, 0) == 0) + if (i915_reset_engine(engine, msg) == 0) engine_mask &= ~intel_engine_flag(engine); clear_bit(I915_RESET_ENGINE + engine->id, @@ -3030,7 +3039,7 @@ void i915_handle_error(struct drm_i915_private *dev_priv, TASK_UNINTERRUPTIBLE); } - i915_reset_device(dev_priv); + i915_reset_device(dev_priv, msg); for_each_engine(engine, dev_priv, tmp) { clear_bit(I915_RESET_ENGINE + engine->id, diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 43c7134a9b93..2325886d1d55 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1229,7 +1229,7 @@ static bool __i915_wait_request_check_and_reset(struct i915_request *request) return false; __set_current_state(TASK_RUNNING); - i915_reset(request->i915, 0); + i915_reset(request->i915); return true; } diff --git a/drivers/gpu/drm/i915/intel_hangcheck.c b/drivers/gpu/drm/i915/intel_hangcheck.c index c8ea510629fa..fd0ffb8328d0 100644 --- a/drivers/gpu/drm/i915/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/intel_hangcheck.c @@ -246,9 +246,8 @@ engine_stuck(struct intel_engine_cs *engine, u64 acthd) */ tmp = I915_READ_CTL(engine); if (tmp & RING_WAIT) { - i915_handle_error(dev_priv, BIT(engine->id), - "Kicking stuck wait on %s", - engine->name); + i915_handle_error(dev_priv, BIT(engine->id), 0, + "stuck wait on %s", engine->name); I915_WRITE_CTL(engine, tmp); return ENGINE_WAIT_KICK; } @@ -258,8 +257,8 @@ engine_stuck(struct intel_engine_cs *engine, u64 acthd) default: return ENGINE_DEAD; case 1: - i915_handle_error(dev_priv, ALL_ENGINES, - "Kicking stuck semaphore on %s", + i915_handle_error(dev_priv, ALL_ENGINES, 0, + "stuck semaphore on %s", engine->name); I915_WRITE_CTL(engine, tmp); return ENGINE_WAIT_KICK; @@ -386,13 +385,13 @@ static void hangcheck_declare_hang(struct drm_i915_private *i915, if (stuck != hung) hung &= ~stuck; len = scnprintf(msg, sizeof(msg), - "%s on ", stuck == hung ? "No progress" : "Hang"); + "%s on ", stuck == hung ? "no progress" : "hang"); for_each_engine_masked(engine, i915, hung, tmp) len += scnprintf(msg + len, sizeof(msg) - len, "%s, ", engine->name); msg[len-2] = '\0'; - return i915_handle_error(i915, hung, "%s", msg); + return i915_handle_error(i915, hung, I915_ERROR_CAPTURE, "%s", msg); } /* diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index df7898c8edcb..4372826998aa 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -433,7 +433,7 @@ static int igt_global_reset(void *arg) mutex_lock(&i915->drm.struct_mutex); reset_count = i915_reset_count(&i915->gpu_error); - i915_reset(i915, I915_RESET_QUIET); + i915_reset(i915); if (i915_reset_count(&i915->gpu_error) == reset_count) { pr_err("No GPU reset recorded!\n"); @@ -518,7 +518,7 @@ static int __igt_reset_engine(struct drm_i915_private *i915, bool active) engine->hangcheck.seqno = intel_engine_get_seqno(engine); - err = i915_reset_engine(engine, I915_RESET_QUIET); + err = i915_reset_engine(engine, NULL); if (err) { pr_err("i915_reset_engine failed\n"); break; @@ -725,7 +725,7 @@ static int __igt_reset_engine_others(struct drm_i915_private *i915, engine->hangcheck.seqno = intel_engine_get_seqno(engine); - err = i915_reset_engine(engine, I915_RESET_QUIET); + err = i915_reset_engine(engine, NULL); if (err) { pr_err("i915_reset_engine(%s:%s) failed, err=%d\n", engine->name, active ? "active" : "idle", err); @@ -865,7 +865,6 @@ static int igt_wait_reset(void *arg) __func__, rq->fence.seqno, hws_seqno(&h, rq)); intel_engine_dump(rq->engine, &p, "%s\n", rq->engine->name); - i915_reset(i915, 0); i915_gem_set_wedged(i915); err = -EIO; @@ -962,7 +961,6 @@ static int igt_reset_queue(void *arg) i915_request_put(rq); i915_request_put(prev); - i915_reset(i915, 0); i915_gem_set_wedged(i915); err = -EIO; @@ -971,7 +969,7 @@ static int igt_reset_queue(void *arg) reset_count = fake_hangcheck(prev); - i915_reset(i915, I915_RESET_QUIET); + i915_reset(i915); GEM_BUG_ON(test_bit(I915_RESET_HANDOFF, &i915->gpu_error.flags)); @@ -1069,7 +1067,6 @@ static int igt_handle_error(void *arg) __func__, rq->fence.seqno, hws_seqno(&h, rq)); intel_engine_dump(rq->engine, &p, "%s\n", rq->engine->name); - i915_reset(i915, 0); i915_gem_set_wedged(i915); err = -EIO; @@ -1084,7 +1081,7 @@ static int igt_handle_error(void *arg) engine->hangcheck.stalled = true; engine->hangcheck.seqno = intel_engine_get_seqno(engine); - i915_handle_error(i915, intel_engine_flag(engine), "%s", __func__); + i915_handle_error(i915, intel_engine_flag(engine), 0, NULL); xchg(&i915->gpu_error.first_error, error); -- cgit v1.2.3 From 8b5eb5e2b5d2ddf9185e55669f22ea87d28f4e90 Mon Sep 17 00:00:00 2001 From: Kelvin Gardiner Date: Tue, 20 Mar 2018 12:45:21 -0700 Subject: drm/i915/icl: Added ICL 11 slice, subslice and EU fuse detection This patch adds support to detect ICL, slice, subslice and EU fuse settings. Add addresses for ICL 11 slice, subslice and EU fuses registers. These register addresses are the same as previous platforms but the format and / or the meaning of the information is different. Therefore Gen11 defines for these registers are added. Bspec: 9731 Bspec: 20643 Bspec: 20673 v2: Update fusing information storage after introducing the new query uAPI (Lionel) v3 (Oscar): - The maximum number of slices in ICL 11 is 1 - The subslice disable fuse can potentially store information in all bits - GEN_MAX_SUBSLICES has to be increased to 8 - Don't trust the slice enabled fuse outside the max number of expected slices - Indentation fix and some reordering and renaming of local variables v4: Use single space after Cc tag Cc: Mika Kuoppala Signed-off-by: Kelvin Gardiner Signed-off-by: Lionel Landwerlin Signed-off-by: Oscar Mateo Reviewed-by: Lionel Landwerlin Signed-off-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/1521575121-9577-1-git-send-email-oscar.mateo@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 8 ++++++ drivers/gpu/drm/i915/intel_device_info.c | 43 +++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_device_info.h | 2 +- 3 files changed, 51 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 699292eae02e..bac3e926583a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2554,6 +2554,14 @@ enum i915_power_well_id { #define GEN11_GT_VEBOX_DISABLE_SHIFT 16 #define GEN11_GT_VEBOX_DISABLE_MASK (0xff << GEN11_GT_VEBOX_DISABLE_SHIFT) +#define GEN11_EU_DISABLE _MMIO(0x9134) +#define GEN11_EU_DIS_MASK 0xFF + +#define GEN11_GT_SLICE_ENABLE _MMIO(0x9138) +#define GEN11_GT_S_ENA_MASK 0xFF + +#define GEN11_GT_SUBSLICE_DISABLE _MMIO(0x913C) + #define GEN6_BSD_SLEEP_PSMI_CONTROL _MMIO(0x12050) #define GEN6_BSD_SLEEP_MSG_DISABLE (1 << 0) #define GEN6_BSD_SLEEP_FLUSH_DISABLE (1 << 2) diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 4babfc6ee45b..a504281e2afa 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -158,6 +158,45 @@ static u16 compute_eu_total(const struct sseu_dev_info *sseu) return total; } +static void gen11_sseu_info_init(struct drm_i915_private *dev_priv) +{ + struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu; + u8 s_en; + u32 ss_en, ss_en_mask; + u8 eu_en; + int s; + + sseu->max_slices = 1; + sseu->max_subslices = 8; + sseu->max_eus_per_subslice = 8; + + s_en = I915_READ(GEN11_GT_SLICE_ENABLE) & GEN11_GT_S_ENA_MASK; + ss_en = ~I915_READ(GEN11_GT_SUBSLICE_DISABLE); + ss_en_mask = BIT(sseu->max_subslices) - 1; + eu_en = ~(I915_READ(GEN11_EU_DISABLE) & GEN11_EU_DIS_MASK); + + for (s = 0; s < sseu->max_slices; s++) { + if (s_en & BIT(s)) { + int ss_idx = sseu->max_subslices * s; + int ss; + + sseu->slice_mask |= BIT(s); + sseu->subslice_mask[s] = (ss_en >> ss_idx) & ss_en_mask; + for (ss = 0; ss < sseu->max_subslices; ss++) { + if (sseu->subslice_mask[s] & BIT(ss)) + sseu_set_eus(sseu, s, ss, eu_en); + } + } + } + sseu->eu_per_subslice = hweight8(eu_en); + sseu->eu_total = compute_eu_total(sseu); + + /* ICL has no power gating restrictions. */ + sseu->has_slice_pg = 1; + sseu->has_subslice_pg = 1; + sseu->has_eu_pg = 1; +} + static void gen10_sseu_info_init(struct drm_i915_private *dev_priv) { struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu; @@ -768,8 +807,10 @@ void intel_device_info_runtime_init(struct intel_device_info *info) broadwell_sseu_info_init(dev_priv); else if (INTEL_GEN(dev_priv) == 9) gen9_sseu_info_init(dev_priv); - else if (INTEL_GEN(dev_priv) >= 10) + else if (INTEL_GEN(dev_priv) == 10) gen10_sseu_info_init(dev_priv); + else if (INTEL_INFO(dev_priv)->gen >= 11) + gen11_sseu_info_init(dev_priv); /* Initialize command stream timestamp frequency */ info->cs_timestamp_frequency_khz = read_timestamp_frequency(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index 0cbb92223013..933e31669557 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -114,7 +114,7 @@ enum intel_platform { func(has_ipc); #define GEN_MAX_SLICES (6) /* CNL upper bound */ -#define GEN_MAX_SUBSLICES (7) +#define GEN_MAX_SUBSLICES (8) /* ICL upper bound */ struct sseu_dev_info { u8 slice_mask; -- cgit v1.2.3 From fa265275910f9d2396f8656317196c830878bd40 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Wed, 14 Mar 2018 20:04:29 +0000 Subject: drm/i915/huc: Check HuC status in dedicated function We try to keep all HuC related code in dedicated file. There is no need to peek HuC register directly during handling getparam ioctl. Signed-off-by: Michal Wajdeczko Cc: Michel Thierry Cc: Rodrigo Vivi Cc: Anusha Srivatsa Reviewed-by: Michel Thierry Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180314200429.40132-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 6 +++--- drivers/gpu/drm/i915/intel_huc.c | 25 +++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_huc.h | 1 + 3 files changed, 29 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 3f637ab89e51..a7d3275f45d2 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -377,9 +377,9 @@ static int i915_getparam_ioctl(struct drm_device *dev, void *data, value = INTEL_INFO(dev_priv)->sseu.min_eu_in_pool; break; case I915_PARAM_HUC_STATUS: - intel_runtime_pm_get(dev_priv); - value = I915_READ(HUC_STATUS2) & HUC_FW_VERIFIED; - intel_runtime_pm_put(dev_priv); + value = intel_huc_check_status(&dev_priv->huc); + if (value < 0) + return value; break; case I915_PARAM_MMAP_GTT_VERSION: /* Though we've started our numbering from 1, and so class all diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c index 1d6c47b17935..291285277403 100644 --- a/drivers/gpu/drm/i915/intel_huc.c +++ b/drivers/gpu/drm/i915/intel_huc.c @@ -92,3 +92,28 @@ fail: DRM_ERROR("HuC: Authentication failed %d\n", ret); return ret; } + +/** + * intel_huc_check_status() - check HuC status + * @huc: intel_huc structure + * + * This function reads status register to verify if HuC + * firmware was successfully loaded. + * + * Returns positive value if HuC firmware is loaded and verified + * and -ENODEV if HuC is not present. + */ +int intel_huc_check_status(struct intel_huc *huc) +{ + struct drm_i915_private *dev_priv = huc_to_i915(huc); + u32 status; + + if (!HAS_HUC(dev_priv)) + return -ENODEV; + + intel_runtime_pm_get(dev_priv); + status = I915_READ(HUC_STATUS2) & HUC_FW_VERIFIED; + intel_runtime_pm_put(dev_priv); + + return status; +} diff --git a/drivers/gpu/drm/i915/intel_huc.h b/drivers/gpu/drm/i915/intel_huc.h index b1858503c451..aa854907abac 100644 --- a/drivers/gpu/drm/i915/intel_huc.h +++ b/drivers/gpu/drm/i915/intel_huc.h @@ -37,6 +37,7 @@ struct intel_huc { void intel_huc_init_early(struct intel_huc *huc); int intel_huc_auth(struct intel_huc *huc); +int intel_huc_check_status(struct intel_huc *huc); static inline int intel_huc_sanitize(struct intel_huc *huc) { -- cgit v1.2.3 From 7beae44d7b295323d8416526fd612ee166851baf Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Tue, 20 Mar 2018 18:14:17 +0000 Subject: drm/i915/guc: Unify naming of private GuC action functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We should avoid using guc_log prefix for functions that don't operate on GuC log, but rather request action from the GuC. Better to use guc_action prefix. v2: rebase + naming compromise v3: rebase Signed-off-by: Michal Wajdeczko Cc: Michal Winiarski Cc: Sagar Arun Kamble Reviewed-by: Michał Winiarski Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180320181419.35576-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc_log.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index ae9b2569adab..957f7edc8ead 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -38,7 +38,7 @@ static void guc_log_capture_logs(struct intel_guc_log *log); * registers value. */ -static int guc_log_flush_complete(struct intel_guc *guc) +static int guc_action_flush_log_complete(struct intel_guc *guc) { u32 action[] = { INTEL_GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE @@ -47,7 +47,7 @@ static int guc_log_flush_complete(struct intel_guc *guc) return intel_guc_send(guc, action, ARRAY_SIZE(action)); } -static int guc_log_flush(struct intel_guc *guc) +static int guc_action_flush_log(struct intel_guc *guc) { u32 action[] = { INTEL_GUC_ACTION_FORCE_LOG_BUFFER_FLUSH, @@ -57,8 +57,8 @@ 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, bool enable, - bool default_logging, u32 verbosity) +static int guc_action_control_log(struct intel_guc *guc, bool enable, + bool default_logging, u32 verbosity) { union guc_log_control control_val = { { @@ -449,7 +449,7 @@ static void guc_log_capture_logs(struct intel_guc_log *log) * time, so get/put should be really quick. */ intel_runtime_pm_get(dev_priv); - guc_log_flush_complete(guc); + guc_action_flush_log_complete(guc); intel_runtime_pm_put(dev_priv); } @@ -526,9 +526,9 @@ int intel_guc_log_level_set(struct intel_guc_log *log, u64 val) } intel_runtime_pm_get(dev_priv); - ret = guc_log_control(guc, GUC_LOG_LEVEL_IS_VERBOSE(val), - GUC_LOG_LEVEL_IS_ENABLED(val), - GUC_LOG_LEVEL_TO_VERBOSITY(val)); + ret = guc_action_control_log(guc, GUC_LOG_LEVEL_IS_VERBOSE(val), + GUC_LOG_LEVEL_IS_ENABLED(val), + GUC_LOG_LEVEL_TO_VERBOSITY(val)); intel_runtime_pm_put(dev_priv); if (ret) { DRM_DEBUG_DRIVER("guc_log_control action failed %d\n", ret); @@ -610,7 +610,7 @@ void intel_guc_log_relay_flush(struct intel_guc_log *log) flush_work(&log->relay.flush_work); intel_runtime_pm_get(i915); - guc_log_flush(guc); + guc_action_flush_log(guc); intel_runtime_pm_put(i915); /* GuC would have updated log buffer by now, so capture it */ -- cgit v1.2.3 From 154374c331b01acbaf6a6957a7f9e65192f6a459 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Tue, 20 Mar 2018 18:14:18 +0000 Subject: drm/i915/guc: Drop union guc_log_control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Usually we use shift/mask macros for bit field definitions. Union guc_log_control was not following that pattern. Additional bonus: add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-25 (-25) Function old new delta intel_guc_log_level_set 388 363 -25 v2: prevent out-of-range verbosity (MichalWi) Signed-off-by: Michal Wajdeczko Cc: Michal Winiarski Cc: Sagar Arun Kamble Reviewed-by: MichaĹ Winiarski Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180320181419.35576-2-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc_fwif.h | 16 +++++----------- drivers/gpu/drm/i915/intel_guc_log.c | 13 +++++-------- 2 files changed, 10 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h index 4971685a2ea8..72941bd704fd 100644 --- a/drivers/gpu/drm/i915/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -534,17 +534,6 @@ struct guc_log_buffer_state { u32 version; } __packed; -union guc_log_control { - struct { - u32 logging_enabled:1; - u32 reserved1:3; - u32 verbosity:4; - u32 default_logging:1; - u32 reserved2:23; - }; - u32 value; -} __packed; - struct guc_ctx_report { u32 report_return_status; u32 reserved1[64]; @@ -603,6 +592,11 @@ enum intel_guc_report_status { INTEL_GUC_REPORT_STATUS_COMPLETE = 0x4, }; +#define GUC_LOG_CONTROL_LOGGING_ENABLED (1 << 0) +#define GUC_LOG_CONTROL_VERBOSITY_SHIFT 4 +#define GUC_LOG_CONTROL_VERBOSITY_MASK (0xF << GUC_LOG_CONTROL_VERBOSITY_SHIFT) +#define GUC_LOG_CONTROL_DEFAULT_LOGGING (1 << 8) + /* * The GuC sends its response to a command by overwriting the * command in SS0. The response is distinguishable from a command diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 957f7edc8ead..188d390e2099 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -60,18 +60,15 @@ static int guc_action_flush_log(struct intel_guc *guc) static int guc_action_control_log(struct intel_guc *guc, bool enable, bool default_logging, u32 verbosity) { - union guc_log_control control_val = { - { - .logging_enabled = enable, - .verbosity = verbosity, - .default_logging = default_logging, - }, - }; u32 action[] = { INTEL_GUC_ACTION_UK_LOG_ENABLE_LOGGING, - control_val.value + (enable ? GUC_LOG_CONTROL_LOGGING_ENABLED : 0) | + (verbosity << GUC_LOG_CONTROL_VERBOSITY_SHIFT) | + (default_logging ? GUC_LOG_CONTROL_DEFAULT_LOGGING : 0) }; + GEM_BUG_ON(verbosity > GUC_LOG_VERBOSITY_MAX); + return intel_guc_send(guc, action, ARRAY_SIZE(action)); } -- cgit v1.2.3 From bc598425eb18d40a18f18d67f7c460189c43a3af Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Tue, 20 Mar 2018 18:14:19 +0000 Subject: drm/i915/guc: Move enable/disable msg functions to GuC header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While today we are modifying GuC enabled msg mask only in GuC log, this code should be defined as generic GuC to allow future code reuse. Signed-off-by: Michal Wajdeczko Cc: Michal Winiarski Cc: Sagar Arun Kamble Cc: Chris Wilson Reviewed-by: Michał Winiarski Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180320181419.35576-3-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc.h | 14 ++++++++++++++ drivers/gpu/drm/i915/intel_guc_log.c | 26 ++++++++++++-------------- 2 files changed, 26 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 9a95d1518aa9..13f3d1dbf38d 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -155,4 +155,18 @@ static inline int intel_guc_sanitize(struct intel_guc *guc) return 0; } +static inline void intel_guc_enable_msg(struct intel_guc *guc, u32 mask) +{ + spin_lock_irq(&guc->irq_lock); + guc->msg_enabled_mask |= mask; + spin_unlock_irq(&guc->irq_lock); +} + +static inline void intel_guc_disable_msg(struct intel_guc *guc, u32 mask) +{ + spin_lock_irq(&guc->irq_lock); + guc->msg_enabled_mask &= ~mask; + spin_unlock_irq(&guc->irq_lock); +} + #endif diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 188d390e2099..a401f7e72c14 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -72,25 +72,23 @@ static int guc_action_control_log(struct intel_guc *guc, bool enable, return intel_guc_send(guc, action, ARRAY_SIZE(action)); } -static void guc_flush_log_msg_enable(struct intel_guc *guc) +static inline struct intel_guc *log_to_guc(struct intel_guc_log *log) { - spin_lock_irq(&guc->irq_lock); - guc->msg_enabled_mask |= INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER | - INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED; - spin_unlock_irq(&guc->irq_lock); + return container_of(log, struct intel_guc, log); } -static void guc_flush_log_msg_disable(struct intel_guc *guc) +static void guc_log_enable_flush_events(struct intel_guc_log *log) { - spin_lock_irq(&guc->irq_lock); - guc->msg_enabled_mask &= ~(INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER | - INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED); - spin_unlock_irq(&guc->irq_lock); + intel_guc_enable_msg(log_to_guc(log), + INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER | + INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED); } -static inline struct intel_guc *log_to_guc(struct intel_guc_log *log) +static void guc_log_disable_flush_events(struct intel_guc_log *log) { - return container_of(log, struct intel_guc, log); + intel_guc_disable_msg(log_to_guc(log), + INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER | + INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED); } /* @@ -576,7 +574,7 @@ int intel_guc_log_relay_open(struct intel_guc_log *log) mutex_unlock(&log->relay.lock); - guc_flush_log_msg_enable(log_to_guc(log)); + guc_log_enable_flush_events(log); /* * When GuC is logging without us relaying to userspace, we're ignoring @@ -616,7 +614,7 @@ void intel_guc_log_relay_flush(struct intel_guc_log *log) void intel_guc_log_relay_close(struct intel_guc_log *log) { - guc_flush_log_msg_disable(log_to_guc(log)); + guc_log_disable_flush_events(log); flush_work(&log->relay.flush_work); mutex_lock(&log->relay.lock); -- cgit v1.2.3 From e9c7e651798b340a175e18fc70ba41c7008d0760 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 19 Mar 2018 12:50:49 +0000 Subject: drm/i915/guc: Handle GuC log flush event in dedicated function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already try to keep all GuC log related code in separate file, handling flush event should be placed there too. This will also allow future code reuse. v2: rebased Signed-off-by: Michal Wajdeczko Cc: Michal Winiarski Cc: Sagar Arun Kamble Cc: Chris Wilson Cc: Oscar Mateo Reviewed-by: Michał Winiarski Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180319125049.48932-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 3 +-- drivers/gpu/drm/i915/intel_guc_log.c | 5 +++++ drivers/gpu/drm/i915/intel_guc_log.h | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 4b7c9c6415dd..8f93f5bef8fd 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -398,8 +398,7 @@ void intel_guc_to_host_event_handler(struct intel_guc *guc) if (msg & (INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER | INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED)) - queue_work(guc->log.relay.flush_wq, - &guc->log.relay.flush_work); + intel_guc_log_handle_flush_event(&guc->log); } int intel_guc_sample_forcewake(struct intel_guc *guc) diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index a401f7e72c14..401e1704d61e 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -623,3 +623,8 @@ void intel_guc_log_relay_close(struct intel_guc_log *log) guc_log_relay_destroy(log); mutex_unlock(&log->relay.lock); } + +void intel_guc_log_handle_flush_event(struct intel_guc_log *log) +{ + queue_work(log->relay.flush_wq, &log->relay.flush_work); +} diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index 1b0d2fa4c0b6..fa80535a6f9d 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -87,4 +87,6 @@ int intel_guc_log_relay_open(struct intel_guc_log *log); void intel_guc_log_relay_flush(struct intel_guc_log *log); void intel_guc_log_relay_close(struct intel_guc_log *log); +void intel_guc_log_handle_flush_event(struct intel_guc_log *log); + #endif -- cgit v1.2.3 From d871bfd0089f50e3010f361e804d290abe67119c Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Tue, 20 Mar 2018 16:20:20 +0000 Subject: drm/i915/guc: Unify parameters of public CT functions There is no need to mix parameter types in public CT functions as we can always accept intel_guc_ct. v2: fix 'Return' doc, s/dev_priv/i915 (Sagar) Signed-off-by: Michal Wajdeczko Cc: Sagar Arun Kamble Cc: Chris Wilson Reviewed-by: Sagar Arun Kamble Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180320162020.38672-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc_ct.c | 41 ++++++++++++++++++++++++------------- drivers/gpu/drm/i915/intel_guc_ct.h | 6 ++---- drivers/gpu/drm/i915/intel_uc.c | 4 ++-- 3 files changed, 31 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index 0a0d3d523c23..a726283489d1 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -28,12 +28,21 @@ enum { CTB_SEND = 0, CTB_RECV = 1 }; enum { CTB_OWNER_HOST = 0 }; +/** + * intel_guc_ct_init_early - Initialize CT state without requiring device access + * @ct: pointer to CT struct + */ void intel_guc_ct_init_early(struct intel_guc_ct *ct) { /* we're using static channel owners */ ct->host_channel.owner = CTB_OWNER_HOST; } +static inline struct intel_guc *ct_to_guc(struct intel_guc_ct *ct) +{ + return container_of(ct, struct intel_guc, ct); +} + static inline const char *guc_ct_buffer_type_to_str(u32 type) { switch (type) { @@ -416,19 +425,21 @@ static int intel_guc_send_ct(struct intel_guc *guc, const u32 *action, u32 len) } /** - * Enable buffer based command transport + * intel_guc_ct_enable - Enable buffer based command transport. + * @ct: pointer to CT struct + * * Shall only be called for platforms with HAS_GUC_CT. - * @guc: the guc - * return: 0 on success - * non-zero on failure + * + * Return: 0 on success, a negative errno code on failure. */ -int intel_guc_enable_ct(struct intel_guc *guc) +int intel_guc_ct_enable(struct intel_guc_ct *ct) { - struct drm_i915_private *dev_priv = guc_to_i915(guc); - struct intel_guc_ct_channel *ctch = &guc->ct.host_channel; + struct intel_guc *guc = ct_to_guc(ct); + struct drm_i915_private *i915 = guc_to_i915(guc); + struct intel_guc_ct_channel *ctch = &ct->host_channel; int err; - GEM_BUG_ON(!HAS_GUC_CT(dev_priv)); + GEM_BUG_ON(!HAS_GUC_CT(i915)); err = ctch_open(guc, ctch); if (unlikely(err)) @@ -441,16 +452,18 @@ int intel_guc_enable_ct(struct intel_guc *guc) } /** - * Disable buffer based command transport. + * intel_guc_ct_disable - Disable buffer based command transport. + * @ct: pointer to CT struct + * * Shall only be called for platforms with HAS_GUC_CT. - * @guc: the guc */ -void intel_guc_disable_ct(struct intel_guc *guc) +void intel_guc_ct_disable(struct intel_guc_ct *ct) { - struct drm_i915_private *dev_priv = guc_to_i915(guc); - struct intel_guc_ct_channel *ctch = &guc->ct.host_channel; + struct intel_guc *guc = ct_to_guc(ct); + struct drm_i915_private *i915 = guc_to_i915(guc); + struct intel_guc_ct_channel *ctch = &ct->host_channel; - GEM_BUG_ON(!HAS_GUC_CT(dev_priv)); + GEM_BUG_ON(!HAS_GUC_CT(i915)); if (!ctch_is_open(ctch)) return; diff --git a/drivers/gpu/drm/i915/intel_guc_ct.h b/drivers/gpu/drm/i915/intel_guc_ct.h index 6d97f36fcc62..595c8ad5bd4a 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.h +++ b/drivers/gpu/drm/i915/intel_guc_ct.h @@ -78,9 +78,7 @@ struct intel_guc_ct { }; void intel_guc_ct_init_early(struct intel_guc_ct *ct); - -/* XXX: move to intel_uc.h ? don't fit there either */ -int intel_guc_enable_ct(struct intel_guc *guc); -void intel_guc_disable_ct(struct intel_guc *guc); +int intel_guc_ct_enable(struct intel_guc_ct *ct); +void intel_guc_ct_disable(struct intel_guc_ct *ct); #endif /* _INTEL_GUC_CT_H_ */ diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 2befcafbaabe..34f8a2c219d8 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -231,7 +231,7 @@ static int guc_enable_communication(struct intel_guc *guc) gen9_enable_guc_interrupts(dev_priv); if (HAS_GUC_CT(dev_priv)) - return intel_guc_enable_ct(guc); + return intel_guc_ct_enable(&guc->ct); guc->send = intel_guc_send_mmio; return 0; @@ -242,7 +242,7 @@ static void guc_disable_communication(struct intel_guc *guc) struct drm_i915_private *dev_priv = guc_to_i915(guc); if (HAS_GUC_CT(dev_priv)) - intel_guc_disable_ct(guc); + intel_guc_ct_disable(&guc->ct); gen9_disable_guc_interrupts(dev_priv); -- cgit v1.2.3 From 9153e6b7c85edbc89e874e5c83f86217c53dcfaf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 21 Mar 2018 09:10:27 +0000 Subject: drm/i915/execlists: Use a locked clear_bit() for synchronisation with interrupt We were relying on the uncached reads when processing the CSB to provide ourselves with the serialisation with the interrupt handler (so we could detect new interrupts in the middle of processing the old one). However, in commit 767a983ab255 ("drm/i915/execlists: Read the context-status HEAD from the HWSP") those uncached reads were eliminated (on one path at least) and along with them our serialisation. The result is that we would very rarely miss notification of a new interrupt and leave a context-switch unprocessed, hanging the GPU. Fixes: 767a983ab255 ("drm/i915/execlists: Read the context-status HEAD from the HWSP") Signed-off-by: Chris Wilson Cc: Michel Thierry Cc: Tvrtko Ursulin Cc: Mika Kuoppala Reviewed-by: Tvrtko Ursulin Reviewed-by: Mika Kuoppala Reviewed-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180321091027.21034-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 53f1c009ed7b..67b6a0f658d6 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -831,7 +831,8 @@ static void execlists_submission_tasklet(unsigned long data) struct drm_i915_private *dev_priv = engine->i915; bool fw = false; - /* We can skip acquiring intel_runtime_pm_get() here as it was taken + /* + * 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 * not be relinquished until the device is idle (see * i915_gem_idle_work_handler()). As a precaution, we make sure @@ -840,7 +841,8 @@ static void execlists_submission_tasklet(unsigned long data) */ GEM_BUG_ON(!dev_priv->gt.awake); - /* Prefer doing test_and_clear_bit() as a two stage operation to avoid + /* + * 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). */ @@ -856,17 +858,10 @@ static void execlists_submission_tasklet(unsigned long data) execlists->csb_head = -1; /* force mmio read of CSB ptrs */ } - /* The write will be ordered by the uncached read (itself - * a memory barrier), so we do not need another in the form - * of a locked instruction. The race between the interrupt - * handler and the split test/clear is harmless as we order - * our clear before the CSB read. If the interrupt arrived - * first between the test and the clear, we read the updated - * CSB and clear the bit. If the interrupt arrives as we read - * the CSB or later (i.e. after we had cleared the bit) the bit - * is set and we do a new loop. - */ - __clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); + /* Clear before reading to catch new interrupts */ + clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); + smp_mb__after_atomic(); + if (unlikely(execlists->csb_head == -1)) { /* following a reset */ if (!fw) { intel_uncore_forcewake_get(dev_priv, -- cgit v1.2.3 From b90eed08d8d0f07f9f08074645d4470e121ff6f5 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Mon, 12 Mar 2018 20:46:45 -0700 Subject: drm/i915/psr: Move PSR aux setup to it's own function. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Non-functional change useful for the following patch. Cc: Rodrigo Vivi Cc: José Roberto de Souza Signed-off-by: Dhinakaran Pandiyan Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180313034646.3721-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_psr.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 317cb4a12693..2c001f4fba3e 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -246,7 +246,7 @@ static i915_reg_t psr_aux_data_reg(struct drm_i915_private *dev_priv, return EDP_PSR_AUX_DATA(index); } -static void hsw_psr_enable_sink(struct intel_dp *intel_dp) +static void hsw_psr_setup_aux(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = dig_port->base.base.dev; @@ -267,6 +267,24 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp) BUILD_BUG_ON(sizeof(aux_msg) > 20); aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0); + aux_ctl_reg = psr_aux_ctl_reg(dev_priv, port); + + /* Setup AUX registers */ + for (i = 0; i < sizeof(aux_msg); i += 4) + I915_WRITE(psr_aux_data_reg(dev_priv, port, i >> 2), + intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i)); + + aux_ctl = intel_dp->get_aux_send_ctl(intel_dp, 0, sizeof(aux_msg), + aux_clock_divider); + I915_WRITE(aux_ctl_reg, aux_ctl); +} + +static void hsw_psr_enable_sink(struct intel_dp *intel_dp) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = dig_port->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + /* Enable AUX frame sync at sink */ if (dev_priv->psr.aux_frame_sync) @@ -285,16 +303,7 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp) drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, DP_PSR_ENABLE); - aux_ctl_reg = psr_aux_ctl_reg(dev_priv, port); - - /* Setup AUX registers */ - for (i = 0; i < sizeof(aux_msg); i += 4) - I915_WRITE(psr_aux_data_reg(dev_priv, port, i >> 2), - intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i)); - - aux_ctl = intel_dp->get_aux_send_ctl(intel_dp, 0, sizeof(aux_msg), - aux_clock_divider); - I915_WRITE(aux_ctl_reg, aux_ctl); + hsw_psr_setup_aux(intel_dp); } static void vlv_psr_enable_source(struct intel_dp *intel_dp, -- cgit v1.2.3 From d544e918ff132488770ab2cb6b03e2af69497d1c Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Mon, 12 Mar 2018 20:46:46 -0700 Subject: drm/i915/psr: Remove open-coded PSR AUX transactions for SKL+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HSW and BDW have SRD_AUX_{CTL, STATUS} registers that the driver needs to setup for the HW to use whenever exiting PSR. SKL+ hardware use hardcoded values for the same and do not need any registers to be setup. So, use drm_dp_dpcd_writeb() for a one-time write during PSR enable and setup the PSR aux registers on HSW and BDW for later use by HW. We also end up writing to reserved bits in SRD_AUX_CTL by reusing intel_dp->get_aux_send_ctl() for HSW and BDW, fix this. Since the AUX register setup is source side programming, move the call to enable_source() from enable_sink(). Cc: José Roberto de Souza Cc: Rodrigo Vivi Signed-off-by: Dhinakaran Pandiyan Reviewed-by: Jose Roberto de Souza Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180313034646.3721-2-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 6 +++++ drivers/gpu/drm/i915/intel_psr.c | 55 ++++++++++++++++------------------------ 2 files changed, 28 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index bac3e926583a..4e31dfff940a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3846,6 +3846,12 @@ enum { #define EDP_PSR_IDLE_FRAME_SHIFT 0 #define EDP_PSR_AUX_CTL _MMIO(dev_priv->psr_mmio_base + 0x10) +#define EDP_PSR_AUX_CTL_TIME_OUT_MASK (3 << 26) +#define EDP_PSR_AUX_CTL_MESSAGE_SIZE_MASK (0x1f << 20) +#define EDP_PSR_AUX_CTL_PRECHARGE_2US_MASK (0xf << 16) +#define EDP_PSR_AUX_CTL_ERROR_INTERRUPT (1 << 11) +#define EDP_PSR_AUX_CTL_BIT_CLOCK_2X_MASK (0x7ff) + #define EDP_PSR_AUX_DATA(i) _MMIO(dev_priv->psr_mmio_base + 0x14 + (i) * 4) /* 5 registers */ #define EDP_PSR_STATUS _MMIO(dev_priv->psr_mmio_base + 0x40) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 2c001f4fba3e..b8e083e10029 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -228,31 +228,12 @@ static void vlv_psr_enable_sink(struct intel_dp *intel_dp) DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE); } -static i915_reg_t psr_aux_ctl_reg(struct drm_i915_private *dev_priv, - enum port port) -{ - if (INTEL_GEN(dev_priv) >= 9) - return DP_AUX_CH_CTL(port); - else - return EDP_PSR_AUX_CTL; -} - -static i915_reg_t psr_aux_data_reg(struct drm_i915_private *dev_priv, - enum port port, int index) -{ - if (INTEL_GEN(dev_priv) >= 9) - return DP_AUX_CH_DATA(port, index); - else - return EDP_PSR_AUX_DATA(index); -} - static void hsw_psr_setup_aux(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = dig_port->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - uint32_t aux_clock_divider; - i915_reg_t aux_ctl_reg; + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + u32 aux_clock_divider, aux_ctl; + int i; static const uint8_t aux_msg[] = { [0] = DP_AUX_NATIVE_WRITE << 4, [1] = DP_SET_POWER >> 8, @@ -260,23 +241,25 @@ static void hsw_psr_setup_aux(struct intel_dp *intel_dp) [3] = 1 - 1, [4] = DP_SET_POWER_D0, }; - enum port port = dig_port->base.port; - u32 aux_ctl; - int i; + u32 psr_aux_mask = EDP_PSR_AUX_CTL_TIME_OUT_MASK | + EDP_PSR_AUX_CTL_MESSAGE_SIZE_MASK | + EDP_PSR_AUX_CTL_PRECHARGE_2US_MASK | + EDP_PSR_AUX_CTL_BIT_CLOCK_2X_MASK; BUILD_BUG_ON(sizeof(aux_msg) > 20); - - aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0); - aux_ctl_reg = psr_aux_ctl_reg(dev_priv, port); - - /* Setup AUX registers */ for (i = 0; i < sizeof(aux_msg); i += 4) - I915_WRITE(psr_aux_data_reg(dev_priv, port, i >> 2), + I915_WRITE(EDP_PSR_AUX_DATA(i >> 2), intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i)); + aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0); + + /* Start with bits set for DDI_AUX_CTL register */ aux_ctl = intel_dp->get_aux_send_ctl(intel_dp, 0, sizeof(aux_msg), aux_clock_divider); - I915_WRITE(aux_ctl_reg, aux_ctl); + + /* Select only valid bits for SRD_AUX_CTL */ + aux_ctl &= psr_aux_mask; + I915_WRITE(EDP_PSR_AUX_CTL, aux_ctl); } static void hsw_psr_enable_sink(struct intel_dp *intel_dp) @@ -303,7 +286,7 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp) drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, DP_PSR_ENABLE); - hsw_psr_setup_aux(intel_dp); + drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0); } static void vlv_psr_enable_source(struct intel_dp *intel_dp, @@ -599,6 +582,12 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp, psr_aux_io_power_get(intel_dp); + /* Only HSW and BDW have PSR AUX registers that need to be setup. SKL+ + * use hardcoded values PSR AUX transactions + */ + if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) + hsw_psr_setup_aux(intel_dp); + if (dev_priv->psr.psr2_support) { chicken = PSR2_VSC_ENABLE_PROG_HEADER; if (dev_priv->psr.y_cord_support) -- cgit v1.2.3 From 0e59c209f4ccf9f9d505babdb04731294e18c4ed Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2018 11:00:59 +0000 Subject: drm/i915: Fix tracing of submit seqno We pre-increment the timeline->seqno when handing it to the request, make sure the GEM_TRACE takes this into account. Otherwise, it appears that we go backwards over a preemption point: 1d..1 157681077us : __i915_request_unsubmit: vcs0 fence 75e:3 <- global_seqno 17 0d.s1 157681113us : __i915_request_submit: vcs0 fence 75e:3 -> global_seqno 16 Fixes: d9b13c4dde6c ("drm/i915: Trace GEM steps between submit and wedging") Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Tvrtko Ursulin Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180322110059.4467-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 2325886d1d55..f1b81fe4f9ab 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -501,7 +501,7 @@ void __i915_request_submit(struct i915_request *request) GEM_TRACE("%s fence %llx:%d -> global_seqno %d\n", request->engine->name, request->fence.context, request->fence.seqno, - engine->timeline->seqno); + engine->timeline->seqno + 1); GEM_BUG_ON(!irqs_disabled()); lockdep_assert_held(&engine->timeline->lock); -- cgit v1.2.3 From 4ccfee92f4b6fbbedee1eb68f110a66f03edf7c6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2018 13:10:34 +0000 Subject: drm/i915: Remove local timeline var from submit/unsubmit Both request_submit and request_unsubmit deal with transferring the request from the client's timeline onto the execution timeline and back again. As both functions deal with a pair of timeline's, using a shorthand for just one of them is slightly confusing, especially as the different functions use the shorthand for the alternate timeline. Instead, use the full version of each timeline so it should be easier to keep track of the transfer between the request/client and the engine. v2: Refactor the common lock+list_move v3: Be clear we require the other timeline list to be locked as well. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180322131034.6036-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_request.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index f1b81fe4f9ab..2314a26cd7f8 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -492,10 +492,20 @@ static u32 timeline_get_seqno(struct intel_timeline *tl) return ++tl->seqno; } +static void move_to_timeline(struct i915_request *request, + struct intel_timeline *timeline) +{ + GEM_BUG_ON(request->timeline == request->engine->timeline); + lockdep_assert_held(&request->engine->timeline->lock); + + spin_lock(&request->timeline->lock); + list_move_tail(&request->link, &timeline->requests); + spin_unlock(&request->timeline->lock); +} + void __i915_request_submit(struct i915_request *request) { struct intel_engine_cs *engine = request->engine; - struct intel_timeline *timeline; u32 seqno; GEM_TRACE("%s fence %llx:%d -> global_seqno %d\n", @@ -506,12 +516,9 @@ void __i915_request_submit(struct i915_request *request) GEM_BUG_ON(!irqs_disabled()); lockdep_assert_held(&engine->timeline->lock); - /* Transfer from per-context onto the global per-engine timeline */ - timeline = engine->timeline; - GEM_BUG_ON(timeline == request->timeline); GEM_BUG_ON(request->global_seqno); - seqno = timeline_get_seqno(timeline); + seqno = timeline_get_seqno(engine->timeline); GEM_BUG_ON(!seqno); GEM_BUG_ON(i915_seqno_passed(intel_engine_get_seqno(engine), seqno)); @@ -525,9 +532,8 @@ void __i915_request_submit(struct i915_request *request) engine->emit_breadcrumb(request, request->ring->vaddr + request->postfix); - spin_lock(&request->timeline->lock); - list_move_tail(&request->link, &timeline->requests); - spin_unlock(&request->timeline->lock); + /* Transfer from per-context onto the global per-engine timeline */ + move_to_timeline(request, engine->timeline); trace_i915_request_execute(request); @@ -550,7 +556,6 @@ void i915_request_submit(struct i915_request *request) void __i915_request_unsubmit(struct i915_request *request) { struct intel_engine_cs *engine = request->engine; - struct intel_timeline *timeline; GEM_TRACE("%s fence %llx:%d <- global_seqno %d\n", request->engine->name, @@ -578,12 +583,7 @@ void __i915_request_unsubmit(struct i915_request *request) spin_unlock(&request->lock); /* Transfer back from the global per-engine timeline to per-context */ - timeline = request->timeline; - GEM_BUG_ON(timeline == engine->timeline); - - spin_lock(&timeline->lock); - list_move(&request->link, &timeline->requests); - spin_unlock(&timeline->lock); + move_to_timeline(request, request->timeline); /* * We don't need to wake_up any waiters on request->execute, they -- cgit v1.2.3 From 0ade43909d599bdde0d60e0c79e6d73479d65ffa Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2018 07:49:08 +0000 Subject: drm/i915/selftests: Include the trace as a debug aide If we fail to reset the GPU in a timely fashion, dump the GEM trace so that we can see what operations were in flight when the GPU got stuck. v2: There's more than one timeout that deserves tracing! v3: Silence checkpatch by not even using a product at all! Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Reviewed-by: Jeff McGee Link: https://patchwork.freedesktop.org/patch/msgid/20180322074908.10838-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/intel_hangcheck.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 4372826998aa..9b235dae8dd9 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -260,8 +260,11 @@ 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); + pr_err("%pS timed out, cancelling all further testing.\n", w->symbol); + + GEM_TRACE("%pS timed out.\n", w->symbol); + GEM_TRACE_DUMP(); + i915_gem_set_wedged(w->i915); } @@ -621,9 +624,19 @@ static int active_engine(void *data) mutex_unlock(&engine->i915->drm.struct_mutex); if (old) { - i915_request_wait(old, 0, MAX_SCHEDULE_TIMEOUT); + if (i915_request_wait(old, 0, HZ) < 0) { + GEM_TRACE("%s timed out.\n", engine->name); + GEM_TRACE_DUMP(); + + i915_gem_set_wedged(engine->i915); + i915_request_put(old); + err = -EIO; + break; + } i915_request_put(old); } + + cond_resched(); } for (count = 0; count < ARRAY_SIZE(rq); count++) @@ -1126,6 +1139,10 @@ int intel_hangcheck_live_selftests(struct drm_i915_private *i915) err = i915_subtests(tests, i915); + mutex_lock(&i915->drm.struct_mutex); + flush_test(i915, I915_WAIT_LOCKED); + mutex_unlock(&i915->drm.struct_mutex); + i915_modparams.enable_hangcheck = saved_hangcheck; intel_runtime_pm_put(i915); -- cgit v1.2.3 From a90507d60763ee1067cf217614a8bb2ab43aca1a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2018 07:35:31 +0000 Subject: drm/i915/selftests: Stress resets-vs-request-priority Watch what happens if we try to reset with a queue of requests with varying priorities -- that may need reordering or preemption across the reset. v2: Tweak priorities to avoid starving the hanging thread. Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180322073533.5313-2-chris@chris-wilson.co.uk Reviewed-by: Jeff McGee --- drivers/gpu/drm/i915/selftests/intel_hangcheck.c | 189 +++++++++++++++-------- 1 file changed, 126 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 9b235dae8dd9..9e4e0ad62724 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -25,6 +25,7 @@ #include #include "../i915_selftest.h" +#include "i915_random.h" #include "mock_context.h" #include "mock_drm.h" @@ -486,6 +487,8 @@ static int __igt_reset_engine(struct drm_i915_private *i915, bool active) set_bit(I915_RESET_ENGINE + id, &i915->gpu_error.flags); do { + u32 seqno = intel_engine_get_seqno(engine); + if (active) { struct i915_request *rq; @@ -514,12 +517,13 @@ static int __igt_reset_engine(struct drm_i915_private *i915, bool active) break; } + GEM_BUG_ON(!rq->global_seqno); + seqno = rq->global_seqno - 1; i915_request_put(rq); } engine->hangcheck.stalled = true; - engine->hangcheck.seqno = - intel_engine_get_seqno(engine); + engine->hangcheck.seqno = seqno; err = i915_reset_engine(engine, NULL); if (err) { @@ -576,11 +580,25 @@ static int igt_reset_active_engine(void *arg) return __igt_reset_engine(arg, true); } +struct active_engine { + struct task_struct *task; + struct intel_engine_cs *engine; + unsigned long resets; + unsigned int flags; +}; + +#define TEST_ACTIVE BIT(0) +#define TEST_OTHERS BIT(1) +#define TEST_SELF BIT(2) +#define TEST_PRIORITY BIT(3) + static int active_engine(void *data) { - struct intel_engine_cs *engine = data; - struct i915_request *rq[2] = {}; - struct i915_gem_context *ctx[2]; + I915_RND_STATE(prng); + struct active_engine *arg = data; + struct intel_engine_cs *engine = arg->engine; + struct i915_request *rq[8] = {}; + struct i915_gem_context *ctx[ARRAY_SIZE(rq)]; struct drm_file *file; unsigned long count = 0; int err = 0; @@ -589,25 +607,20 @@ static int active_engine(void *data) if (IS_ERR(file)) return PTR_ERR(file); - mutex_lock(&engine->i915->drm.struct_mutex); - ctx[0] = live_context(engine->i915, file); - mutex_unlock(&engine->i915->drm.struct_mutex); - if (IS_ERR(ctx[0])) { - err = PTR_ERR(ctx[0]); - goto err_file; - } - - mutex_lock(&engine->i915->drm.struct_mutex); - ctx[1] = live_context(engine->i915, file); - mutex_unlock(&engine->i915->drm.struct_mutex); - if (IS_ERR(ctx[1])) { - err = PTR_ERR(ctx[1]); - i915_gem_context_put(ctx[0]); - goto err_file; + for (count = 0; count < ARRAY_SIZE(ctx); count++) { + mutex_lock(&engine->i915->drm.struct_mutex); + ctx[count] = live_context(engine->i915, file); + mutex_unlock(&engine->i915->drm.struct_mutex); + if (IS_ERR(ctx[count])) { + err = PTR_ERR(ctx[count]); + while (--count) + i915_gem_context_put(ctx[count]); + goto err_file; + } } while (!kthread_should_stop()) { - unsigned int idx = count++ & 1; + unsigned int idx = count++ & (ARRAY_SIZE(rq) - 1); struct i915_request *old = rq[idx]; struct i915_request *new; @@ -619,6 +632,10 @@ static int active_engine(void *data) break; } + if (arg->flags & TEST_PRIORITY) + ctx[idx]->priority = + i915_prandom_u32_max_state(512, &prng); + rq[idx] = i915_request_get(new); i915_request_add(new); mutex_unlock(&engine->i915->drm.struct_mutex); @@ -647,8 +664,9 @@ err_file: return err; } -static int __igt_reset_engine_others(struct drm_i915_private *i915, - bool active) +static int __igt_reset_engines(struct drm_i915_private *i915, + const char *test_name, + unsigned int flags) { struct intel_engine_cs *engine, *other; enum intel_engine_id id, tmp; @@ -662,50 +680,61 @@ static int __igt_reset_engine_others(struct drm_i915_private *i915, if (!intel_has_reset_engine(i915)) return 0; - if (active) { + if (flags & TEST_ACTIVE) { mutex_lock(&i915->drm.struct_mutex); err = hang_init(&h, i915); mutex_unlock(&i915->drm.struct_mutex); if (err) return err; + + if (flags & TEST_PRIORITY) + h.ctx->priority = 1024; } for_each_engine(engine, i915, id) { - struct task_struct *threads[I915_NUM_ENGINES] = {}; - unsigned long resets[I915_NUM_ENGINES]; + struct active_engine threads[I915_NUM_ENGINES] = {}; unsigned long global = i915_reset_count(&i915->gpu_error); - unsigned long count = 0; + unsigned long count = 0, reported; IGT_TIMEOUT(end_time); - if (active && !intel_engine_can_store_dword(engine)) + if (flags & TEST_ACTIVE && + !intel_engine_can_store_dword(engine)) continue; memset(threads, 0, sizeof(threads)); for_each_engine(other, i915, tmp) { struct task_struct *tsk; - resets[tmp] = i915_reset_engine_count(&i915->gpu_error, - other); + threads[tmp].resets = + i915_reset_engine_count(&i915->gpu_error, + other); - if (other == engine) + if (!(flags & TEST_OTHERS)) continue; - tsk = kthread_run(active_engine, other, + if (other == engine && !(flags & TEST_SELF)) + continue; + + threads[tmp].engine = other; + threads[tmp].flags = flags; + + tsk = kthread_run(active_engine, &threads[tmp], "igt/%s", other->name); if (IS_ERR(tsk)) { err = PTR_ERR(tsk); goto unwind; } - threads[tmp] = tsk; + threads[tmp].task = tsk; get_task_struct(tsk); } set_bit(I915_RESET_ENGINE + id, &i915->gpu_error.flags); do { - if (active) { - struct i915_request *rq; + u32 seqno = intel_engine_get_seqno(engine); + struct i915_request *rq = NULL; + if (flags & TEST_ACTIVE) { mutex_lock(&i915->drm.struct_mutex); rq = hang_create_request(&h, engine); if (IS_ERR(rq)) { @@ -731,33 +760,38 @@ static int __igt_reset_engine_others(struct drm_i915_private *i915, break; } - i915_request_put(rq); + GEM_BUG_ON(!rq->global_seqno); + seqno = rq->global_seqno - 1; } engine->hangcheck.stalled = true; - engine->hangcheck.seqno = - intel_engine_get_seqno(engine); + engine->hangcheck.seqno = seqno; err = i915_reset_engine(engine, NULL); if (err) { - pr_err("i915_reset_engine(%s:%s) failed, err=%d\n", - engine->name, active ? "active" : "idle", err); + pr_err("i915_reset_engine(%s:%s): failed, err=%d\n", + engine->name, test_name, err); break; } engine->hangcheck.stalled = false; count++; + + if (rq) { + i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT); + i915_request_put(rq); + } } while (time_before(jiffies, end_time)); clear_bit(I915_RESET_ENGINE + id, &i915->gpu_error.flags); pr_info("i915_reset_engine(%s:%s): %lu resets\n", - engine->name, active ? "active" : "idle", count); - - if (i915_reset_engine_count(&i915->gpu_error, engine) - - resets[engine->id] != (active ? count : 0)) { - pr_err("i915_reset_engine(%s:%s): reset %lu times, but reported %lu\n", - engine->name, active ? "active" : "idle", count, - i915_reset_engine_count(&i915->gpu_error, - engine) - resets[engine->id]); + engine->name, test_name, count); + + reported = i915_reset_engine_count(&i915->gpu_error, engine); + reported -= threads[engine->id].resets; + if (reported != (flags & TEST_ACTIVE ? count : 0)) { + pr_err("i915_reset_engine(%s:%s): reset %lu times, but reported %lu, expected %lu reported\n", + engine->name, test_name, count, reported, + (flags & TEST_ACTIVE ? count : 0)); if (!err) err = -EINVAL; } @@ -766,24 +800,26 @@ unwind: for_each_engine(other, i915, tmp) { int ret; - if (!threads[tmp]) + if (!threads[tmp].task) continue; - ret = kthread_stop(threads[tmp]); + ret = kthread_stop(threads[tmp].task); if (ret) { pr_err("kthread for other engine %s failed, err=%d\n", other->name, ret); if (!err) err = ret; } - put_task_struct(threads[tmp]); + put_task_struct(threads[tmp].task); - if (resets[tmp] != i915_reset_engine_count(&i915->gpu_error, - other)) { + if (other != engine && + threads[tmp].resets != + i915_reset_engine_count(&i915->gpu_error, other)) { pr_err("Innocent engine %s was reset (count=%ld)\n", other->name, i915_reset_engine_count(&i915->gpu_error, - other) - resets[tmp]); + other) - + threads[tmp].resets); if (!err) err = -EINVAL; } @@ -807,7 +843,7 @@ unwind: if (i915_terminally_wedged(&i915->gpu_error)) err = -EIO; - if (active) { + if (flags & TEST_ACTIVE) { mutex_lock(&i915->drm.struct_mutex); hang_fini(&h); mutex_unlock(&i915->drm.struct_mutex); @@ -816,14 +852,42 @@ unwind: return err; } -static int igt_reset_idle_engine_others(void *arg) +static int igt_reset_engines(void *arg) { - return __igt_reset_engine_others(arg, false); -} + static const struct { + const char *name; + unsigned int flags; + } phases[] = { + { "idle", 0 }, + { "active", TEST_ACTIVE }, + { "others-idle", TEST_OTHERS }, + { "others-active", TEST_OTHERS | TEST_ACTIVE }, + { + "others-priority", + TEST_OTHERS | TEST_ACTIVE | TEST_PRIORITY + }, + { + "self-priority", + TEST_OTHERS | TEST_ACTIVE | TEST_PRIORITY | TEST_SELF, + }, + { } + }; + struct drm_i915_private *i915 = arg; + typeof(*phases) *p; + int err; -static int igt_reset_active_engine_others(void *arg) -{ - return __igt_reset_engine_others(arg, true); + for (p = phases; p->name; p++) { + if (p->flags & TEST_PRIORITY) { + if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_PRIORITY)) + continue; + } + + err = __igt_reset_engines(arg, p->name, p->flags); + if (err) + return err; + } + + return 0; } static u32 fake_hangcheck(struct i915_request *rq) @@ -1122,8 +1186,7 @@ int intel_hangcheck_live_selftests(struct drm_i915_private *i915) SUBTEST(igt_hang_sanitycheck), SUBTEST(igt_reset_idle_engine), SUBTEST(igt_reset_active_engine), - SUBTEST(igt_reset_idle_engine_others), - SUBTEST(igt_reset_active_engine_others), + SUBTEST(igt_reset_engines), SUBTEST(igt_wait_reset), SUBTEST(igt_reset_queue), SUBTEST(igt_handle_error), -- cgit v1.2.3 From 1c645bf4378f1539df57c6228f5c4957c130324a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2018 07:35:32 +0000 Subject: drm/i915: Use full serialisation around engine->irq_posted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using engine->irq_posted for execlists, we are not always serialised by the tasklet as we supposed. On the reset paths, the tasklet is disabled and ignored. Instead, we manipulate the engine->irq_posted directly to account for the reset, but if an interrupt fired before the reset and so wrote to engine->irq_posted, that write may not be flushed from the local CPU's cacheline until much later as the tasklet is already active and so does not generate a mb(). To correctly serialise the interrupt with reset, we need serialisation on the set_bit() itself. And at last Mika can be happy. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Michał Winiarski CC: Michel Thierry Cc: Jeff McGee Cc: Tvrtko Ursulin Reviewed-by: Mika Kuoppala Reviewed-by: Jeff McGee Link: https://patchwork.freedesktop.org/patch/msgid/20180322073533.5313-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_irq.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index fa7310766217..27aee25429b7 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1405,10 +1405,9 @@ gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir) bool tasklet = false; if (iir & GT_CONTEXT_SWITCH_INTERRUPT) { - if (READ_ONCE(engine->execlists.active)) { - __set_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); - tasklet = true; - } + if (READ_ONCE(engine->execlists.active)) + tasklet = !test_and_set_bit(ENGINE_IRQ_EXECLIST, + &engine->irq_posted); } if (iir & GT_RENDER_USER_INTERRUPT) { -- cgit v1.2.3 From 0f36a85c3bd5e0dfcbb49af203a96a933dae86cf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2018 07:35:33 +0000 Subject: drm/i915: Flush pending interrupt following a GPU reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After resetting the GPU (or subset of engines), call synchronize_irq() to flush any pending irq before proceeding with the cleanup. For a device level reset, we disable the interupts around the reset, but when resetting just one engine, we have to avoid such global disabling. This leaves us open to an interrupt arriving for the engine as we try to reset it. We already do try to flush the IIR following the reset, but we have to ensure that the in-flight interrupt does not land after we start cleaning up after the reset; enter synchronize_irq(). As it current stands, we very rarely, but fatally, see sequences such as: 2.... 57964564us : execlists_reset_prepare: rcs0 2.... 57964613us : execlists_reset: rcs0 seqno=424 0d.h1 57964615us : gen8_cs_irq_handler: rcs0 CS active=1 2d..1 57964617us : __i915_request_unsubmit: rcs0 fence 29:1056 <- global_seqno 1060 2.... 57964703us : execlists_reset_finish: rcs0 0..s. 57964705us : execlists_submission_tasklet: rcs0 awake?=1, active=0, irq-posted?=1 v2: Move the sync into the execlists reset handler so that we coordinate the flush with disabling the interrupt handling and canceling the pending interrupt. v3: Just use synchronize_hardirq() to avoid the might_sleep(), we do not yet have threaded-irq to worry about. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Michel Thierry Cc: Michał Winiarski Cc: Jeff McGee Link: https://patchwork.freedesktop.org/patch/msgid/20180322073533.5313-4-chris@chris-wilson.co.uk Reviewed-by: Jeff McGee --- drivers/gpu/drm/i915/intel_lrc.c | 7 ++++--- drivers/gpu/drm/i915/intel_uncore.c | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 67b6a0f658d6..ce09c5ad334f 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -805,6 +805,10 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) spin_unlock(&engine->timeline->lock); + /* Mark all CS interrupts as complete */ + smp_store_mb(execlists->active, 0); + synchronize_hardirq(engine->i915->drm.irq); + /* * The port is checked prior to scheduling a tasklet, but * just in case we have suspended the tasklet to do the @@ -813,9 +817,6 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) */ clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); - /* Mark all CS interrupts as complete */ - execlists->active = 0; - local_irq_restore(flags); } diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 4c616d074a97..f37ecfc69e49 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -2116,8 +2116,10 @@ int intel_gpu_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) i915_stop_engines(dev_priv, engine_mask); ret = -ENODEV; - if (reset) + if (reset) { + GEM_TRACE("engine_mask=%x\n", engine_mask); ret = reset(dev_priv, engine_mask); + } if (ret != -ETIMEDOUT) break; -- cgit v1.2.3 From 66c1f77ae2b773f349c1ea1312d69a6ab775cc26 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 20 Mar 2018 17:17:33 +0200 Subject: drm/i915: Avoid setting ring freq on invalid rps freqs Looping through rps frequencies when both min and max are zero ends up into an endless loop. This can happen during hardware enablement. Bail out early if rps frequencies are not correctly set yet. Cc: Chris Wilson Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180320151734.11761-1-mika.kuoppala@linux.intel.com --- drivers/gpu/drm/i915/intel_pm.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index dd5ddb77b306..19e82aaa9863 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6890,15 +6890,18 @@ static void gen6_enable_rps(struct drm_i915_private *dev_priv) static void gen6_update_ring_freq(struct drm_i915_private *dev_priv) { struct intel_rps *rps = &dev_priv->gt_pm.rps; - int min_freq = 15; + const int min_freq = 15; + const int scaling_factor = 180; unsigned int gpu_freq; unsigned int max_ia_freq, min_ring_freq; unsigned int max_gpu_freq, min_gpu_freq; - int scaling_factor = 180; struct cpufreq_policy *policy; WARN_ON(!mutex_is_locked(&dev_priv->pcu_lock)); + if (rps->max_freq <= rps->min_freq) + return; + policy = cpufreq_cpu_get(0); if (policy) { max_ia_freq = policy->cpuinfo.max_freq; @@ -6932,7 +6935,7 @@ static void gen6_update_ring_freq(struct drm_i915_private *dev_priv) * the PCU should use as a reference to determine the ring frequency. */ for (gpu_freq = max_gpu_freq; gpu_freq >= min_gpu_freq; gpu_freq--) { - int diff = max_gpu_freq - gpu_freq; + const int diff = max_gpu_freq - gpu_freq; unsigned int ia_freq = 0, ring_freq = 0; if (IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv)) { -- cgit v1.2.3 From 0ef904bb3a6d9dc2d81301e84116eaff880412f2 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 21 Mar 2018 10:32:28 +0000 Subject: drm/i915: Skip logging impossible slices Log up to sseu->max_slices instead basing on ARRAY_SIZE since to avoid printing impossible and empty slices for a platform. Also compact slice total and slice mask into one log line. Signed-off-by: Tvrtko Ursulin Cc: Lionel Landwerlin Reviewed-by: Lionel Landwerlin Link: https://patchwork.freedesktop.org/patch/msgid/20180321103228.32205-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/intel_device_info.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index a504281e2afa..0d1509e25db8 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -83,11 +83,11 @@ static void sseu_dump(const struct sseu_dev_info *sseu, struct drm_printer *p) { int s; - drm_printf(p, "slice mask: %04x\n", sseu->slice_mask); - drm_printf(p, "slice total: %u\n", hweight8(sseu->slice_mask)); + drm_printf(p, "slice total: %u, mask=%04x\n", + hweight8(sseu->slice_mask), sseu->slice_mask); drm_printf(p, "subslice total: %u\n", sseu_subslice_total(sseu)); - for (s = 0; s < ARRAY_SIZE(sseu->subslice_mask); s++) { - drm_printf(p, "slice%d %u subslices mask=%04x\n", + for (s = 0; s < sseu->max_slices; s++) { + drm_printf(p, "slice%d: %u subslices, mask=%04x\n", s, hweight8(sseu->subslice_mask[s]), sseu->subslice_mask[s]); } -- cgit v1.2.3 From 277ab5abc68df2f6f8fac7a46e50105b6648f432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 22 Mar 2018 17:47:07 +0200 Subject: drm/i915: Don't spew errors when resetting HDMI scrambling/bit clock ratio fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we're disabling the HDMI link we try to reset the scrambling and TMDS bit clock ratio back to the default values. This will fail if the sink has already been disconnected. Thus we should not print an error message when resetting the scrambling/TMDS bit clock ratio fail during disable. During enable we do want the error, and during disable we may still want to know what happended for debug purposes so let's use DRM_DEBUG_KMS() there. v2: Remember them consts v3: Go back to just one function and print the errors/debugs from callers (Shashank) Cc: Shashank Sharma Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105644 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105655 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180322154707.22103-1-ville.syrjala@linux.intel.com Reviewed-by: Shashank Sharma --- drivers/gpu/drm/i915/intel_ddi.c | 19 ++++++++++++------- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_hdmi.c | 40 ++++++++++++++++----------------------- 3 files changed, 29 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 8c2d778560f0..c449619427da 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2424,12 +2424,14 @@ static void intel_enable_ddi_hdmi(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); + struct drm_connector *connector = conn_state->connector; enum port port = encoder->port; - intel_hdmi_handle_sink_scrambling(encoder, - conn_state->connector, - crtc_state->hdmi_high_tmds_clock_ratio, - crtc_state->hdmi_scrambling); + if (!intel_hdmi_handle_sink_scrambling(encoder, connector, + crtc_state->hdmi_high_tmds_clock_ratio, + crtc_state->hdmi_scrambling)) + DRM_ERROR("[CONNECTOR:%d:%s] Failed to configure sink scrambling/TMDS bit clock ratio\n", + connector->base.id, connector->name); /* Display WA #1143: skl,kbl,cfl */ if (IS_GEN9_BC(dev_priv)) { @@ -2520,13 +2522,16 @@ static void intel_disable_ddi_hdmi(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { + struct drm_connector *connector = old_conn_state->connector; + if (old_crtc_state->has_audio) intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); - intel_hdmi_handle_sink_scrambling(encoder, - old_conn_state->connector, - false, false); + if (!intel_hdmi_handle_sink_scrambling(encoder, connector, + false, false)) + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Failed to reset sink scrambling/TMDS bit clock ratio\n", + connector->base.id, connector->name); } static void intel_disable_ddi(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index de6db9196638..b79a01b7f008 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1782,7 +1782,7 @@ struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state); -void intel_hdmi_handle_sink_scrambling(struct intel_encoder *intel_encoder, +bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder, struct drm_connector *connector, bool high_tmds_clock_ratio, bool scrambling); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 1baef4ac7ecb..ee929f31f7db 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -2082,41 +2082,33 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c * it enables scrambling. This should be called before enabling the HDMI * 2.0 port, as the sink can choose to disable the scrambling if it doesn't * detect a scrambled clock within 100 ms. + * + * Returns: + * True on success, false on failure. */ -void intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder, +bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder, struct drm_connector *connector, bool high_tmds_clock_ratio, bool scrambling) { + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); - struct drm_i915_private *dev_priv = connector->dev->dev_private; struct drm_scrambling *sink_scrambling = - &connector->display_info.hdmi.scdc.scrambling; - struct i2c_adapter *adptr = intel_gmbus_get_adapter(dev_priv, - intel_hdmi->ddc_bus); - bool ret; + &connector->display_info.hdmi.scdc.scrambling; + struct i2c_adapter *adapter = + intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); if (!sink_scrambling->supported) - return; - - DRM_DEBUG_KMS("Setting sink scrambling for enc:%s connector:%s\n", - encoder->base.name, connector->name); + return true; - /* Set TMDS bit clock ratio to 1/40 or 1/10 */ - ret = drm_scdc_set_high_tmds_clock_ratio(adptr, high_tmds_clock_ratio); - if (!ret) { - DRM_ERROR("Set TMDS ratio failed\n"); - return; - } - - /* Enable/disable sink scrambling */ - ret = drm_scdc_set_scrambling(adptr, scrambling); - if (!ret) { - DRM_ERROR("Set sink scrambling failed\n"); - return; - } + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] scrambling=%s, TMDS bit clock ratio=1/%d\n", + connector->base.id, connector->name, + yesno(scrambling), high_tmds_clock_ratio ? 40 : 10); - DRM_DEBUG_KMS("sink scrambling handled\n"); + /* Set TMDS bit clock ratio to 1/40 or 1/10, and enable/disable scrambling */ + return drm_scdc_set_high_tmds_clock_ratio(adapter, + high_tmds_clock_ratio) && + drm_scdc_set_scrambling(adapter, scrambling); } static u8 chv_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port) -- cgit v1.2.3 From 28e0e8ac27409e1f2f2abd226548f0ebeef19ad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Pi=C3=B3rkowski?= Date: Fri, 23 Mar 2018 12:23:18 +0100 Subject: drm/i915/guc: Fix null pointer dereference when GuC FW is not available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If GuC firmware is not available on the system and we load i915 with enable GuC, then we hit this null pointer dereference issue: [ 71.098873] BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 [ 71.098938] IP: intel_uc_fw_upload+0x1f/0x360 [i915] [ 71.098947] PGD 0 P4D 0 [ 71.098956] Oops: 0000 [#1] PREEMPT SMP PTI [ 71.098965] Modules linked in: i915(O+) netconsole x86_pkg_temp_thermal intel_powerclamp coretemp crct10dif_pclmul crc32_pclmul ghash_clmulni_intel mei_me i2c_i801 prime_numbers mei [last unloaded: i915] [ 71.099005] CPU: 2 PID: 1167 Comm: insmod Tainted: G U W O 4.16.0-rc1+ #337 [ 71.099018] Hardware name: /NUC6i5SYB, BIOS SYSKLi35.86A.0065.2018.0103.1000 01/03/2018 [ 71.099077] RIP: 0010:intel_uc_fw_upload+0x1f/0x360 [i915] [ 71.099087] RSP: 0018:ffffc90000417aa0 EFLAGS: 00010282 [ 71.099097] RAX: 0000000000000000 RBX: ffff88084cad12f8 RCX: ffffffffa03e9357 [ 71.099108] RDX: 0000000000000002 RSI: ffffffffa034dba0 RDI: ffff88084cad12f8 [ 71.099118] RBP: 0000000000000002 R08: ffff88085344ca90 R09: 0000000000000001 [ 71.099128] R10: 0000000000000000 R11: 0000000000000000 R12: ffff88084cad0000 [ 71.099139] R13: ffffffffa034dba0 R14: 00000000fffffff5 R15: ffff88084cad12b0 [ 71.099151] FS: 00007f7f24ae2740(0000) GS:ffff88085e200000(0000) knlGS:0000000000000000 [ 71.099162] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 71.099171] CR2: 0000000000000008 CR3: 0000000855f48001 CR4: 00000000003606e0 [ 71.099182] Call Trace: [ 71.099246] intel_uc_init_hw+0xc8/0x520 [i915] [ 71.099303] i915_gem_init_hw+0x11f/0x2d0 [i915] [ 71.099364] i915_gem_init+0x2b9/0x640 [i915] [ 71.099413] i915_driver_load+0xb74/0x1110 [i915] [ 71.099462] i915_pci_probe+0x2e/0x90 [i915] [ 71.099476] pci_device_probe+0xa1/0x130 [ 71.099488] driver_probe_device+0x302/0x470 [ 71.099502] __driver_attach+0xb9/0xe0 [ 71.099513] ? driver_probe_device+0x470/0x470 [ 71.099525] ? driver_probe_device+0x470/0x470 [ 71.099538] bus_for_each_dev+0x64/0x90 [ 71.099550] bus_add_driver+0x164/0x260 [ 71.099561] ? 0xffffffffa04d6000 [ 71.099572] driver_register+0x57/0xc0 [ 71.099582] ? 0xffffffffa04d6000 [ 71.099593] do_one_initcall+0x3b/0x160 [ 71.099606] ? kmem_cache_alloc_trace+0x1c3/0x2a0 [ 71.099621] do_init_module+0x5b/0x1f9 [ 71.099635] load_module+0x2467/0x2a70 [ 71.099654] ? SyS_finit_module+0xbd/0xe0 [ 71.099668] SyS_finit_module+0xbd/0xe0 [ 71.099682] do_syscall_64+0x73/0x1c0 [ 71.099694] entry_SYSCALL_64_after_hwframe+0x26/0x9b [ 71.099706] RIP: 0033:0x7f7f23fb40d9 [ 71.099717] RSP: 002b:00007ffda7d67ed8 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 [ 71.099734] RAX: ffffffffffffffda RBX: 000055f96e2a8870 RCX: 00007f7f23fb40d9 [ 71.099748] RDX: 0000000000000000 RSI: 000055f96e2a8260 RDI: 0000000000000003 [ 71.099763] RBP: 000055f96e2a8260 R08: 0000000000000000 R09: 00007ffda7d68088 [ 71.099777] R10: 0000000000000003 R11: 0000000000000246 R12: 0000000000000000 [ 71.099791] R13: 000055f96e2a8830 R14: 0000000000000000 R15: 000055f96e2a8260 [ 71.099810] Code: 00 00 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 41 55 41 54 49 89 f5 55 53 48 c7 c1 57 93 3e a0 48 8b 47 10 48 89 fb 4c 8b 07 <48> 8b 68 08 8b 47 28 85 c0 74 15 83 f8 01 48 c7 c1 5b 93 3e a0 [ 71.100004] RIP: intel_uc_fw_upload+0x1f/0x360 [i915] RSP: ffffc90000417aa0 [ 71.100020] CR2: 0000000000000008 [ 71.100031] ---[ end trace d8ac93c30ceff5b2 ]-- Fixes: 6b0478fb722a ("drm/i915: Implement dynamic GuC WOPCM offset and size calculation") v2: don't assume it is always GuC FW (Michal) v3: added a new variable to avoid exceeding the number of characters in the line (Michal) Signed-off-by: Piotr Piórkowski Reported-by: Radoslaw Szwichtenberg Cc: Michał Winiarski Cc: Michal Wajdeczko Cc: Sagar Arun Kamble Cc: Joonas Lahtinen Cc: Jackie Li Cc: Radoslaw Szwichtenberg Reviewed-by: Michal Wajdeczko Reviewed-by: Jackie Li Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180323112319.16293-1-piotr.piorkowski@intel.com --- drivers/gpu/drm/i915/intel_uc_fw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_uc_fw.c b/drivers/gpu/drm/i915/intel_uc_fw.c index 30c73243f54d..6e8e0b546743 100644 --- a/drivers/gpu/drm/i915/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/intel_uc_fw.c @@ -199,8 +199,8 @@ int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, int (*xfer)(struct intel_uc_fw *uc_fw, struct i915_vma *vma)) { - struct drm_i915_private *i915 = to_i915(uc_fw->obj->base.dev); struct i915_vma *vma; + u32 ggtt_pin_bias; int err; DRM_DEBUG_DRIVER("%s fw load %s\n", @@ -222,9 +222,9 @@ int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, goto fail; } + ggtt_pin_bias = to_i915(uc_fw->obj->base.dev)->guc.ggtt_pin_bias; vma = i915_gem_object_ggtt_pin(uc_fw->obj, NULL, 0, 0, - PIN_OFFSET_BIAS | - i915->guc.ggtt_pin_bias); + PIN_OFFSET_BIAS | ggtt_pin_bias); if (IS_ERR(vma)) { err = PTR_ERR(vma); DRM_DEBUG_DRIVER("%s fw ggtt-pin err=%d\n", -- cgit v1.2.3 From a0de908d44fb67500b7c45bd8325f316496227db Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 23 Mar 2018 12:34:49 +0000 Subject: drm/i915: Reorder early initialization In upcoming patch, we want to perform more actions in early initialization of the uC. This reordering will help resolve new dependencies that will be introduced by future patch. v2: s/i915_gem_load_init/i915_gem_init_early (Chris) v3: s/i915_gem_load_cleanup/i915_gem_cleanup_early (Michal) Signed-off-by: Michal Wajdeczko Cc: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180323123451.59244-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 17 ++++++++--------- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- drivers/gpu/drm/i915/i915_gem.c | 5 ++--- 3 files changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a7d3275f45d2..2561974af79c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -919,17 +919,21 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv, mutex_init(&dev_priv->wm.wm_mutex); mutex_init(&dev_priv->pps_mutex); - intel_wopcm_init_early(&dev_priv->wopcm); - intel_uc_init_early(dev_priv); i915_memcpy_init_early(dev_priv); ret = i915_workqueues_init(dev_priv); if (ret < 0) goto err_engines; + ret = i915_gem_init_early(dev_priv); + if (ret < 0) + goto err_workqueues; + /* This must be called before any calls to HAS_PCH_* */ intel_detect_pch(dev_priv); + intel_wopcm_init_early(&dev_priv->wopcm); + intel_uc_init_early(dev_priv); intel_pm_setup(dev_priv); intel_init_dpio(dev_priv); intel_power_domains_init(dev_priv); @@ -938,18 +942,13 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv, intel_init_display_hooks(dev_priv); intel_init_clock_gating_hooks(dev_priv); intel_init_audio_hooks(dev_priv); - ret = i915_gem_load_init(dev_priv); - if (ret < 0) - goto err_irq; - intel_display_crc_init(dev_priv); intel_detect_preproduction_hw(dev_priv); return 0; -err_irq: - intel_irq_fini(dev_priv); +err_workqueues: i915_workqueues_cleanup(dev_priv); err_engines: i915_engines_cleanup(dev_priv); @@ -962,8 +961,8 @@ err_engines: */ static void i915_driver_cleanup_early(struct drm_i915_private *dev_priv) { - i915_gem_load_cleanup(dev_priv); intel_irq_fini(dev_priv); + i915_gem_cleanup_early(dev_priv); i915_workqueues_cleanup(dev_priv); i915_engines_cleanup(dev_priv); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c9c3b2ba6a86..28ab91812701 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2869,8 +2869,8 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, int i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void i915_gem_sanitize(struct drm_i915_private *i915); -int i915_gem_load_init(struct drm_i915_private *dev_priv); -void i915_gem_load_cleanup(struct drm_i915_private *dev_priv); +int i915_gem_init_early(struct drm_i915_private *dev_priv); +void i915_gem_cleanup_early(struct drm_i915_private *dev_priv); void i915_gem_load_init_fences(struct drm_i915_private *dev_priv); int i915_gem_freeze(struct drm_i915_private *dev_priv); int i915_gem_freeze_late(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 802df8e1a544..9650a7b10c5f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5502,8 +5502,7 @@ static void i915_gem_init__mm(struct drm_i915_private *i915) INIT_WORK(&i915->mm.free_work, __i915_gem_free_work); } -int -i915_gem_load_init(struct drm_i915_private *dev_priv) +int i915_gem_init_early(struct drm_i915_private *dev_priv) { int err = -ENOMEM; @@ -5578,7 +5577,7 @@ err_out: return err; } -void i915_gem_load_cleanup(struct drm_i915_private *dev_priv) +void i915_gem_cleanup_early(struct drm_i915_private *dev_priv) { i915_gem_drain_freed_objects(dev_priv); GEM_BUG_ON(!llist_empty(&dev_priv->mm.free_list)); -- cgit v1.2.3 From 8c650aefb82d559aa0e1b7c0c36346b906481106 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 23 Mar 2018 12:34:50 +0000 Subject: drm/i915/uc: Fetch uC firmware in init_early We were fetching uC firmwares in separate uc_init_fw step, while there is no reason why we can't fetch them during init_early. This will also simplify upcoming patches, as size of the firmware may be used for register initialization. Signed-off-by: Michal Wajdeczko Cc: Michal Winiarski Cc: Sagar Arun Kamble Cc: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180323123451.59244-2-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 8 ++------ drivers/gpu/drm/i915/intel_guc_fw.c | 5 ++--- drivers/gpu/drm/i915/intel_huc_fw.c | 5 ++--- drivers/gpu/drm/i915/intel_uc.c | 37 ++++++++++++++++++------------------- drivers/gpu/drm/i915/intel_uc.h | 3 +-- 5 files changed, 25 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2561974af79c..db223378d84b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -692,11 +692,9 @@ static int i915_load_modeset_init(struct drm_device *dev) if (ret) goto cleanup_irq; - intel_uc_init_fw(dev_priv); - ret = i915_gem_init(dev_priv); if (ret) - goto cleanup_uc; + goto cleanup_irq; intel_setup_overlay(dev_priv); @@ -716,8 +714,6 @@ cleanup_gem: if (i915_gem_suspend(dev_priv)) DRM_ERROR("failed to idle hardware; continuing to unload!\n"); i915_gem_fini(dev_priv); -cleanup_uc: - intel_uc_fini_fw(dev_priv); cleanup_irq: drm_irq_uninstall(dev); intel_teardown_gmbus(dev_priv); @@ -962,6 +958,7 @@ err_engines: static void i915_driver_cleanup_early(struct drm_i915_private *dev_priv) { intel_irq_fini(dev_priv); + intel_uc_cleanup_early(dev_priv); i915_gem_cleanup_early(dev_priv); i915_workqueues_cleanup(dev_priv); i915_engines_cleanup(dev_priv); @@ -1457,7 +1454,6 @@ void i915_driver_unload(struct drm_device *dev) i915_reset_error_state(dev_priv); i915_gem_fini(dev_priv); - intel_uc_fini_fw(dev_priv); intel_fbc_cleanup_cfb(dev_priv); intel_power_domains_fini(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_guc_fw.c b/drivers/gpu/drm/i915/intel_guc_fw.c index 978668cf82cc..a9e6fcce467c 100644 --- a/drivers/gpu/drm/i915/intel_guc_fw.c +++ b/drivers/gpu/drm/i915/intel_guc_fw.c @@ -275,9 +275,8 @@ static int guc_fw_xfer(struct intel_uc_fw *guc_fw, struct i915_vma *vma) * Called from intel_uc_init_hw() during driver load, resume from sleep and * after a GPU reset. * - * The firmware image should have already been fetched into memory by the - * earlier call to intel_uc_init_fw(), so here we need to only check that - * fetch succeeded, and then transfer the image to the h/w. + * The firmware image should have already been fetched into memory, so only + * check that fetch succeeded, and then transfer the image to the h/w. * * Return: non-zero code on error */ diff --git a/drivers/gpu/drm/i915/intel_huc_fw.c b/drivers/gpu/drm/i915/intel_huc_fw.c index bb0f8b7a8d2b..f93d2384d482 100644 --- a/drivers/gpu/drm/i915/intel_huc_fw.c +++ b/drivers/gpu/drm/i915/intel_huc_fw.c @@ -155,9 +155,8 @@ static int huc_fw_xfer(struct intel_uc_fw *huc_fw, struct i915_vma *vma) * Called from intel_uc_init_hw() during driver load, resume from sleep and * after a GPU reset. Note that HuC must be loaded before GuC. * - * The firmware image should have already been fetched into memory by the - * earlier call to intel_uc_init_fw(), so here we need to only check that - * fetch succeeded, and then transfer the image to the h/w. + * The firmware image should have already been fetched into memory, so only + * check that fetch succeeded, and then transfer the image to the h/w. * * Return: non-zero code on error */ diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 34f8a2c219d8..4aad8442e789 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -162,36 +162,35 @@ static void sanitize_options_early(struct drm_i915_private *dev_priv) GEM_BUG_ON(i915_modparams.guc_log_level < 0); } -void intel_uc_init_early(struct drm_i915_private *dev_priv) +void intel_uc_init_early(struct drm_i915_private *i915) { - intel_guc_init_early(&dev_priv->guc); - intel_huc_init_early(&dev_priv->huc); + struct intel_guc *guc = &i915->guc; + struct intel_huc *huc = &i915->huc; - sanitize_options_early(dev_priv); -} + intel_guc_init_early(guc); + intel_huc_init_early(huc); -void intel_uc_init_fw(struct drm_i915_private *dev_priv) -{ - if (!USES_GUC(dev_priv)) - return; + sanitize_options_early(i915); - if (USES_HUC(dev_priv)) - intel_uc_fw_fetch(dev_priv, &dev_priv->huc.fw); + if (USES_GUC(i915)) + intel_uc_fw_fetch(i915, &guc->fw); - intel_uc_fw_fetch(dev_priv, &dev_priv->guc.fw); + if (USES_HUC(i915)) + intel_uc_fw_fetch(i915, &huc->fw); } -void intel_uc_fini_fw(struct drm_i915_private *dev_priv) +void intel_uc_cleanup_early(struct drm_i915_private *i915) { - if (!USES_GUC(dev_priv)) - return; + struct intel_guc *guc = &i915->guc; + struct intel_huc *huc = &i915->huc; - intel_uc_fw_fini(&dev_priv->guc.fw); + if (USES_HUC(i915)) + intel_uc_fw_fini(&huc->fw); - if (USES_HUC(dev_priv)) - intel_uc_fw_fini(&dev_priv->huc.fw); + if (USES_GUC(i915)) + intel_uc_fw_fini(&guc->fw); - guc_free_load_err_log(&dev_priv->guc); + guc_free_load_err_log(guc); } /** diff --git a/drivers/gpu/drm/i915/intel_uc.h b/drivers/gpu/drm/i915/intel_uc.h index 937e61175258..25d73ada74ae 100644 --- a/drivers/gpu/drm/i915/intel_uc.h +++ b/drivers/gpu/drm/i915/intel_uc.h @@ -29,9 +29,8 @@ #include "i915_params.h" void intel_uc_init_early(struct drm_i915_private *dev_priv); +void intel_uc_cleanup_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_misc(struct drm_i915_private *dev_priv); void intel_uc_fini_misc(struct drm_i915_private *dev_priv); void intel_uc_sanitize(struct drm_i915_private *dev_priv); -- cgit v1.2.3 From 46b3617dfec875c1414c6ccbfcab371c97735562 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 23 Mar 2018 10:18:24 +0000 Subject: drm/i915: Actually flush interrupts on reset not just wedging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 0f36a85c3bd5 ("drm/i915: Flush pending interrupt following a GPU reset") got confused and only applied the flush to the set-wedge path (which itself is proving troublesome), but we also need the serialisation on the regular reset path. Oops. Move the interrupt into reset_irq() and make it common to the reset and final set-wedge. v2: reset_irq() after port cancellation, as we assert that execlists->active is sane for cancellation (and is being reset by reset_irq). References: 0f36a85c3bd5 ("drm/i915: Flush pending interrupt following a GPU reset") Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Michel Thierry Cc: Michał Winiarski Cc: Jeff McGee Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180323101824.14645-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 107 +++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index ce09c5ad334f..b4ab06b05e58 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -740,6 +740,57 @@ execlists_cancel_port_requests(struct intel_engine_execlists * const execlists) } } +static void clear_gtiir(struct intel_engine_cs *engine) +{ + static const u8 gtiir[] = { + [RCS] = 0, + [BCS] = 0, + [VCS] = 1, + [VCS2] = 1, + [VECS] = 3, + }; + struct drm_i915_private *dev_priv = engine->i915; + int i; + + /* TODO: correctly reset irqs for gen11 */ + if (WARN_ON_ONCE(INTEL_GEN(engine->i915) >= 11)) + return; + + 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 so if we only reset it once there may + * still be an interrupt pending. + */ + for (i = 0; i < 2; i++) { + I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]), + engine->irq_keep_mask); + POSTING_READ(GEN8_GT_IIR(gtiir[engine->id])); + } + GEM_BUG_ON(I915_READ(GEN8_GT_IIR(gtiir[engine->id])) & + engine->irq_keep_mask); +} + +static void reset_irq(struct intel_engine_cs *engine) +{ + /* Mark all CS interrupts as complete */ + smp_store_mb(engine->execlists.active, 0); + synchronize_hardirq(engine->i915->drm.irq); + + clear_gtiir(engine); + + /* + * The port is checked prior to scheduling a tasklet, but + * just in case we have suspended the tasklet to do the + * wedging make sure that when it wakes, it decides there + * is no work to do by clearing the irq_posted bit. + */ + clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); +} + static void execlists_cancel_requests(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; @@ -767,6 +818,7 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) /* Cancel the requests on the HW and clear the ELSP tracker. */ execlists_cancel_port_requests(execlists); + reset_irq(engine); spin_lock(&engine->timeline->lock); @@ -805,18 +857,6 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) spin_unlock(&engine->timeline->lock); - /* Mark all CS interrupts as complete */ - smp_store_mb(execlists->active, 0); - synchronize_hardirq(engine->i915->drm.irq); - - /* - * The port is checked prior to scheduling a tasklet, but - * just in case we have suspended the tasklet to do the - * wedging make sure that when it wakes, it decides there - * is no work to do by clearing the irq_posted bit. - */ - clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); - local_irq_restore(flags); } @@ -1566,14 +1606,6 @@ static int intel_init_workaround_bb(struct intel_engine_cs *engine) return ret; } -static u8 gtiir[] = { - [RCS] = 0, - [BCS] = 0, - [VCS] = 1, - [VCS2] = 1, - [VECS] = 3, -}; - static void enable_execlists(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; @@ -1657,35 +1689,6 @@ 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; - int i; - - /* TODO: correctly reset irqs for gen11 */ - if (WARN_ON_ONCE(INTEL_GEN(engine->i915) >= 11)) - return; - - 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. - */ - for (i = 0; i < 2; i++) { - I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]), - engine->irq_keep_mask); - POSTING_READ(GEN8_GT_IIR(gtiir[engine->id])); - } - GEM_BUG_ON(I915_READ(GEN8_GT_IIR(gtiir[engine->id])) & - engine->irq_keep_mask); - - clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); -} - static void reset_common_ring(struct intel_engine_cs *engine, struct i915_request *request) { @@ -1699,8 +1702,6 @@ static void reset_common_ring(struct intel_engine_cs *engine, /* See execlists_cancel_requests() for the irq/spinlock split. */ local_irq_save(flags); - reset_irq(engine); - /* * Catch up with any missed context-switch interrupts. * @@ -1711,15 +1712,13 @@ static void reset_common_ring(struct intel_engine_cs *engine, * requests were completed. */ execlists_cancel_port_requests(execlists); + reset_irq(engine); /* Push back any incomplete requests for replay after the reset. */ spin_lock(&engine->timeline->lock); __unwind_incomplete_requests(engine); spin_unlock(&engine->timeline->lock); - /* Mark all CS interrupts as complete */ - execlists->active = 0; - local_irq_restore(flags); /* -- cgit v1.2.3 From 0f90603c33bdf6575cfdc81edd53f3f13ba166fb Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 22 Mar 2018 16:36:42 +0200 Subject: drm/i915: Fix hibernation with ACPI S0 target state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit dd9f31c7a3887950cbd0d49eb9d43f7a1518a356 Author: Imre Deak Date: Wed Aug 16 17:46:07 2017 +0300 drm/i915/gen9+: Set same power state before hibernation image save/restore during hibernation/suspend the power domain functionality got disabled, after which resume could leave it incorrectly disabled if the ACPI target state was S0 during suspend and i915 was not loaded by the loader kernel. This was caused by not considering if we resumed from hibernation as the condition for power domains reiniting. Fix this by simply tracking if we suspended power domains during system suspend and reinit power domains accordingly during resume. This will result in reiniting power domains always when resuming from hibernation, regardless of the platform and whether or not i915 is loaded by the loader kernel. The reason we didn't catch this earlier is that the enabled/disabled state of power domains during PMSG_FREEZE/PMSG_QUIESCE is platform and kernel config dependent: on my SKL the target state is S4 during PMSG_FREEZE and (with the driver loaded in the loader kernel) S0 during PMSG_QUIESCE. On the reporter's machine it's S0 during PMSG_FREEZE but (contrary to this) power domains are not initialized during PMSG_QUIESCE since i915 is not loaded in the loader kernel, or it's loaded but without the DMC firmware being available. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105196 Reported-and-tested-by: amn-bas@hotmail.com Fixes: dd9f31c7a388 ("drm/i915/gen9+: Set same power state before hibernation image save/restore") Cc: amn-bas@hotmail.com Cc: Ville Syrjälä Cc: Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180322143642.26883-1-imre.deak@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 22 ++++++++++------------ drivers/gpu/drm/i915/i915_drv.h | 2 +- 2 files changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index db223378d84b..d354627882e3 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1607,15 +1607,12 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) { struct drm_i915_private *dev_priv = to_i915(dev); struct pci_dev *pdev = dev_priv->drm.pdev; - bool fw_csr; int ret; disable_rpm_wakeref_asserts(dev_priv); intel_display_set_init_power(dev_priv, false); - fw_csr = !IS_GEN9_LP(dev_priv) && !hibernation && - suspend_to_idle(dev_priv) && dev_priv->csr.dmc_payload; /* * In case of firmware assisted context save/restore don't manually * deinit the power domains. This also means the CSR/DMC firmware will @@ -1623,8 +1620,11 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) * also enable deeper system power states that would be blocked if the * firmware was inactive. */ - if (!fw_csr) + if (IS_GEN9_LP(dev_priv) || hibernation || !suspend_to_idle(dev_priv) || + dev_priv->csr.dmc_payload == NULL) { intel_power_domains_suspend(dev_priv); + dev_priv->power_domains_suspended = true; + } ret = 0; if (IS_GEN9_LP(dev_priv)) @@ -1636,8 +1636,10 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) if (ret) { DRM_ERROR("Suspend complete failed: %d\n", ret); - if (!fw_csr) + if (dev_priv->power_domains_suspended) { intel_power_domains_init_hw(dev_priv, true); + dev_priv->power_domains_suspended = false; + } goto out; } @@ -1658,8 +1660,6 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) if (!(hibernation && INTEL_GEN(dev_priv) < 6)) pci_set_power_state(pdev, PCI_D3hot); - dev_priv->suspended_to_idle = suspend_to_idle(dev_priv); - out: enable_rpm_wakeref_asserts(dev_priv); @@ -1826,8 +1826,7 @@ static int i915_drm_resume_early(struct drm_device *dev) intel_uncore_resume_early(dev_priv); if (IS_GEN9_LP(dev_priv)) { - if (!dev_priv->suspended_to_idle) - gen9_sanitize_dc_state(dev_priv); + gen9_sanitize_dc_state(dev_priv); bxt_disable_dc9(dev_priv); } else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { hsw_disable_pc8(dev_priv); @@ -1835,8 +1834,7 @@ static int i915_drm_resume_early(struct drm_device *dev) intel_uncore_sanitize(dev_priv); - if (IS_GEN9_LP(dev_priv) || - !(dev_priv->suspended_to_idle && dev_priv->csr.dmc_payload)) + if (dev_priv->power_domains_suspended) intel_power_domains_init_hw(dev_priv, true); else intel_display_set_init_power(dev_priv, true); @@ -1846,7 +1844,7 @@ static int i915_drm_resume_early(struct drm_device *dev) enable_rpm_wakeref_asserts(dev_priv); out: - dev_priv->suspended_to_idle = false; + dev_priv->power_domains_suspended = false; return ret; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 28ab91812701..299b24045003 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1851,7 +1851,7 @@ struct drm_i915_private { u32 bxt_phy_grc; u32 suspend_count; - bool suspended_to_idle; + bool power_domains_suspended; struct i915_suspend_saved_registers regfile; struct vlv_s0ix_state vlv_s0ix_state; -- cgit v1.2.3 From 5bb975de3f279c6577fb54334cdd7e55c47a362c Mon Sep 17 00:00:00 2001 From: Manasi Navare Date: Fri, 23 Mar 2018 10:24:13 -0700 Subject: drm/i915/icl: Add register definitions for Combo PHY vswing sequences. This patch defines register definitions required for ICL voltage vswing programming for Combo PHY DDI Ports. It uses the same bit definitions and macros as the CNL voltage swing sequences. v8 (from Paulo): * Rebase. v7: * Kill _MMIIO_PORT2_LN (Paulo) v6: * Replace some spaces with TAB (Paulo) v5: * Use _PORT instead of _PICK (Paulo) * Remove DW7 defs for ICL, not used (Paulo) v4: * Rebase after _PICK was used instead of _PORT3 * Use _PICK for _MMIO_PORT2 since address of B is less than address of A so cant use the math (Paulo) v3: * Make changes to the existing macro in a diff patch (Paulo) v2: * Add new defs fro ICL regs (Paulo) Cc: Jani Nikula Cc: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Manasi Navare Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180323172419.24911-2-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4e31dfff940a..407ee5ca527f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1697,6 +1697,16 @@ enum i915_power_well_id { _CNL_PORT_PCS_DW1_LN0_D, \ _CNL_PORT_PCS_DW1_LN0_AE, \ _CNL_PORT_PCS_DW1_LN0_F)) +#define _ICL_PORT_PCS_DW1_GRP_A 0x162604 +#define _ICL_PORT_PCS_DW1_GRP_B 0x6C604 +#define _ICL_PORT_PCS_DW1_LN0_A 0x162804 +#define _ICL_PORT_PCS_DW1_LN0_B 0x6C804 +#define ICL_PORT_PCS_DW1_GRP(port) _MMIO_PORT(port,\ + _ICL_PORT_PCS_DW1_GRP_A, \ + _ICL_PORT_PCS_DW1_GRP_B) +#define ICL_PORT_PCS_DW1_LN0(port) _MMIO_PORT(port, \ + _ICL_PORT_PCS_DW1_LN0_A, \ + _ICL_PORT_PCS_DW1_LN0_B) #define COMMON_KEEPER_EN (1 << 26) /* CNL Port TX registers */ @@ -1729,6 +1739,16 @@ enum i915_power_well_id { #define CNL_PORT_TX_DW2_GRP(port) _MMIO(_CNL_PORT_TX_DW_GRP((port), 2)) #define CNL_PORT_TX_DW2_LN0(port) _MMIO(_CNL_PORT_TX_DW_LN0((port), 2)) +#define _ICL_PORT_TX_DW2_GRP_A 0x162688 +#define _ICL_PORT_TX_DW2_GRP_B 0x6C688 +#define _ICL_PORT_TX_DW2_LN0_A 0x162888 +#define _ICL_PORT_TX_DW2_LN0_B 0x6C888 +#define ICL_PORT_TX_DW2_GRP(port) _MMIO_PORT(port, \ + _ICL_PORT_TX_DW2_GRP_A, \ + _ICL_PORT_TX_DW2_GRP_B) +#define ICL_PORT_TX_DW2_LN0(port) _MMIO_PORT(port, \ + _ICL_PORT_TX_DW2_LN0_A, \ + _ICL_PORT_TX_DW2_LN0_B) #define SWING_SEL_UPPER(x) ((x >> 3) << 15) #define SWING_SEL_UPPER_MASK (1 << 15) #define SWING_SEL_LOWER(x) ((x & 0x7) << 11) @@ -1743,6 +1763,19 @@ enum i915_power_well_id { #define CNL_PORT_TX_DW4_LN(port, ln) _MMIO(_CNL_PORT_TX_DW_LN0((port), 4) + \ (ln * (_CNL_PORT_TX_DW4_LN1_AE - \ _CNL_PORT_TX_DW4_LN0_AE))) +#define _ICL_PORT_TX_DW4_GRP_A 0x162690 +#define _ICL_PORT_TX_DW4_GRP_B 0x6C690 +#define _ICL_PORT_TX_DW4_LN0_A 0x162890 +#define _ICL_PORT_TX_DW4_LN1_A 0x162990 +#define _ICL_PORT_TX_DW4_LN0_B 0x6C890 +#define ICL_PORT_TX_DW4_GRP(port) _MMIO_PORT(port, \ + _ICL_PORT_TX_DW4_GRP_A, \ + _ICL_PORT_TX_DW4_GRP_B) +#define ICL_PORT_TX_DW4_LN(port, ln) _MMIO(_PORT(port, \ + _ICL_PORT_TX_DW4_LN0_A, \ + _ICL_PORT_TX_DW4_LN0_B) + \ + (ln * (_ICL_PORT_TX_DW4_LN1_A - \ + _ICL_PORT_TX_DW4_LN0_A))) #define LOADGEN_SELECT (1 << 31) #define POST_CURSOR_1(x) ((x) << 12) #define POST_CURSOR_1_MASK (0x3F << 12) @@ -1753,7 +1786,18 @@ enum i915_power_well_id { #define CNL_PORT_TX_DW5_GRP(port) _MMIO(_CNL_PORT_TX_DW_GRP((port), 5)) #define CNL_PORT_TX_DW5_LN0(port) _MMIO(_CNL_PORT_TX_DW_LN0((port), 5)) +#define _ICL_PORT_TX_DW5_GRP_A 0x162694 +#define _ICL_PORT_TX_DW5_GRP_B 0x6C694 +#define _ICL_PORT_TX_DW5_LN0_A 0x162894 +#define _ICL_PORT_TX_DW5_LN0_B 0x6C894 +#define ICL_PORT_TX_DW5_GRP(port) _MMIO_PORT(port, \ + _ICL_PORT_TX_DW5_GRP_A, \ + _ICL_PORT_TX_DW5_GRP_B) +#define ICL_PORT_TX_DW5_LN0(port) _MMIO_PORT(port, \ + _ICL_PORT_TX_DW5_LN0_A, \ + _ICL_PORT_TX_DW5_LN0_B) #define TX_TRAINING_EN (1 << 31) +#define TAP2_DISABLE (1 << 30) #define TAP3_DISABLE (1 << 29) #define SCALING_MODE_SEL(x) ((x) << 18) #define SCALING_MODE_SEL_MASK (0x7 << 18) -- cgit v1.2.3 From 19b904f8df5c6c1418769de35bf238ef72e49814 Mon Sep 17 00:00:00 2001 From: Manasi Navare Date: Fri, 23 Mar 2018 10:24:14 -0700 Subject: drm/i915/icl: Add Combo PHY DDI Buffer translation tables for Icelake. These tables are used on voltage vswing sequence initialization on Icelake. The swing_sel on the spec's table is defined in a 4 bits binary like 1010. However the register bits are split in upper 1 bit swing_sel and lower 3 bits swing sel. In this table here we store this value as a single value in hex like it is mentioned in the Bspec and split it to the upper and lower bit values only while programming the registers. For instance: b1010 is written as 0xA and then while writing to the register, the upper 1 bit is obtained by (0xA & 0x8) and shifting by appropriate bits while lower 3 bits are obtained by (0xA & 0x7) and shifting by appropriate bits. Some of the columns need to be updated after the spec is updated. v5 (from Paulo): * Checkpatch fixes. v4 (from Paulo): * Fix minor typo * Coding style conformance v3: * Get rid of HDMI/DVI tables, same as DP (Paulo) * Use combo_phy in ddi buf trans table defs (Paulo) v2: * Added DW4_scaling_hex column to the translation tables (Rodrigo) Cc: Jani Nikula Cc: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Manasi Navare Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180323172419.24911-3-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_ddi.c | 99 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index c449619427da..229b9d5250c4 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -493,6 +493,105 @@ static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_1_05V[] = { { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ }; +struct icl_combo_phy_ddi_buf_trans { + u32 dw2_swing_select; + u32 dw2_swing_scalar; + u32 dw4_scaling; +}; + +/* Voltage Swing Programming for VccIO 0.85V for DP */ +static const struct icl_combo_phy_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hdmi_0_85V[] = { + /* Voltage mV db */ + { 0x2, 0x98, 0x0018 }, /* 400 0.0 */ + { 0x2, 0x98, 0x3015 }, /* 400 3.5 */ + { 0x2, 0x98, 0x6012 }, /* 400 6.0 */ + { 0x2, 0x98, 0x900F }, /* 400 9.5 */ + { 0xB, 0x70, 0x0018 }, /* 600 0.0 */ + { 0xB, 0x70, 0x3015 }, /* 600 3.5 */ + { 0xB, 0x70, 0x6012 }, /* 600 6.0 */ + { 0x5, 0x00, 0x0018 }, /* 800 0.0 */ + { 0x5, 0x00, 0x3015 }, /* 800 3.5 */ + { 0x6, 0x98, 0x0018 }, /* 1200 0.0 */ +}; + +/* FIXME - After table is updated in Bspec */ +/* Voltage Swing Programming for VccIO 0.85V for eDP */ +static const struct icl_combo_phy_ddi_buf_trans icl_combo_phy_ddi_translations_edp_0_85V[] = { + /* Voltage mV db */ + { 0x0, 0x00, 0x00 }, /* 200 0.0 */ + { 0x0, 0x00, 0x00 }, /* 200 1.5 */ + { 0x0, 0x00, 0x00 }, /* 200 4.0 */ + { 0x0, 0x00, 0x00 }, /* 200 6.0 */ + { 0x0, 0x00, 0x00 }, /* 250 0.0 */ + { 0x0, 0x00, 0x00 }, /* 250 1.5 */ + { 0x0, 0x00, 0x00 }, /* 250 4.0 */ + { 0x0, 0x00, 0x00 }, /* 300 0.0 */ + { 0x0, 0x00, 0x00 }, /* 300 1.5 */ + { 0x0, 0x00, 0x00 }, /* 350 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 0.95V for DP */ +static const struct icl_combo_phy_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hdmi_0_95V[] = { + /* Voltage mV db */ + { 0x2, 0x98, 0x0018 }, /* 400 0.0 */ + { 0x2, 0x98, 0x3015 }, /* 400 3.5 */ + { 0x2, 0x98, 0x6012 }, /* 400 6.0 */ + { 0x2, 0x98, 0x900F }, /* 400 9.5 */ + { 0x4, 0x98, 0x0018 }, /* 600 0.0 */ + { 0x4, 0x98, 0x3015 }, /* 600 3.5 */ + { 0x4, 0x98, 0x6012 }, /* 600 6.0 */ + { 0x5, 0x76, 0x0018 }, /* 800 0.0 */ + { 0x5, 0x76, 0x3015 }, /* 800 3.5 */ + { 0x6, 0x98, 0x0018 }, /* 1200 0.0 */ +}; + +/* FIXME - After table is updated in Bspec */ +/* Voltage Swing Programming for VccIO 0.95V for eDP */ +static const struct icl_combo_phy_ddi_buf_trans icl_combo_phy_ddi_translations_edp_0_95V[] = { + /* Voltage mV db */ + { 0x0, 0x00, 0x00 }, /* 200 0.0 */ + { 0x0, 0x00, 0x00 }, /* 200 1.5 */ + { 0x0, 0x00, 0x00 }, /* 200 4.0 */ + { 0x0, 0x00, 0x00 }, /* 200 6.0 */ + { 0x0, 0x00, 0x00 }, /* 250 0.0 */ + { 0x0, 0x00, 0x00 }, /* 250 1.5 */ + { 0x0, 0x00, 0x00 }, /* 250 4.0 */ + { 0x0, 0x00, 0x00 }, /* 300 0.0 */ + { 0x0, 0x00, 0x00 }, /* 300 1.5 */ + { 0x0, 0x00, 0x00 }, /* 350 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 1.05V for DP */ +static const struct icl_combo_phy_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hdmi_1_05V[] = { + /* Voltage mV db */ + { 0x2, 0x98, 0x0018 }, /* 400 0.0 */ + { 0x2, 0x98, 0x3015 }, /* 400 3.5 */ + { 0x2, 0x98, 0x6012 }, /* 400 6.0 */ + { 0x2, 0x98, 0x900F }, /* 400 9.5 */ + { 0x4, 0x98, 0x0018 }, /* 600 0.0 */ + { 0x4, 0x98, 0x3015 }, /* 600 3.5 */ + { 0x4, 0x98, 0x6012 }, /* 600 6.0 */ + { 0x5, 0x71, 0x0018 }, /* 800 0.0 */ + { 0x5, 0x71, 0x3015 }, /* 800 3.5 */ + { 0x6, 0x98, 0x0018 }, /* 1200 0.0 */ +}; + +/* FIXME - After table is updated in Bspec */ +/* Voltage Swing Programming for VccIO 1.05V for eDP */ +static const struct icl_combo_phy_ddi_buf_trans icl_combo_phy_ddi_translations_edp_1_05V[] = { + /* Voltage mV db */ + { 0x0, 0x00, 0x00 }, /* 200 0.0 */ + { 0x0, 0x00, 0x00 }, /* 200 1.5 */ + { 0x0, 0x00, 0x00 }, /* 200 4.0 */ + { 0x0, 0x00, 0x00 }, /* 200 6.0 */ + { 0x0, 0x00, 0x00 }, /* 250 0.0 */ + { 0x0, 0x00, 0x00 }, /* 250 1.5 */ + { 0x0, 0x00, 0x00 }, /* 250 4.0 */ + { 0x0, 0x00, 0x00 }, /* 300 0.0 */ + { 0x0, 0x00, 0x00 }, /* 300 1.5 */ + { 0x0, 0x00, 0x00 }, /* 350 0.0 */ +}; + static const struct ddi_buf_trans * bdw_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries) { -- cgit v1.2.3 From c92f47b5ec977a31c72a3c3514ae460b3dd725ff Mon Sep 17 00:00:00 2001 From: Manasi Navare Date: Fri, 23 Mar 2018 10:24:15 -0700 Subject: drm/i915/icl: Add register defs for voltage swing sequences for MG PHY DDI On Icelake platform, MG PHY is used when operating in DP alternate mode or the legacy HDMI or DP modes. DDI Ports C, D, E, F are MG PHY DDI ports on ICL. This patch adds the necessary voltage swing programming related register definitions and macros for MG PHY DDI ports. v4 (from Paulo): * Use _PORT instead of _PICK * Change some mask names to our current coding standards * Stay under 80 columns v3: * Rebase on new revision of patches v2: * Remove whitespaces in the #defines (Paulo) Cc: Rodrigo Vivi Cc: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Manasi Navare Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180323172419.24911-4-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 116 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 407ee5ca527f..aa001dd98cc5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1809,6 +1809,122 @@ enum i915_power_well_id { #define N_SCALAR(x) ((x) << 24) #define N_SCALAR_MASK (0x7F << 24) +#define _ICL_MG_PHY_PORT_LN(port, ln, ln0p1, ln0p2, ln1p1) \ + _MMIO(_PORT((port) - PORT_C, ln0p1, ln0p2) + (ln) * ((ln1p1) - (ln0p1))) + +#define _ICL_MG_TX_LINK_PARAMS_TX1LN0_PORT1 0x16812C +#define _ICL_MG_TX_LINK_PARAMS_TX1LN1_PORT1 0x16852C +#define _ICL_MG_TX_LINK_PARAMS_TX1LN0_PORT2 0x16912C +#define _ICL_MG_TX_LINK_PARAMS_TX1LN1_PORT2 0x16952C +#define _ICL_MG_TX_LINK_PARAMS_TX1LN0_PORT3 0x16A12C +#define _ICL_MG_TX_LINK_PARAMS_TX1LN1_PORT3 0x16A52C +#define _ICL_MG_TX_LINK_PARAMS_TX1LN0_PORT4 0x16B12C +#define _ICL_MG_TX_LINK_PARAMS_TX1LN1_PORT4 0x16B52C +#define ICL_PORT_MG_TX1_LINK_PARAMS(port, ln) \ + _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_LINK_PARAMS_TX1LN0_PORT1, \ + _ICL_MG_TX_LINK_PARAMS_TX1LN0_PORT2, \ + _ICL_MG_TX_LINK_PARAMS_TX1LN1_PORT1) + +#define _ICL_MG_TX_LINK_PARAMS_TX2LN0_PORT1 0x1680AC +#define _ICL_MG_TX_LINK_PARAMS_TX2LN1_PORT1 0x1684AC +#define _ICL_MG_TX_LINK_PARAMS_TX2LN0_PORT2 0x1690AC +#define _ICL_MG_TX_LINK_PARAMS_TX2LN1_PORT2 0x1694AC +#define _ICL_MG_TX_LINK_PARAMS_TX2LN0_PORT3 0x16A0AC +#define _ICL_MG_TX_LINK_PARAMS_TX2LN1_PORT3 0x16A4AC +#define _ICL_MG_TX_LINK_PARAMS_TX2LN0_PORT4 0x16B0AC +#define _ICL_MG_TX_LINK_PARAMS_TX2LN1_PORT4 0x16B4AC +#define ICL_PORT_MG_TX2_LINK_PARAMS(port, ln) \ + _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_LINK_PARAMS_TX2LN0_PORT1, \ + _ICL_MG_TX_LINK_PARAMS_TX2LN0_PORT2, \ + _ICL_MG_TX_LINK_PARAMS_TX2LN1_PORT1) +#define CRI_USE_FS32 (1 << 5) + +#define _ICL_MG_TX_PISO_READLOAD_TX1LN0_PORT1 0x16814C +#define _ICL_MG_TX_PISO_READLOAD_TX1LN1_PORT1 0x16854C +#define _ICL_MG_TX_PISO_READLOAD_TX1LN0_PORT2 0x16914C +#define _ICL_MG_TX_PISO_READLOAD_TX1LN1_PORT2 0x16954C +#define _ICL_MG_TX_PISO_READLOAD_TX1LN0_PORT3 0x16A14C +#define _ICL_MG_TX_PISO_READLOAD_TX1LN1_PORT3 0x16A54C +#define _ICL_MG_TX_PISO_READLOAD_TX1LN0_PORT4 0x16B14C +#define _ICL_MG_TX_PISO_READLOAD_TX1LN1_PORT4 0x16B54C +#define ICL_PORT_MG_TX1_PISO_READLOAD(port, ln) \ + _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_PISO_READLOAD_TX1LN0_PORT1, \ + _ICL_MG_TX_PISO_READLOAD_TX1LN0_PORT2, \ + _ICL_MG_TX_PISO_READLOAD_TX1LN1_PORT1) + +#define _ICL_MG_TX_PISO_READLOAD_TX2LN0_PORT1 0x1680CC +#define _ICL_MG_TX_PISO_READLOAD_TX2LN1_PORT1 0x1684CC +#define _ICL_MG_TX_PISO_READLOAD_TX2LN0_PORT2 0x1690CC +#define _ICL_MG_TX_PISO_READLOAD_TX2LN1_PORT2 0x1694CC +#define _ICL_MG_TX_PISO_READLOAD_TX2LN0_PORT3 0x16A0CC +#define _ICL_MG_TX_PISO_READLOAD_TX2LN1_PORT3 0x16A4CC +#define _ICL_MG_TX_PISO_READLOAD_TX2LN0_PORT4 0x16B0CC +#define _ICL_MG_TX_PISO_READLOAD_TX2LN1_PORT4 0x16B4CC +#define ICL_PORT_MG_TX2_PISO_READLOAD(port, ln) \ + _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_PISO_READLOAD_TX2LN0_PORT1, \ + _ICL_MG_TX_PISO_READLOAD_TX2LN0_PORT2, \ + _ICL_MG_TX_PISO_READLOAD_TX2LN1_PORT1) +#define CRI_CALCINIT (1 << 1) + +#define _ICL_MG_TX_SWINGCTRL_TX1LN0_PORT1 0x168148 +#define _ICL_MG_TX_SWINGCTRL_TX1LN1_PORT1 0x168548 +#define _ICL_MG_TX_SWINGCTRL_TX1LN0_PORT2 0x169148 +#define _ICL_MG_TX_SWINGCTRL_TX1LN1_PORT2 0x169548 +#define _ICL_MG_TX_SWINGCTRL_TX1LN0_PORT3 0x16A148 +#define _ICL_MG_TX_SWINGCTRL_TX1LN1_PORT3 0x16A548 +#define _ICL_MG_TX_SWINGCTRL_TX1LN0_PORT4 0x16B148 +#define _ICL_MG_TX_SWINGCTRL_TX1LN1_PORT4 0x16B548 +#define ICL_PORT_MG_TX1_SWINGCTRL(port, ln) \ + _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_SWINGCTRL_TX1LN0_PORT1, \ + _ICL_MG_TX_SWINGCTRL_TX1LN0_PORT2, \ + _ICL_MG_TX_SWINGCTRL_TX1LN1_PORT1) + +#define _ICL_MG_TX_SWINGCTRL_TX2LN0_PORT1 0x1680C8 +#define _ICL_MG_TX_SWINGCTRL_TX2LN1_PORT1 0x1684C8 +#define _ICL_MG_TX_SWINGCTRL_TX2LN0_PORT2 0x1690C8 +#define _ICL_MG_TX_SWINGCTRL_TX2LN1_PORT2 0x1694C8 +#define _ICL_MG_TX_SWINGCTRL_TX2LN0_PORT3 0x16A0C8 +#define _ICL_MG_TX_SWINGCTRL_TX2LN1_PORT3 0x16A4C8 +#define _ICL_MG_TX_SWINGCTRL_TX2LN0_PORT4 0x16B0C8 +#define _ICL_MG_TX_SWINGCTRL_TX2LN1_PORT4 0x16B4C8 +#define ICL_PORT_MG_TX2_SWINGCTRL(port, ln) \ + _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_SWINGCTRL_TX2LN0_PORT1, \ + _ICL_MG_TX_SWINGCTRL_TX2LN0_PORT2, \ + _ICL_MG_TX_SWINGCTRL_TX2LN1_PORT1) +#define CRI_TXDEEMPH_OVERRIDE_17_12(x) ((x) << 0) +#define CRI_TXDEEMPH_OVERRIDE_17_12_MASK (0x3F << 0) + +#define _ICL_MG_TX_DRVCTRL_TX1LN0_PORT1 0x168144 +#define _ICL_MG_TX_DRVCTRL_TX1LN1_PORT1 0x168544 +#define _ICL_MG_TX_DRVCTRL_TX1LN0_PORT2 0x169144 +#define _ICL_MG_TX_DRVCTRL_TX1LN1_PORT2 0x169544 +#define _ICL_MG_TX_DRVCTRL_TX1LN0_PORT3 0x16A144 +#define _ICL_MG_TX_DRVCTRL_TX1LN1_PORT3 0x16A544 +#define _ICL_MG_TX_DRVCTRL_TX1LN0_PORT4 0x16B144 +#define _ICL_MG_TX_DRVCTRL_TX1LN1_PORT4 0x16B544 +#define ICL_PORT_MG_TX1_DRVCTRL(port, ln) \ + _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_DRVCTRL_TX1LN0_PORT1, \ + _ICL_MG_TX_DRVCTRL_TX1LN0_PORT2, \ + _ICL_MG_TX_DRVCTRL_TX1LN1_PORT1) + +#define _ICL_MG_TX_DRVCTRL_TX2LN0_PORT1 0x1680C4 +#define _ICL_MG_TX_DRVCTRL_TX2LN1_PORT1 0x1684C4 +#define _ICL_MG_TX_DRVCTRL_TX2LN0_PORT2 0x1690C4 +#define _ICL_MG_TX_DRVCTRL_TX2LN1_PORT2 0x1694C4 +#define _ICL_MG_TX_DRVCTRL_TX2LN0_PORT3 0x16A0C4 +#define _ICL_MG_TX_DRVCTRL_TX2LN1_PORT3 0x16A4C4 +#define _ICL_MG_TX_DRVCTRL_TX2LN0_PORT4 0x16B0C4 +#define _ICL_MG_TX_DRVCTRL_TX2LN1_PORT4 0x16B4C4 +#define ICL_PORT_MG_TX2_DRVCTRL(port, ln) \ + _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_DRVCTRL_TX2LN0_PORT1, \ + _ICL_MG_TX_DRVCTRL_TX2LN0_PORT2, \ + _ICL_MG_TX_DRVCTRL_TX2LN1_PORT1) +#define CRI_TXDEEMPH_OVERRIDE_11_6(x) ((x) << 24) +#define CRI_TXDEEMPH_OVERRIDE_11_6_MASK (0x3F << 24) +#define CRI_TXDEEMPH_OVERRIDE_EN (1 << 22) +#define CRI_TXDEEMPH_OVERRIDE_5_0(x) ((x) << 16) +#define CRI_TXDEEMPH_OVERRIDE_5_0_MASK (0x3F << 16) + /* The spec defines this only for BXT PHY0, but lets assume that this * would exist for PHY1 too if it had a second channel. */ -- cgit v1.2.3 From cd96bea7ba90c45c8d1d315433c78021e56ec8c7 Mon Sep 17 00:00:00 2001 From: Manasi Navare Date: Fri, 23 Mar 2018 10:24:16 -0700 Subject: drm/i915/icl: Add Voltage swing table for MG PHY DDI Buffer This table is used for voltage swing programming sequence during DDI Buffer initialization for MG PHY DDI Buffers on Icelake. v2 (from Paulo): * Fix white space issues. Cc: Rodrigo Vivi Cc: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Manasi Navare Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180323172419.24911-5-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_ddi.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 229b9d5250c4..359acbfec4b1 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -592,6 +592,26 @@ static const struct icl_combo_phy_ddi_buf_trans icl_combo_phy_ddi_translations_e { 0x0, 0x00, 0x00 }, /* 350 0.0 */ }; +struct icl_mg_phy_ddi_buf_trans { + u32 cri_txdeemph_override_5_0; + u32 cri_txdeemph_override_11_6; + u32 cri_txdeemph_override_17_12; +}; + +static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations[] = { + /* Voltage swing pre-emphasis */ + { 0x0, 0x1B, 0x00 }, /* 0 0 */ + { 0x0, 0x23, 0x08 }, /* 0 1 */ + { 0x0, 0x2D, 0x12 }, /* 0 2 */ + { 0x0, 0x00, 0x00 }, /* 0 3 */ + { 0x0, 0x23, 0x00 }, /* 1 0 */ + { 0x0, 0x2B, 0x09 }, /* 1 1 */ + { 0x0, 0x2E, 0x11 }, /* 1 2 */ + { 0x0, 0x2F, 0x00 }, /* 2 0 */ + { 0x0, 0x33, 0x0C }, /* 2 1 */ + { 0x0, 0x00, 0x00 }, /* 3 0 */ +}; + static const struct ddi_buf_trans * bdw_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries) { -- cgit v1.2.3 From 96ae48311ebc23cfe4f929754dc1e1cfb0d031b0 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Fri, 23 Mar 2018 10:24:17 -0700 Subject: drm/i915/icl: HPD pin for port F Extend enum hpd_pin to port F so that we can start using this for ICL. v2: Rebase. Cc: Rodrigo Vivi Cc: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Dhinakaran Pandiyan Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180323172419.24911-6-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_hotplug.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 299b24045003..800230ba1c3b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -262,6 +262,7 @@ enum hpd_pin { HPD_PORT_C, HPD_PORT_D, HPD_PORT_E, + HPD_PORT_F, HPD_NUM_PINS }; diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 0e3d3e89d66a..43aa92beff2a 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -100,6 +100,8 @@ enum port intel_hpd_pin_to_port(struct drm_i915_private *dev_priv, if (IS_CNL_WITH_PORT_F(dev_priv)) return PORT_F; return PORT_E; + case HPD_PORT_F: + return PORT_F; default: return PORT_NONE; /* no port for this pin */ } @@ -132,6 +134,7 @@ enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv, case PORT_F: if (IS_CNL_WITH_PORT_F(dev_priv)) return HPD_PORT_E; + return HPD_PORT_F; default: MISSING_CASE(port); return HPD_NONE; -- cgit v1.2.3 From 323301af974cdd4b797e5b54f5c418554f39d1fa Mon Sep 17 00:00:00 2001 From: Nabendu Maiti Date: Fri, 23 Mar 2018 10:24:18 -0700 Subject: drm/i915/icl: Added 5k source scaling support for Gen11 platform Gen11 supports upto 5k source scaling v2: Re-factoring of code as per review v3: Corrected max Vertical size and indentation v4: Added max Vertical dst size in same patch Reviewed-by: Paulo Zanoni Signed-off-by: Nabendu Maiti Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180323172419.24911-7-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_display.c | 11 +++++++---- drivers/gpu/drm/i915/intel_drv.h | 4 ++++ 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b31b80643f87..d5b3c7eb2353 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4756,10 +4756,13 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, /* range checks */ if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H || - dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H || - - src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H || - dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H) { + dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H || + (IS_GEN11(dev_priv) && + (src_w > ICL_MAX_SRC_W || src_h > ICL_MAX_SRC_H || + dst_w > ICL_MAX_DST_W || dst_h > ICL_MAX_DST_H)) || + (!IS_GEN11(dev_priv) && + (src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H || + dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H))) { DRM_DEBUG_KMS("scaler_user index %u.%u: src %ux%u dst %ux%u " "size is out of scaler range\n", intel_crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b79a01b7f008..d2935acfedb1 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -548,6 +548,10 @@ struct intel_initial_plane_config { #define SKL_MAX_DST_W 4096 #define SKL_MIN_DST_H 8 #define SKL_MAX_DST_H 4096 +#define ICL_MAX_SRC_W 5120 +#define ICL_MAX_SRC_H 4096 +#define ICL_MAX_DST_W 5120 +#define ICL_MAX_DST_H 4096 struct intel_scaler { int in_use; -- cgit v1.2.3 From 7487508eff1fe787573aa6e0f3daaa6b12bd4520 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 23 Mar 2018 12:58:53 -0700 Subject: drm/i915: protect macro parameters in SWING_SEL_{UPP,LO}WER Protect the macro parameters with parens in order to avoid priority issues on macro evaluation when the macro argument is not a single operand. This is not a problem today, but it could be in the future. I found this while reviewing a patch that introduces new callers for the macros. v2: Rebase. Reference: commit 04416108ccea ("drm/i915/cnl: Add registers related to voltage swing sequences.") Cc: Rodrigo Vivi Reviewed-by: Rodrigo Vivi Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180323195853.4599-1-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index aa001dd98cc5..b0c55f9d401b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1749,9 +1749,9 @@ enum i915_power_well_id { #define ICL_PORT_TX_DW2_LN0(port) _MMIO_PORT(port, \ _ICL_PORT_TX_DW2_LN0_A, \ _ICL_PORT_TX_DW2_LN0_B) -#define SWING_SEL_UPPER(x) ((x >> 3) << 15) +#define SWING_SEL_UPPER(x) (((x) >> 3) << 15) #define SWING_SEL_UPPER_MASK (1 << 15) -#define SWING_SEL_LOWER(x) ((x & 0x7) << 11) +#define SWING_SEL_LOWER(x) (((x) & 0x7) << 11) #define SWING_SEL_LOWER_MASK (0x7 << 11) #define RCOMP_SCALAR(x) ((x) << 0) #define RCOMP_SCALAR_MASK (0xFF << 0) -- cgit v1.2.3 From eed7ec52f214bac2f25395ccaad610fbeb842a6e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2018 12:58:29 +0000 Subject: drm/i915/execlists: Clear user-active flag on preemption completion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When cancelling the requests and clearing out the ports following a successful preemption completion, also clear the active flag. I had assumed that all preemptions would be followed by an immediate dequeue (preserving the active user flag), but under rare circumstances we may be triggering a preemption for the second port only for it to have completed before the preemotion kicks in; leaving execlists->active set even though the system is now idle. We can clear the flag inside the common execlists_cancel_port_requests() as the other users also expect the semantics of active being cleared. Fixes: f6322eddaff7 ("drm/i915/preemption: Allow preemption between submission ports") Signed-off-by: Chris Wilson Cc: Michał Winiarski Cc: Michel Thierry Cc: Mika Kuoppala Cc: Tvrtko Ursulin Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180324125829.27026-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index b4ab06b05e58..9c84af53db94 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -577,6 +577,8 @@ static void execlists_dequeue(struct intel_engine_cs *engine) * know the next preemption status we see corresponds * to this ELSP update. */ + GEM_BUG_ON(!execlists_is_active(execlists, + EXECLISTS_ACTIVE_USER)); GEM_BUG_ON(!port_count(&port[0])); if (port_count(&port[0]) > 1) goto unlock; @@ -738,6 +740,8 @@ execlists_cancel_port_requests(struct intel_engine_execlists * const execlists) memset(port, 0, sizeof(*port)); port++; } + + execlists_clear_active(execlists, EXECLISTS_ACTIVE_USER); } static void clear_gtiir(struct intel_engine_cs *engine) @@ -1042,6 +1046,11 @@ static void execlists_submission_tasklet(unsigned long data) if (fw) intel_uncore_forcewake_put(dev_priv, execlists->fw_domains); + + /* If the engine is now idle, so should be the flag; and vice versa. */ + GEM_BUG_ON(execlists_is_active(&engine->execlists, + EXECLISTS_ACTIVE_USER) == + !port_isset(engine->execlists.port)); } static void queue_request(struct intel_engine_cs *engine, -- cgit v1.2.3 From 9040871336db2c2e379402d7ba9c275d6495b9e0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 26 Mar 2018 12:50:36 +0100 Subject: drm/i915: Include submission tasklet state in engine dump For the off-chance we have an interrupt posted and haven't processed the CSB. v2: Include tasklet enable/disable state for good measure. Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180326115044.2505-4-chris@chris-wilson.co.uk Reviewed-by: Mika Kuoppala --- drivers/gpu/drm/i915/intel_engine_cs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index de09fa42a509..12486d8f534b 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1859,12 +1859,15 @@ static void intel_engine_print_registers(const struct intel_engine_cs *engine, ptr = I915_READ(RING_CONTEXT_STATUS_PTR(engine)); read = GEN8_CSB_READ_PTR(ptr); write = GEN8_CSB_WRITE_PTR(ptr); - drm_printf(m, "\tExeclist CSB read %d [%d cached], write %d [%d from hws], interrupt posted? %s\n", + drm_printf(m, "\tExeclist CSB read %d [%d cached], write %d [%d from hws], interrupt posted? %s, tasklet queued? %s (%s)\n", read, execlists->csb_head, write, intel_read_status_page(engine, intel_hws_csb_write_index(engine->i915)), yesno(test_bit(ENGINE_IRQ_EXECLIST, - &engine->irq_posted))); + &engine->irq_posted)), + yesno(test_bit(TASKLET_STATE_SCHED, + &engine->execlists.tasklet.state)), + enableddisabled(!atomic_read(&engine->execlists.tasklet.count))); if (read >= GEN8_CSB_ENTRIES) read = 0; if (write >= GEN8_CSB_ENTRIES) -- cgit v1.2.3 From ae2f5c009335f4d273d2431539de91c8f28d4736 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 26 Mar 2018 12:50:34 +0100 Subject: drm/i915/execlists: Avoid kicking the submission too early for rescheduling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the request is still waiting on external fences, it has not yet been submitted to the HW queue and so we can forgo kicking the submission tasklet when re-evaluating its priority. This should have no impact other than reducing the number of tasklet wakeups under signal heavy workloads (e.g. switching between engines). v2: Use prebaked container_of() References: f6322eddaff7 ("drm/i915/preemption: Allow preemption between submission ports") Signed-off-by: Chris Wilson Cc: Michał Winiarski Cc: Michel Thierry Cc: Mika Kuoppala Cc: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180326115044.2505-2-chris@chris-wilson.co.uk Reviewed-by: Mika Kuoppala --- drivers/gpu/drm/i915/intel_lrc.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9c84af53db94..ba7f7831f934 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1060,12 +1060,16 @@ static void queue_request(struct intel_engine_cs *engine, list_add_tail(&pt->link, &lookup_priolist(engine, pt, prio)->requests); } +static void __submit_queue(struct intel_engine_cs *engine, int prio) +{ + engine->execlists.queue_priority = prio; + tasklet_hi_schedule(&engine->execlists.tasklet); +} + static void submit_queue(struct intel_engine_cs *engine, int prio) { - if (prio > engine->execlists.queue_priority) { - engine->execlists.queue_priority = prio; - tasklet_hi_schedule(&engine->execlists.tasklet); - } + if (prio > engine->execlists.queue_priority) + __submit_queue(engine, prio); } static void execlists_submit_request(struct i915_request *request) @@ -1198,7 +1202,10 @@ static void execlists_schedule(struct i915_request *request, int prio) __list_del_entry(&pt->link); queue_request(engine, pt, prio); } - submit_queue(engine, prio); + + if (prio > engine->execlists.queue_priority && + i915_sw_fence_done(&pt_to_request(pt)->submit)) + __submit_queue(engine, prio); } spin_unlock_irq(&engine->timeline->lock); -- cgit v1.2.3 From 57bdff48a0a553468f16a65149d51213b5f25fee Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Mon, 19 Mar 2018 10:37:20 -0700 Subject: drm/i915: Reword warning for missing cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In some places we end up converting switch statements to a series of if/else, particularly when introducing helper functions to handle a group of cases. It's tempting to either leave a wrong warning (since now we don't have a switch case anymore) or to convert to WARN(1, ...), but we can just provide a better message and avoid the doubt when such conversions arrise. Introducing a warning inside i915_driver_load() just for tests we get: [ 4535.233717] Missing case (ret == 0) [ 4535.233868] WARNING: CPU: 1 PID: 795 at drivers/gpu/drm/i915/i915_drv.c:1341 i915_driver_load+0x42/0x10e0 [i915] which is clear enough. v2: remove __func__ since this is already on the warning. Cc: Chris Wilson Cc: Ville Syrjälä Cc: Daniel Vetter Signed-off-by: Lucas De Marchi Reviewed-by: Chris Wilson Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180319173720.6974-1-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/i915_utils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h index 51dbfe5bb418..0695717522ea 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -40,8 +40,8 @@ #undef WARN_ON_ONCE #define WARN_ON_ONCE(x) WARN_ONCE((x), "%s", "WARN_ON_ONCE(" __stringify(x) ")") -#define MISSING_CASE(x) WARN(1, "Missing switch case (%lu) in %s\n", \ - (long)(x), __func__) +#define MISSING_CASE(x) WARN(1, "Missing case (%s == %ld)\n", \ + __stringify(x), (long)(x)) #if GCC_VERSION >= 70000 #define add_overflows(A, B) \ -- cgit v1.2.3 From 47aa1e73e72e5e0f5a07e30b84478461195845f5 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 20 Mar 2018 15:06:31 -0700 Subject: drm/i915: move dpll_info to header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow the struct to be embedded in intel_shared_dpll. Signed-off-by: Lucas De Marchi Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180320220637.21480-2-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/intel_dpll_mgr.c | 7 ------- drivers/gpu/drm/i915/intel_dpll_mgr.h | 10 ++++++++++ 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 51c5ae4e9116..52d6e731c3e9 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -1877,13 +1877,6 @@ static void intel_ddi_pll_init(struct drm_device *dev) } } -struct dpll_info { - const char *name; - const int id; - const struct intel_shared_dpll_funcs *funcs; - uint32_t flags; -}; - struct intel_dpll_mgr { const struct dpll_info *dpll_info; diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h index f24ccf443d25..e99d6385478a 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h @@ -205,6 +205,16 @@ struct intel_shared_dpll_funcs { struct intel_dpll_hw_state *hw_state); }; +/** + * struct dpll_info - display PLL platform specific info + */ +struct dpll_info { + const char *name; + const int id; + const struct intel_shared_dpll_funcs *funcs; + uint32_t flags; +}; + /** * struct intel_shared_dpll - display PLL with tracked state and users */ -- cgit v1.2.3 From e30379637fc712991ec8fff1f79344f384ace0aa Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 20 Mar 2018 15:06:32 -0700 Subject: drm/i915: add dpll_info inside intel_shared_dpll MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way we can stop copying fields from dpll_info to intel_shared_dpll one by one. The migration of each field will come on separate patches. Signed-off-by: Lucas De Marchi Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180320220637.21480-3-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/intel_dpll_mgr.c | 1 + drivers/gpu/drm/i915/intel_dpll_mgr.h | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 52d6e731c3e9..30a9ac5322fe 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -2410,6 +2410,7 @@ void intel_shared_dpll_init(struct drm_device *dev) for (i = 0; dpll_info[i].id >= 0; i++) { WARN_ON(i != dpll_info[i].id); + dev_priv->shared_dplls[i].info = &dpll_info[i]; dev_priv->shared_dplls[i].id = dpll_info[i].id; dev_priv->shared_dplls[i].name = dpll_info[i].name; diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h index e99d6385478a..bd2d3652cec4 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h @@ -253,6 +253,11 @@ struct intel_shared_dpll { */ struct intel_shared_dpll_funcs funcs; + /** + * @info: platform specific info + */ + const struct dpll_info *info; + #define INTEL_DPLL_ALWAYS_ON (1 << 0) /** * @flags: -- cgit v1.2.3 From ee1398ba01b308015e568d46fd62a38ceebd7abe Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 20 Mar 2018 15:06:33 -0700 Subject: drm/i915: use funcs from intel_shared_dpll.info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace all users of pll->funcs.* to use pll->info->funcs->*. The extra indirection here is not on any critical path and we can leave all const data together. Signed-off-by: Lucas De Marchi Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180320220637.21480-4-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/intel_display.c | 16 ++++++++-------- drivers/gpu/drm/i915/intel_dpll_mgr.c | 9 ++++----- drivers/gpu/drm/i915/intel_dpll_mgr.h | 8 +++----- 3 files changed, 15 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d5b3c7eb2353..cee9ea3b7eeb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8763,8 +8763,8 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, intel_get_shared_dpll_by_id(dev_priv, pll_id); pll = pipe_config->shared_dpll; - WARN_ON(!pll->funcs.get_hw_state(dev_priv, pll, - &pipe_config->dpll_hw_state)); + WARN_ON(!pll->info->funcs->get_hw_state(dev_priv, pll, + &pipe_config->dpll_hw_state)); tmp = pipe_config->dpll_hw_state.dpll; pipe_config->pixel_multiplier = @@ -9240,8 +9240,8 @@ static void haswell_get_ddi_port_state(struct intel_crtc *crtc, pll = pipe_config->shared_dpll; if (pll) { - WARN_ON(!pll->funcs.get_hw_state(dev_priv, pll, - &pipe_config->dpll_hw_state)); + WARN_ON(!pll->info->funcs->get_hw_state(dev_priv, pll, + &pipe_config->dpll_hw_state)); } /* @@ -11655,7 +11655,7 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv, DRM_DEBUG_KMS("%s\n", pll->name); - active = pll->funcs.get_hw_state(dev_priv, pll, &dpll_hw_state); + active = pll->info->funcs->get_hw_state(dev_priv, pll, &dpll_hw_state); if (!(pll->flags & INTEL_DPLL_ALWAYS_ON)) { I915_STATE_WARN(!pll->on && pll->active_mask, @@ -15128,8 +15128,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) for (i = 0; i < dev_priv->num_shared_dpll; i++) { struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; - pll->on = pll->funcs.get_hw_state(dev_priv, pll, - &pll->state.hw_state); + pll->on = pll->info->funcs->get_hw_state(dev_priv, pll, + &pll->state.hw_state); pll->state.crtc_mask = 0; for_each_intel_crtc(dev, crtc) { struct intel_crtc_state *crtc_state = @@ -15318,7 +15318,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev, DRM_DEBUG_KMS("%s enabled but not in use, disabling\n", pll->name); - pll->funcs.disable(dev_priv, pll); + pll->info->funcs->disable(dev_priv, pll); pll->on = false; } diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 30a9ac5322fe..24d9aa180e0c 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -118,7 +118,7 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv, if (WARN(!pll, "asserting DPLL %s with no DPLL\n", onoff(state))) return; - cur_state = pll->funcs.get_hw_state(dev_priv, pll, &hw_state); + cur_state = pll->info->funcs->get_hw_state(dev_priv, pll, &hw_state); I915_STATE_WARN(cur_state != state, "%s assertion failure (expected %s, current %s)\n", pll->name, onoff(state), onoff(cur_state)); @@ -147,7 +147,7 @@ void intel_prepare_shared_dpll(struct intel_crtc *crtc) WARN_ON(pll->on); assert_shared_dpll_disabled(dev_priv, pll); - pll->funcs.prepare(dev_priv, pll); + pll->info->funcs->prepare(dev_priv, pll); } mutex_unlock(&dev_priv->dpll_lock); } @@ -190,7 +190,7 @@ void intel_enable_shared_dpll(struct intel_crtc *crtc) WARN_ON(pll->on); DRM_DEBUG_KMS("enabling %s\n", pll->name); - pll->funcs.enable(dev_priv, pll); + pll->info->funcs->enable(dev_priv, pll); pll->on = true; out: @@ -232,7 +232,7 @@ void intel_disable_shared_dpll(struct intel_crtc *crtc) goto out; DRM_DEBUG_KMS("disabling %s\n", pll->name); - pll->funcs.disable(dev_priv, pll); + pll->info->funcs->disable(dev_priv, pll); pll->on = false; out: @@ -2414,7 +2414,6 @@ void intel_shared_dpll_init(struct drm_device *dev) dev_priv->shared_dplls[i].id = dpll_info[i].id; dev_priv->shared_dplls[i].name = dpll_info[i].name; - dev_priv->shared_dplls[i].funcs = *dpll_info[i].funcs; dev_priv->shared_dplls[i].flags = dpll_info[i].flags; } diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h index bd2d3652cec4..f49382207a0a 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h @@ -211,6 +211,9 @@ struct intel_shared_dpll_funcs { struct dpll_info { const char *name; const int id; + /** + * @funcs: platform specific hooks + */ const struct intel_shared_dpll_funcs *funcs; uint32_t flags; }; @@ -248,11 +251,6 @@ struct intel_shared_dpll { */ enum intel_dpll_id id; - /** - * @funcs: platform specific hooks - */ - struct intel_shared_dpll_funcs funcs; - /** * @info: platform specific info */ -- cgit v1.2.3 From 72f775fa284886893bec4a189ed38ac30e2535aa Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 20 Mar 2018 15:06:34 -0700 Subject: drm/i915: use name from intel_shared_dpll.info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace all users of pll->name to use pll->info->name. Signed-off-by: Lucas De Marchi Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180320220637.21480-5-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 3 ++- drivers/gpu/drm/i915/intel_display.c | 7 ++++--- drivers/gpu/drm/i915/intel_dpll_mgr.c | 26 ++++++++++++++------------ drivers/gpu/drm/i915/intel_dpll_mgr.h | 8 +++----- 4 files changed, 23 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 7816cd53100a..057fe12124d8 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3285,7 +3285,8 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused) for (i = 0; i < dev_priv->num_shared_dpll; i++) { struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; - seq_printf(m, "DPLL%i: %s, id: %i\n", i, pll->name, pll->id); + seq_printf(m, "DPLL%i: %s, id: %i\n", i, pll->info->name, + pll->id); seq_printf(m, " crtc_mask: 0x%08x, active: 0x%x, on: %s\n", pll->state.crtc_mask, pll->active_mask, yesno(pll->on)); seq_printf(m, " tracked hardware state:\n"); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cee9ea3b7eeb..5f79444d12c5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11653,7 +11653,7 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv, memset(&dpll_hw_state, 0, sizeof(dpll_hw_state)); - DRM_DEBUG_KMS("%s\n", pll->name); + DRM_DEBUG_KMS("%s\n", pll->info->name); active = pll->info->funcs->get_hw_state(dev_priv, pll, &dpll_hw_state); @@ -15142,7 +15142,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) pll->active_mask = pll->state.crtc_mask; DRM_DEBUG_KMS("%s hw state readout: crtc_mask 0x%08x, on %i\n", - pll->name, pll->state.crtc_mask, pll->on); + pll->info->name, pll->state.crtc_mask, pll->on); } for_each_intel_encoder(dev, encoder) { @@ -15316,7 +15316,8 @@ intel_modeset_setup_hw_state(struct drm_device *dev, if (!pll->on || pll->active_mask) continue; - DRM_DEBUG_KMS("%s enabled but not in use, disabling\n", pll->name); + DRM_DEBUG_KMS("%s enabled but not in use, disabling\n", + pll->info->name); pll->info->funcs->disable(dev_priv, pll); pll->on = false; diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 24d9aa180e0c..ed46ade0efff 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -121,7 +121,7 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv, cur_state = pll->info->funcs->get_hw_state(dev_priv, pll, &hw_state); I915_STATE_WARN(cur_state != state, "%s assertion failure (expected %s, current %s)\n", - pll->name, onoff(state), onoff(cur_state)); + pll->info->name, onoff(state), onoff(cur_state)); } /** @@ -143,7 +143,7 @@ void intel_prepare_shared_dpll(struct intel_crtc *crtc) mutex_lock(&dev_priv->dpll_lock); WARN_ON(!pll->state.crtc_mask); if (!pll->active_mask) { - DRM_DEBUG_DRIVER("setting up %s\n", pll->name); + DRM_DEBUG_DRIVER("setting up %s\n", pll->info->name); WARN_ON(pll->on); assert_shared_dpll_disabled(dev_priv, pll); @@ -179,7 +179,7 @@ void intel_enable_shared_dpll(struct intel_crtc *crtc) pll->active_mask |= crtc_mask; DRM_DEBUG_KMS("enable %s (active %x, on? %d) for crtc %d\n", - pll->name, pll->active_mask, pll->on, + pll->info->name, pll->active_mask, pll->on, crtc->base.base.id); if (old_mask) { @@ -189,7 +189,7 @@ void intel_enable_shared_dpll(struct intel_crtc *crtc) } WARN_ON(pll->on); - DRM_DEBUG_KMS("enabling %s\n", pll->name); + DRM_DEBUG_KMS("enabling %s\n", pll->info->name); pll->info->funcs->enable(dev_priv, pll); pll->on = true; @@ -221,7 +221,7 @@ void intel_disable_shared_dpll(struct intel_crtc *crtc) goto out; DRM_DEBUG_KMS("disable %s (active %x, on? %d) for crtc %d\n", - pll->name, pll->active_mask, pll->on, + pll->info->name, pll->active_mask, pll->on, crtc->base.base.id); assert_shared_dpll_enabled(dev_priv, pll); @@ -231,7 +231,7 @@ void intel_disable_shared_dpll(struct intel_crtc *crtc) if (pll->active_mask) goto out; - DRM_DEBUG_KMS("disabling %s\n", pll->name); + DRM_DEBUG_KMS("disabling %s\n", pll->info->name); pll->info->funcs->disable(dev_priv, pll); pll->on = false; @@ -263,7 +263,8 @@ intel_find_shared_dpll(struct intel_crtc *crtc, &shared_dpll[i].hw_state, sizeof(crtc_state->dpll_hw_state)) == 0) { DRM_DEBUG_KMS("[CRTC:%d:%s] sharing existing %s (crtc mask 0x%08x, active %x)\n", - crtc->base.base.id, crtc->base.name, pll->name, + crtc->base.base.id, crtc->base.name, + pll->info->name, shared_dpll[i].crtc_mask, pll->active_mask); return pll; @@ -275,7 +276,8 @@ intel_find_shared_dpll(struct intel_crtc *crtc, pll = &dev_priv->shared_dplls[i]; if (shared_dpll[i].crtc_mask == 0) { DRM_DEBUG_KMS("[CRTC:%d:%s] allocated %s\n", - crtc->base.base.id, crtc->base.name, pll->name); + crtc->base.base.id, crtc->base.name, + pll->info->name); return pll; } } @@ -298,7 +300,7 @@ intel_reference_shared_dpll(struct intel_shared_dpll *pll, crtc_state->dpll_hw_state; crtc_state->shared_dpll = pll; - DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name, + DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->info->name, pipe_name(crtc->pipe)); shared_dpll[pll->id].crtc_mask |= 1 << crtc->pipe; @@ -429,7 +431,8 @@ ibx_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, pll = &dev_priv->shared_dplls[i]; DRM_DEBUG_KMS("[CRTC:%d:%s] using pre-allocated %s\n", - crtc->base.base.id, crtc->base.name, pll->name); + crtc->base.base.id, crtc->base.name, + pll->info->name); } else { pll = intel_find_shared_dpll(crtc, crtc_state, DPLL_ID_PCH_PLL_A, @@ -1824,7 +1827,7 @@ bxt_get_dpll(struct intel_crtc *crtc, pll = intel_get_shared_dpll_by_id(dev_priv, i); DRM_DEBUG_KMS("[CRTC:%d:%s] using pre-allocated %s\n", - crtc->base.base.id, crtc->base.name, pll->name); + crtc->base.base.id, crtc->base.name, pll->info->name); intel_reference_shared_dpll(pll, crtc_state); @@ -2413,7 +2416,6 @@ void intel_shared_dpll_init(struct drm_device *dev) dev_priv->shared_dplls[i].info = &dpll_info[i]; dev_priv->shared_dplls[i].id = dpll_info[i].id; - dev_priv->shared_dplls[i].name = dpll_info[i].name; dev_priv->shared_dplls[i].flags = dpll_info[i].flags; } diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h index f49382207a0a..e5ed3e0269e3 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h @@ -209,6 +209,9 @@ struct intel_shared_dpll_funcs { * struct dpll_info - display PLL platform specific info */ struct dpll_info { + /** + * @name: DPLL name; used for logging + */ const char *name; const int id; /** @@ -240,11 +243,6 @@ struct intel_shared_dpll { */ bool on; - /** - * @name: DPLL name; used for logging - */ - const char *name; - /** * @id: unique indentifier for this DPLL; should match the index in the * dev_priv->shared_dplls array -- cgit v1.2.3 From 0823eb9c52f9e47564277e5bdd6b78cd95cf9f9c Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 20 Mar 2018 15:06:35 -0700 Subject: drm/i915: use id from intel_shared_dpll.info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace all users of pll->id to use pll->info->id. In functions using this more than once it was preferred to add an id variable to make the code easier to read. Signed-off-by: Lucas De Marchi Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180320220637.21480-6-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/intel_ddi.c | 8 +- drivers/gpu/drm/i915/intel_dpll_mgr.c | 160 +++++++++++++++++++--------------- drivers/gpu/drm/i915/intel_dpll_mgr.h | 10 +-- 4 files changed, 98 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 057fe12124d8..ff90577da450 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3286,7 +3286,7 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused) struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; seq_printf(m, "DPLL%i: %s, id: %i\n", i, pll->info->name, - pll->id); + pll->info->id); seq_printf(m, " crtc_mask: 0x%08x, active: 0x%x, on: %s\n", pll->state.crtc_mask, pll->active_mask, yesno(pll->on)); seq_printf(m, " tracked hardware state:\n"); diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 359acbfec4b1..a6672a9abd85 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -994,7 +994,7 @@ static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, static uint32_t hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll) { - switch (pll->id) { + switch (pll->info->id) { case DPLL_ID_WRPLL1: return PORT_CLK_SEL_WRPLL1; case DPLL_ID_WRPLL2: @@ -1008,7 +1008,7 @@ static uint32_t hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll) case DPLL_ID_LCPLL_2700: return PORT_CLK_SEL_LCPLL_2700; default: - MISSING_CASE(pll->id); + MISSING_CASE(pll->info->id); return PORT_CLK_SEL_NONE; } } @@ -2250,7 +2250,7 @@ static void intel_ddi_clk_select(struct intel_encoder *encoder, /* Configure DPCLKA_CFGCR0 to map the DPLL to the DDI. */ val = I915_READ(DPCLKA_CFGCR0); val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port); - val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->id, port); + val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port); I915_WRITE(DPCLKA_CFGCR0, val); /* @@ -2267,7 +2267,7 @@ static void intel_ddi_clk_select(struct intel_encoder *encoder, val &= ~(DPLL_CTRL2_DDI_CLK_OFF(port) | DPLL_CTRL2_DDI_CLK_SEL_MASK(port)); - val |= (DPLL_CTRL2_DDI_CLK_SEL(pll->id, port) | + val |= (DPLL_CTRL2_DDI_CLK_SEL(pll->info->id, port) | DPLL_CTRL2_DDI_SEL_OVERRIDE(port)); I915_WRITE(DPLL_CTRL2, val); diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index ed46ade0efff..48466b19d1f6 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -291,19 +291,19 @@ intel_reference_shared_dpll(struct intel_shared_dpll *pll, { struct intel_shared_dpll_state *shared_dpll; struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); - enum intel_dpll_id i = pll->id; + const enum intel_dpll_id id = pll->info->id; shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state); - if (shared_dpll[i].crtc_mask == 0) - shared_dpll[i].hw_state = + if (shared_dpll[id].crtc_mask == 0) + shared_dpll[id].hw_state = crtc_state->dpll_hw_state; crtc_state->shared_dpll = pll; DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->info->name, pipe_name(crtc->pipe)); - shared_dpll[pll->id].crtc_mask |= 1 << crtc->pipe; + shared_dpll[id].crtc_mask |= 1 << crtc->pipe; } /** @@ -343,15 +343,16 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { + const enum intel_dpll_id id = pll->info->id; uint32_t val; if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS)) return false; - val = I915_READ(PCH_DPLL(pll->id)); + val = I915_READ(PCH_DPLL(id)); hw_state->dpll = val; - hw_state->fp0 = I915_READ(PCH_FP0(pll->id)); - hw_state->fp1 = I915_READ(PCH_FP1(pll->id)); + hw_state->fp0 = I915_READ(PCH_FP0(id)); + hw_state->fp1 = I915_READ(PCH_FP1(id)); intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS); @@ -361,8 +362,10 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv, static void ibx_pch_dpll_prepare(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { - I915_WRITE(PCH_FP0(pll->id), pll->state.hw_state.fp0); - I915_WRITE(PCH_FP1(pll->id), pll->state.hw_state.fp1); + const enum intel_dpll_id id = pll->info->id; + + I915_WRITE(PCH_FP0(id), pll->state.hw_state.fp0); + I915_WRITE(PCH_FP1(id), pll->state.hw_state.fp1); } static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) @@ -381,13 +384,15 @@ static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { + const enum intel_dpll_id id = pll->info->id; + /* PCH refclock must be enabled first */ ibx_assert_pch_refclk_enabled(dev_priv); - I915_WRITE(PCH_DPLL(pll->id), pll->state.hw_state.dpll); + I915_WRITE(PCH_DPLL(id), pll->state.hw_state.dpll); /* Wait for the clocks to stabilize. */ - POSTING_READ(PCH_DPLL(pll->id)); + POSTING_READ(PCH_DPLL(id)); udelay(150); /* The pixel multiplier can only be updated once the @@ -395,14 +400,15 @@ static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, * * So write it again. */ - I915_WRITE(PCH_DPLL(pll->id), pll->state.hw_state.dpll); - POSTING_READ(PCH_DPLL(pll->id)); + I915_WRITE(PCH_DPLL(id), pll->state.hw_state.dpll); + POSTING_READ(PCH_DPLL(id)); udelay(200); } static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { + const enum intel_dpll_id id = pll->info->id; struct drm_device *dev = &dev_priv->drm; struct intel_crtc *crtc; @@ -412,8 +418,8 @@ static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv, assert_pch_transcoder_disabled(dev_priv, crtc->pipe); } - I915_WRITE(PCH_DPLL(pll->id), 0); - POSTING_READ(PCH_DPLL(pll->id)); + I915_WRITE(PCH_DPLL(id), 0); + POSTING_READ(PCH_DPLL(id)); udelay(200); } @@ -469,8 +475,10 @@ static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = { static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { - I915_WRITE(WRPLL_CTL(pll->id), pll->state.hw_state.wrpll); - POSTING_READ(WRPLL_CTL(pll->id)); + const enum intel_dpll_id id = pll->info->id; + + I915_WRITE(WRPLL_CTL(id), pll->state.hw_state.wrpll); + POSTING_READ(WRPLL_CTL(id)); udelay(20); } @@ -485,11 +493,12 @@ static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv, static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { + const enum intel_dpll_id id = pll->info->id; uint32_t val; - val = I915_READ(WRPLL_CTL(pll->id)); - I915_WRITE(WRPLL_CTL(pll->id), val & ~WRPLL_PLL_ENABLE); - POSTING_READ(WRPLL_CTL(pll->id)); + val = I915_READ(WRPLL_CTL(id)); + I915_WRITE(WRPLL_CTL(id), val & ~WRPLL_PLL_ENABLE); + POSTING_READ(WRPLL_CTL(id)); } static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv, @@ -506,12 +515,13 @@ static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { + const enum intel_dpll_id id = pll->info->id; uint32_t val; if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS)) return false; - val = I915_READ(WRPLL_CTL(pll->id)); + val = I915_READ(WRPLL_CTL(id)); hw_state->wrpll = val; intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS); @@ -917,13 +927,15 @@ static const struct skl_dpll_regs skl_dpll_regs[4] = { static void skl_ddi_pll_write_ctrl1(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { + const enum intel_dpll_id id = pll->info->id; uint32_t val; val = I915_READ(DPLL_CTRL1); - val &= ~(DPLL_CTRL1_HDMI_MODE(pll->id) | DPLL_CTRL1_SSC(pll->id) | - DPLL_CTRL1_LINK_RATE_MASK(pll->id)); - val |= pll->state.hw_state.ctrl1 << (pll->id * 6); + val &= ~(DPLL_CTRL1_HDMI_MODE(id) | + DPLL_CTRL1_SSC(id) | + DPLL_CTRL1_LINK_RATE_MASK(id)); + val |= pll->state.hw_state.ctrl1 << (id * 6); I915_WRITE(DPLL_CTRL1, val); POSTING_READ(DPLL_CTRL1); @@ -933,24 +945,25 @@ static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { const struct skl_dpll_regs *regs = skl_dpll_regs; + const enum intel_dpll_id id = pll->info->id; skl_ddi_pll_write_ctrl1(dev_priv, pll); - I915_WRITE(regs[pll->id].cfgcr1, pll->state.hw_state.cfgcr1); - I915_WRITE(regs[pll->id].cfgcr2, pll->state.hw_state.cfgcr2); - POSTING_READ(regs[pll->id].cfgcr1); - POSTING_READ(regs[pll->id].cfgcr2); + I915_WRITE(regs[id].cfgcr1, pll->state.hw_state.cfgcr1); + I915_WRITE(regs[id].cfgcr2, pll->state.hw_state.cfgcr2); + POSTING_READ(regs[id].cfgcr1); + POSTING_READ(regs[id].cfgcr2); /* the enable bit is always bit 31 */ - I915_WRITE(regs[pll->id].ctl, - I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE); + I915_WRITE(regs[id].ctl, + I915_READ(regs[id].ctl) | LCPLL_PLL_ENABLE); if (intel_wait_for_register(dev_priv, DPLL_STATUS, - DPLL_LOCK(pll->id), - DPLL_LOCK(pll->id), + DPLL_LOCK(id), + DPLL_LOCK(id), 5)) - DRM_ERROR("DPLL %d not locked\n", pll->id); + DRM_ERROR("DPLL %d not locked\n", id); } static void skl_ddi_dpll0_enable(struct drm_i915_private *dev_priv, @@ -963,11 +976,12 @@ static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { const struct skl_dpll_regs *regs = skl_dpll_regs; + const enum intel_dpll_id id = pll->info->id; /* the enable bit is always bit 31 */ - I915_WRITE(regs[pll->id].ctl, - I915_READ(regs[pll->id].ctl) & ~LCPLL_PLL_ENABLE); - POSTING_READ(regs[pll->id].ctl); + I915_WRITE(regs[id].ctl, + I915_READ(regs[id].ctl) & ~LCPLL_PLL_ENABLE); + POSTING_READ(regs[id].ctl); } static void skl_ddi_dpll0_disable(struct drm_i915_private *dev_priv, @@ -981,6 +995,7 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, { uint32_t val; const struct skl_dpll_regs *regs = skl_dpll_regs; + const enum intel_dpll_id id = pll->info->id; bool ret; if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS)) @@ -988,17 +1003,17 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, ret = false; - val = I915_READ(regs[pll->id].ctl); + val = I915_READ(regs[id].ctl); if (!(val & LCPLL_PLL_ENABLE)) goto out; val = I915_READ(DPLL_CTRL1); - hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f; + hw_state->ctrl1 = (val >> (id * 6)) & 0x3f; /* avoid reading back stale values if HDMI mode is not enabled */ - if (val & DPLL_CTRL1_HDMI_MODE(pll->id)) { - hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1); - hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2); + if (val & DPLL_CTRL1_HDMI_MODE(id)) { + hw_state->cfgcr1 = I915_READ(regs[id].cfgcr1); + hw_state->cfgcr2 = I915_READ(regs[id].cfgcr2); } ret = true; @@ -1014,6 +1029,7 @@ static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv, { uint32_t val; const struct skl_dpll_regs *regs = skl_dpll_regs; + const enum intel_dpll_id id = pll->info->id; bool ret; if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS)) @@ -1022,12 +1038,12 @@ static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv, ret = false; /* DPLL0 is always enabled since it drives CDCLK */ - val = I915_READ(regs[pll->id].ctl); + val = I915_READ(regs[id].ctl); if (WARN_ON(!(val & LCPLL_PLL_ENABLE))) goto out; val = I915_READ(DPLL_CTRL1); - hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f; + hw_state->ctrl1 = (val >> (id * 6)) & 0x3f; ret = true; @@ -1427,7 +1443,7 @@ static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { uint32_t temp; - enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */ + enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */ enum dpio_phy phy; enum dpio_channel ch; @@ -1546,7 +1562,7 @@ static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv, static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { - enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */ + enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */ uint32_t temp; temp = I915_READ(BXT_PORT_PLL_ENABLE(port)); @@ -1569,7 +1585,7 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { - enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */ + enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */ uint32_t val; bool ret; enum dpio_phy phy; @@ -1949,38 +1965,39 @@ static const struct intel_dpll_mgr bxt_pll_mgr = { static void cnl_ddi_pll_enable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { + const enum intel_dpll_id id = pll->info->id; uint32_t val; /* 1. Enable DPLL power in DPLL_ENABLE. */ - val = I915_READ(CNL_DPLL_ENABLE(pll->id)); + val = I915_READ(CNL_DPLL_ENABLE(id)); val |= PLL_POWER_ENABLE; - I915_WRITE(CNL_DPLL_ENABLE(pll->id), val); + I915_WRITE(CNL_DPLL_ENABLE(id), val); /* 2. Wait for DPLL power state enabled in DPLL_ENABLE. */ if (intel_wait_for_register(dev_priv, - CNL_DPLL_ENABLE(pll->id), + CNL_DPLL_ENABLE(id), PLL_POWER_STATE, PLL_POWER_STATE, 5)) - DRM_ERROR("PLL %d Power not enabled\n", pll->id); + DRM_ERROR("PLL %d Power not enabled\n", id); /* * 3. Configure DPLL_CFGCR0 to set SSC enable/disable, * select DP mode, and set DP link rate. */ val = pll->state.hw_state.cfgcr0; - I915_WRITE(CNL_DPLL_CFGCR0(pll->id), val); + I915_WRITE(CNL_DPLL_CFGCR0(id), val); /* 4. Reab back to ensure writes completed */ - POSTING_READ(CNL_DPLL_CFGCR0(pll->id)); + POSTING_READ(CNL_DPLL_CFGCR0(id)); /* 3. Configure DPLL_CFGCR0 */ /* Avoid touch CFGCR1 if HDMI mode is not enabled */ if (pll->state.hw_state.cfgcr0 & DPLL_CFGCR0_HDMI_MODE) { val = pll->state.hw_state.cfgcr1; - I915_WRITE(CNL_DPLL_CFGCR1(pll->id), val); + I915_WRITE(CNL_DPLL_CFGCR1(id), val); /* 4. Reab back to ensure writes completed */ - POSTING_READ(CNL_DPLL_CFGCR1(pll->id)); + POSTING_READ(CNL_DPLL_CFGCR1(id)); } /* @@ -1993,17 +2010,17 @@ static void cnl_ddi_pll_enable(struct drm_i915_private *dev_priv, */ /* 6. Enable DPLL in DPLL_ENABLE. */ - val = I915_READ(CNL_DPLL_ENABLE(pll->id)); + val = I915_READ(CNL_DPLL_ENABLE(id)); val |= PLL_ENABLE; - I915_WRITE(CNL_DPLL_ENABLE(pll->id), val); + I915_WRITE(CNL_DPLL_ENABLE(id), val); /* 7. Wait for PLL lock status in DPLL_ENABLE. */ if (intel_wait_for_register(dev_priv, - CNL_DPLL_ENABLE(pll->id), + CNL_DPLL_ENABLE(id), PLL_LOCK, PLL_LOCK, 5)) - DRM_ERROR("PLL %d not locked\n", pll->id); + DRM_ERROR("PLL %d not locked\n", id); /* * 8. If the frequency will result in a change to the voltage @@ -2023,6 +2040,7 @@ static void cnl_ddi_pll_enable(struct drm_i915_private *dev_priv, static void cnl_ddi_pll_disable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { + const enum intel_dpll_id id = pll->info->id; uint32_t val; /* @@ -2040,17 +2058,17 @@ static void cnl_ddi_pll_disable(struct drm_i915_private *dev_priv, */ /* 3. Disable DPLL through DPLL_ENABLE. */ - val = I915_READ(CNL_DPLL_ENABLE(pll->id)); + val = I915_READ(CNL_DPLL_ENABLE(id)); val &= ~PLL_ENABLE; - I915_WRITE(CNL_DPLL_ENABLE(pll->id), val); + I915_WRITE(CNL_DPLL_ENABLE(id), val); /* 4. Wait for PLL not locked status in DPLL_ENABLE. */ if (intel_wait_for_register(dev_priv, - CNL_DPLL_ENABLE(pll->id), + CNL_DPLL_ENABLE(id), PLL_LOCK, 0, 5)) - DRM_ERROR("PLL %d locked\n", pll->id); + DRM_ERROR("PLL %d locked\n", id); /* * 5. If the frequency will result in a change to the voltage @@ -2062,23 +2080,24 @@ static void cnl_ddi_pll_disable(struct drm_i915_private *dev_priv, */ /* 6. Disable DPLL power in DPLL_ENABLE. */ - val = I915_READ(CNL_DPLL_ENABLE(pll->id)); + val = I915_READ(CNL_DPLL_ENABLE(id)); val &= ~PLL_POWER_ENABLE; - I915_WRITE(CNL_DPLL_ENABLE(pll->id), val); + I915_WRITE(CNL_DPLL_ENABLE(id), val); /* 7. Wait for DPLL power state disabled in DPLL_ENABLE. */ if (intel_wait_for_register(dev_priv, - CNL_DPLL_ENABLE(pll->id), + CNL_DPLL_ENABLE(id), PLL_POWER_STATE, 0, 5)) - DRM_ERROR("PLL %d Power not disabled\n", pll->id); + DRM_ERROR("PLL %d Power not disabled\n", id); } static bool cnl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { + const enum intel_dpll_id id = pll->info->id; uint32_t val; bool ret; @@ -2087,16 +2106,16 @@ static bool cnl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, ret = false; - val = I915_READ(CNL_DPLL_ENABLE(pll->id)); + val = I915_READ(CNL_DPLL_ENABLE(id)); if (!(val & PLL_ENABLE)) goto out; - val = I915_READ(CNL_DPLL_CFGCR0(pll->id)); + val = I915_READ(CNL_DPLL_CFGCR0(id)); hw_state->cfgcr0 = val; /* avoid reading back stale values if HDMI mode is not enabled */ if (val & DPLL_CFGCR0_HDMI_MODE) { - hw_state->cfgcr1 = I915_READ(CNL_DPLL_CFGCR1(pll->id)); + hw_state->cfgcr1 = I915_READ(CNL_DPLL_CFGCR1(id)); } ret = true; @@ -2415,7 +2434,6 @@ void intel_shared_dpll_init(struct drm_device *dev) WARN_ON(i != dpll_info[i].id); dev_priv->shared_dplls[i].info = &dpll_info[i]; - dev_priv->shared_dplls[i].id = dpll_info[i].id; dev_priv->shared_dplls[i].flags = dpll_info[i].flags; } @@ -2476,7 +2494,7 @@ void intel_release_shared_dpll(struct intel_shared_dpll *dpll, struct intel_shared_dpll_state *shared_dpll_state; shared_dpll_state = intel_atomic_get_shared_dpll_state(state); - shared_dpll_state[dpll->id].crtc_mask &= ~(1 << crtc->pipe); + shared_dpll_state[dpll->info->id].crtc_mask &= ~(1 << crtc->pipe); } /** diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h index e5ed3e0269e3..7c95ecce41ee 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h @@ -213,6 +213,10 @@ struct dpll_info { * @name: DPLL name; used for logging */ const char *name; + /** + * @id: unique indentifier for this DPLL; should match the index in the + * dev_priv->shared_dplls array + */ const int id; /** * @funcs: platform specific hooks @@ -243,12 +247,6 @@ struct intel_shared_dpll { */ bool on; - /** - * @id: unique indentifier for this DPLL; should match the index in the - * dev_priv->shared_dplls array - */ - enum intel_dpll_id id; - /** * @info: platform specific info */ -- cgit v1.2.3 From 5cd281f679f3ccb517f87589fe4070a3f8014d08 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 20 Mar 2018 15:06:36 -0700 Subject: drm/i915: use flags from dpll_info embedded in intel_shared_dpll MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace all users of pll->flags to use pll->info.flags. Signed-off-by: Lucas De Marchi Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180320220637.21480-7-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_dpll_mgr.c | 2 -- drivers/gpu/drm/i915/intel_dpll_mgr.h | 18 ++++++++---------- 3 files changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5f79444d12c5..64dd88e49bd9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11657,7 +11657,7 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv, active = pll->info->funcs->get_hw_state(dev_priv, pll, &dpll_hw_state); - if (!(pll->flags & INTEL_DPLL_ALWAYS_ON)) { + if (!(pll->info->flags & INTEL_DPLL_ALWAYS_ON)) { I915_STATE_WARN(!pll->on && pll->active_mask, "pll in active use but not on in sw tracking\n"); I915_STATE_WARN(pll->on && !pll->active_mask, diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 48466b19d1f6..bda69e1ccd76 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -2433,8 +2433,6 @@ void intel_shared_dpll_init(struct drm_device *dev) for (i = 0; dpll_info[i].id >= 0; i++) { WARN_ON(i != dpll_info[i].id); dev_priv->shared_dplls[i].info = &dpll_info[i]; - - dev_priv->shared_dplls[i].flags = dpll_info[i].flags; } dev_priv->dpll_mgr = dpll_mgr; diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h index 7c95ecce41ee..e4c01e487be7 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h @@ -222,6 +222,14 @@ struct dpll_info { * @funcs: platform specific hooks */ const struct intel_shared_dpll_funcs *funcs; +#define INTEL_DPLL_ALWAYS_ON (1 << 0) + /** + * @flags: + * + * INTEL_DPLL_ALWAYS_ON + * Inform the state checker that the DPLL is kept enabled even if + * not in use by any CRTC. + */ uint32_t flags; }; @@ -251,16 +259,6 @@ struct intel_shared_dpll { * @info: platform specific info */ const struct dpll_info *info; - -#define INTEL_DPLL_ALWAYS_ON (1 << 0) - /** - * @flags: - * - * INTEL_DPLL_ALWAYS_ON - * Inform the state checker that the DPLL is kept enabled even if - * not in use by any CRTC. - */ - uint32_t flags; }; #define SKL_DPLL0 0 -- cgit v1.2.3 From 7fd9e829931349ad417579a718213c2b8369bff4 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 20 Mar 2018 15:06:37 -0700 Subject: drm/i915: reorder dpll_info members MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove 4-bytes hole in this struct an reorder tables accordingly. This also changes the last element of the tables to be more future-proof. Signed-off-by: Lucas De Marchi Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180320220637.21480-8-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/intel_dpll_mgr.c | 48 +++++++++++++++++------------------ drivers/gpu/drm/i915/intel_dpll_mgr.h | 13 ++++++---- 2 files changed, 32 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index bda69e1ccd76..d5e114e9660b 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -1908,9 +1908,9 @@ struct intel_dpll_mgr { }; static const struct dpll_info pch_plls[] = { - { "PCH DPLL A", DPLL_ID_PCH_PLL_A, &ibx_pch_dpll_funcs, 0 }, - { "PCH DPLL B", DPLL_ID_PCH_PLL_B, &ibx_pch_dpll_funcs, 0 }, - { NULL, -1, NULL, 0 }, + { "PCH DPLL A", &ibx_pch_dpll_funcs, DPLL_ID_PCH_PLL_A, 0 }, + { "PCH DPLL B", &ibx_pch_dpll_funcs, DPLL_ID_PCH_PLL_B, 0 }, + { }, }; static const struct intel_dpll_mgr pch_pll_mgr = { @@ -1920,13 +1920,13 @@ static const struct intel_dpll_mgr pch_pll_mgr = { }; static const struct dpll_info hsw_plls[] = { - { "WRPLL 1", DPLL_ID_WRPLL1, &hsw_ddi_wrpll_funcs, 0 }, - { "WRPLL 2", DPLL_ID_WRPLL2, &hsw_ddi_wrpll_funcs, 0 }, - { "SPLL", DPLL_ID_SPLL, &hsw_ddi_spll_funcs, 0 }, - { "LCPLL 810", DPLL_ID_LCPLL_810, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON }, - { "LCPLL 1350", DPLL_ID_LCPLL_1350, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON }, - { "LCPLL 2700", DPLL_ID_LCPLL_2700, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON }, - { NULL, -1, NULL, }, + { "WRPLL 1", &hsw_ddi_wrpll_funcs, DPLL_ID_WRPLL1, 0 }, + { "WRPLL 2", &hsw_ddi_wrpll_funcs, DPLL_ID_WRPLL2, 0 }, + { "SPLL", &hsw_ddi_spll_funcs, DPLL_ID_SPLL, 0 }, + { "LCPLL 810", &hsw_ddi_lcpll_funcs, DPLL_ID_LCPLL_810, INTEL_DPLL_ALWAYS_ON }, + { "LCPLL 1350", &hsw_ddi_lcpll_funcs, DPLL_ID_LCPLL_1350, INTEL_DPLL_ALWAYS_ON }, + { "LCPLL 2700", &hsw_ddi_lcpll_funcs, DPLL_ID_LCPLL_2700, INTEL_DPLL_ALWAYS_ON }, + { }, }; static const struct intel_dpll_mgr hsw_pll_mgr = { @@ -1936,11 +1936,11 @@ static const struct intel_dpll_mgr hsw_pll_mgr = { }; static const struct dpll_info skl_plls[] = { - { "DPLL 0", DPLL_ID_SKL_DPLL0, &skl_ddi_dpll0_funcs, INTEL_DPLL_ALWAYS_ON }, - { "DPLL 1", DPLL_ID_SKL_DPLL1, &skl_ddi_pll_funcs, 0 }, - { "DPLL 2", DPLL_ID_SKL_DPLL2, &skl_ddi_pll_funcs, 0 }, - { "DPLL 3", DPLL_ID_SKL_DPLL3, &skl_ddi_pll_funcs, 0 }, - { NULL, -1, NULL, }, + { "DPLL 0", &skl_ddi_dpll0_funcs, DPLL_ID_SKL_DPLL0, INTEL_DPLL_ALWAYS_ON }, + { "DPLL 1", &skl_ddi_pll_funcs, DPLL_ID_SKL_DPLL1, 0 }, + { "DPLL 2", &skl_ddi_pll_funcs, DPLL_ID_SKL_DPLL2, 0 }, + { "DPLL 3", &skl_ddi_pll_funcs, DPLL_ID_SKL_DPLL3, 0 }, + { }, }; static const struct intel_dpll_mgr skl_pll_mgr = { @@ -1950,10 +1950,10 @@ static const struct intel_dpll_mgr skl_pll_mgr = { }; static const struct dpll_info bxt_plls[] = { - { "PORT PLL A", DPLL_ID_SKL_DPLL0, &bxt_ddi_pll_funcs, 0 }, - { "PORT PLL B", DPLL_ID_SKL_DPLL1, &bxt_ddi_pll_funcs, 0 }, - { "PORT PLL C", DPLL_ID_SKL_DPLL2, &bxt_ddi_pll_funcs, 0 }, - { NULL, -1, NULL, }, + { "PORT PLL A", &bxt_ddi_pll_funcs, DPLL_ID_SKL_DPLL0, 0 }, + { "PORT PLL B", &bxt_ddi_pll_funcs, DPLL_ID_SKL_DPLL1, 0 }, + { "PORT PLL C", &bxt_ddi_pll_funcs, DPLL_ID_SKL_DPLL2, 0 }, + { }, }; static const struct intel_dpll_mgr bxt_pll_mgr = { @@ -2387,10 +2387,10 @@ static const struct intel_shared_dpll_funcs cnl_ddi_pll_funcs = { }; static const struct dpll_info cnl_plls[] = { - { "DPLL 0", DPLL_ID_SKL_DPLL0, &cnl_ddi_pll_funcs, 0 }, - { "DPLL 1", DPLL_ID_SKL_DPLL1, &cnl_ddi_pll_funcs, 0 }, - { "DPLL 2", DPLL_ID_SKL_DPLL2, &cnl_ddi_pll_funcs, 0 }, - { NULL, -1, NULL, }, + { "DPLL 0", &cnl_ddi_pll_funcs, DPLL_ID_SKL_DPLL0, 0 }, + { "DPLL 1", &cnl_ddi_pll_funcs, DPLL_ID_SKL_DPLL1, 0 }, + { "DPLL 2", &cnl_ddi_pll_funcs, DPLL_ID_SKL_DPLL2, 0 }, + { }, }; static const struct intel_dpll_mgr cnl_pll_mgr = { @@ -2430,7 +2430,7 @@ void intel_shared_dpll_init(struct drm_device *dev) dpll_info = dpll_mgr->dpll_info; - for (i = 0; dpll_info[i].id >= 0; i++) { + for (i = 0; dpll_info[i].name; i++) { WARN_ON(i != dpll_info[i].id); dev_priv->shared_dplls[i].info = &dpll_info[i]; } diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h index e4c01e487be7..4febfaa90bde 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h @@ -213,15 +213,18 @@ struct dpll_info { * @name: DPLL name; used for logging */ const char *name; - /** - * @id: unique indentifier for this DPLL; should match the index in the - * dev_priv->shared_dplls array - */ - const int id; + /** * @funcs: platform specific hooks */ const struct intel_shared_dpll_funcs *funcs; + + /** + * @id: unique indentifier for this DPLL; should match the index in the + * dev_priv->shared_dplls array + */ + enum intel_dpll_id id; + #define INTEL_DPLL_ALWAYS_ON (1 << 0) /** * @flags: -- cgit v1.2.3 From fbe6f8f2a648584b97beeaaaeff75b795fb3c6cb Mon Sep 17 00:00:00 2001 From: Yaodong Li Date: Thu, 22 Mar 2018 16:59:22 -0700 Subject: drm/i915: Use correct reST syntax for WOPCM and GuC kernel-doc diagrams GuC Address Space and WOPCM Layout diagrams won't be generated correctly by sphinx build if not using proper reST syntax. This patch uses reST literal blocks to make sure GuC Address Space and WOPCM Layout diagrams to be generated correctly, and it also corrects some errors in the diagram description. v2: - Fixed errors in diagram description v3: - Updated GuC Address Space kernel-doc based on Michal's suggestion v4: - Added WOPCM layout and GuC address space docs into i915.rst (Joonas) Signed-off-by: Jackie Li Cc: Michal Wajdeczko Cc: Sagar Arun Kamble Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen Signed-off-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/1521763162-11424-1-git-send-email-yaodong.li@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 56 ++++++++++++++++++++------------------ drivers/gpu/drm/i915/intel_wopcm.c | 44 ++++++++++++++++-------------- 2 files changed, 52 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 8f93f5bef8fd..c5f64c762f0a 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -494,35 +494,37 @@ int intel_guc_resume(struct intel_guc *guc) /** * DOC: GuC Address Space * - * The layout of GuC address space is shown as below: + * The layout of GuC address space is shown below: * - * +==============> +====================+ <== GUC_GGTT_TOP - * ^ | | - * | | | - * | | DRAM | - * | | Memory | - * | | | - * GuC | | - * Address +========> +====================+ <== WOPCM Top - * Space ^ | HW contexts RSVD | - * | | | WOPCM | - * | | +==> +--------------------+ <== GuC WOPCM Top - * | GuC ^ | | - * | GGTT | | | - * | Pin GuC | GuC | - * | Bias WOPCM | WOPCM | - * | | Size | | - * | | | | | - * v v v | | - * +=====+=====+==> +====================+ <== GuC WOPCM Base - * | Non-GuC WOPCM | - * | (HuC/Reserved) | - * +====================+ <== WOPCM Base + * :: * - * The lower part [0, GuC ggtt_pin_bias) is mapped to WOPCM which consists of - * GuC WOPCM and WOPCM reserved for other usage (e.g.RC6 context). The value of - * the GuC ggtt_pin_bias is determined by the actually GuC WOPCM size which is - * set in GUC_WOPCM_SIZE register. + * +==============> +====================+ <== GUC_GGTT_TOP + * ^ | | + * | | | + * | | DRAM | + * | | Memory | + * | | | + * GuC | | + * Address +========> +====================+ <== WOPCM Top + * Space ^ | HW contexts RSVD | + * | | | WOPCM | + * | | +==> +--------------------+ <== GuC WOPCM Top + * | GuC ^ | | + * | GGTT | | | + * | Pin GuC | GuC | + * | Bias WOPCM | WOPCM | + * | | Size | | + * | | | | | + * v v v | | + * +=====+=====+==> +====================+ <== GuC WOPCM Base + * | Non-GuC WOPCM | + * | (HuC/Reserved) | + * +====================+ <== WOPCM Base + * + * The lower part of GuC Address Space [0, ggtt_pin_bias) is mapped to WOPCM + * while upper part of GuC Address Space [ggtt_pin_bias, GUC_GGTT_TOP) is mapped + * to DRAM. The value of the GuC ggtt_pin_bias is determined by WOPCM size and + * actual GuC WOPCM size. */ /** diff --git a/drivers/gpu/drm/i915/intel_wopcm.c b/drivers/gpu/drm/i915/intel_wopcm.c index 4117886bfb05..74bf76f3fddc 100644 --- a/drivers/gpu/drm/i915/intel_wopcm.c +++ b/drivers/gpu/drm/i915/intel_wopcm.c @@ -11,28 +11,30 @@ * DOC: WOPCM Layout * * The layout of the WOPCM will be fixed after writing to GuC WOPCM size and - * offset registers whose are calculated are determined by size of HuC/GuC - * firmware size and set of hw requirements/restrictions as shown below: + * offset registers whose values are calculated and determined by HuC/GuC + * firmware size and set of hardware requirements/restrictions as shown below: * - * +=========> +====================+ <== WOPCM Top - * ^ | HW contexts RSVD | - * | +===> +====================+ <== GuC WOPCM Top - * | ^ | | - * | | | | - * | | | | - * | GuC | | - * | WOPCM | | - * | Size +--------------------+ - * WOPCM | | GuC FW RSVD | - * | | +--------------------+ - * | | | GuC Stack RSVD | - * | | +------------------- + - * | v | GuC WOPCM RSVD | - * | +===> +====================+ <== GuC WOPCM base - * | | WOPCM RSVD | - * | +------------------- + <== HuC Firmware Top - * v | HuC FW | - * +=========> +====================+ <== WOPCM Base + * :: + * + * +=========> +====================+ <== WOPCM Top + * ^ | HW contexts RSVD | + * | +===> +====================+ <== GuC WOPCM Top + * | ^ | | + * | | | | + * | | | | + * | GuC | | + * | WOPCM | | + * | Size +--------------------+ + * WOPCM | | GuC FW RSVD | + * | | +--------------------+ + * | | | GuC Stack RSVD | + * | | +------------------- + + * | v | GuC WOPCM RSVD | + * | +===> +====================+ <== GuC WOPCM base + * | | WOPCM RSVD | + * | +------------------- + <== HuC Firmware Top + * v | HuC FW | + * +=========> +====================+ <== WOPCM Base * * GuC accessible WOPCM starts at GuC WOPCM base and ends at GuC WOPCM top. * The top part of the WOPCM is reserved for hardware contexts (e.g. RC6 -- cgit v1.2.3 From d775a7b1840ddc96e7f25af20989ff43f2809436 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 9 Jan 2018 21:28:35 -0200 Subject: drm/i915/gen11: add support for reading the timestamp frequency The only thing that differs here is that the crystal clock freq now has four possible values. This patch gets rid of the "Unknown gen, unable to compute..." message at boot for gen11. Reviewed-by: Lionel Landwerlin Signed-off-by: Paulo Zanoni Link: https://patchwork.freedesktop.org/patch/msgid/20180109232835.11478-18-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 6 +++ drivers/gpu/drm/i915/intel_device_info.c | 71 +++++++++++++++++++++++++------- 2 files changed, 61 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b0c55f9d401b..5a53d0e1583c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -861,6 +861,12 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK (1 << GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT) #define GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_19_2_MHZ 0 #define GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_24_MHZ 1 +#define GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT 3 +#define GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK (0x7 << GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT) +#define GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_24_MHZ 0 +#define GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_19_2_MHZ 1 +#define GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_38_4_MHZ 2 +#define GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_25_MHZ 3 #define GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_SHIFT 1 #define GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK (0x3 << GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_SHIFT) diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 0d1509e25db8..a32ba72c514e 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -596,6 +596,52 @@ static u32 read_reference_ts_freq(struct drm_i915_private *dev_priv) return base_freq + frac_freq; } +static u32 gen10_get_crystal_clock_freq(struct drm_i915_private *dev_priv, + u32 rpm_config_reg) +{ + u32 f19_2_mhz = 19200; + u32 f24_mhz = 24000; + u32 crystal_clock = (rpm_config_reg & + GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK) >> + GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT; + + switch (crystal_clock) { + case GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_19_2_MHZ: + return f19_2_mhz; + case GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_24_MHZ: + return f24_mhz; + default: + MISSING_CASE(crystal_clock); + return 0; + } +} + +static u32 gen11_get_crystal_clock_freq(struct drm_i915_private *dev_priv, + u32 rpm_config_reg) +{ + u32 f19_2_mhz = 19200; + u32 f24_mhz = 24000; + u32 f25_mhz = 25000; + u32 f38_4_mhz = 38400; + u32 crystal_clock = (rpm_config_reg & + GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK) >> + GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT; + + switch (crystal_clock) { + case GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_24_MHZ: + return f24_mhz; + case GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_19_2_MHZ: + return f19_2_mhz; + case GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_38_4_MHZ: + return f38_4_mhz; + case GEN11_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_25_MHZ: + return f25_mhz; + default: + MISSING_CASE(crystal_clock); + return 0; + } +} + static u32 read_timestamp_frequency(struct drm_i915_private *dev_priv) { u32 f12_5_mhz = 12500; @@ -636,10 +682,9 @@ static u32 read_timestamp_frequency(struct drm_i915_private *dev_priv) } return freq; - } else if (INTEL_GEN(dev_priv) <= 10) { + } else if (INTEL_GEN(dev_priv) <= 11) { u32 ctc_reg = I915_READ(CTC_MODE); u32 freq = 0; - u32 rpm_config_reg = 0; /* First figure out the reference frequency. There are 2 ways * we can compute the frequency, either through the @@ -649,20 +694,14 @@ static u32 read_timestamp_frequency(struct drm_i915_private *dev_priv) if ((ctc_reg & CTC_SOURCE_PARAMETER_MASK) == CTC_SOURCE_DIVIDE_LOGIC) { freq = read_reference_ts_freq(dev_priv); } else { - u32 crystal_clock; - - rpm_config_reg = I915_READ(RPM_CONFIG0); - crystal_clock = (rpm_config_reg & - GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK) >> - GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT; - switch (crystal_clock) { - case GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_19_2_MHZ: - freq = f19_2_mhz; - break; - case GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_24_MHZ: - freq = f24_mhz; - break; - } + u32 rpm_config_reg = I915_READ(RPM_CONFIG0); + + if (INTEL_GEN(dev_priv) <= 10) + freq = gen10_get_crystal_clock_freq(dev_priv, + rpm_config_reg); + else + freq = gen11_get_crystal_clock_freq(dev_priv, + rpm_config_reg); /* Now figure out how the command stream's timestamp * register increments from this frequency (it might -- cgit v1.2.3 From c216e90686105e5b9fdbb22f6cfcc38334e432cc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 27 Mar 2018 22:01:36 +0100 Subject: drm/i915/execlists: Reset ring registers on rebinding contexts Tvrtko uncovered a fun issue with recovering from a wedge device. In his tests, he wedged the driver by injecting an unrecoverable hang whilst a batch was spinning. As we reset the gpu in the middle of the spinner, when resumed it would continue on from the next instruction in the ring and write it's breadcrumb. However, on wedging we updated our bookkeeping to indicate that the GPU had completed executing and would restart from after the breadcrumb; so the emission of the stale breadcrumb from before the reset came as a bit of a surprise. A simple fix is to when rebinding the context into the GPU, we update the ring register state in the context image to match our bookkeeping. We already have to update the RING_START and RING_TAIL, so updating RING_HEAD as well is trivial. This works because whenever we unbind the context, we keep the bookkeeping in check; and on wedging we unbind all contexts. Testcase: igt/gem_eio Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180327210136.16750-1-chris@chris-wilson.co.uk Tested-by: Tvrtko Ursulin Reviewed-by: Mika Kuoppala Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/intel_lrc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index ba7f7831f934..654634254b64 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1272,6 +1272,7 @@ execlists_context_pin(struct intel_engine_cs *engine, ce->lrc_reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE; ce->lrc_reg_state[CTX_RING_BUFFER_START+1] = i915_ggtt_offset(ce->ring->vma); + ce->lrc_reg_state[CTX_RING_HEAD+1] = ce->ring->head; ce->state->obj->pin_global++; i915_gem_context_get(ctx); -- cgit v1.2.3 From 4d82a174847b1b2d5e541ca7040398ac56efed7b Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 26 Mar 2018 19:48:18 +0000 Subject: drm/i915/guc: Add documentation for MMIO based communication As we are going to extend our use of MMIO based communication, try to explain its mechanics and update corresponding definitions. v2: fix checkpatch MACRO_ARG_REUSE Signed-off-by: Michal Wajdeczko Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Kelvin Gardiner Reviewed-by: Michel Thierry #1 Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180326194829.58836-2-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 20 ++++---- drivers/gpu/drm/i915/intel_guc_ct.c | 2 +- drivers/gpu/drm/i915/intel_guc_fwif.h | 88 ++++++++++++++++++++++++++++------- 3 files changed, 82 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index c5f64c762f0a..78e68b169cf2 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -329,6 +329,9 @@ int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len) GEM_BUG_ON(!len); GEM_BUG_ON(len > guc->send_regs.count); + /* We expect only action code */ + GEM_BUG_ON(*action & ~INTEL_GUC_MSG_CODE_MASK); + /* If CT is available, we expect to use MMIO only during init/fini */ GEM_BUG_ON(HAS_GUC_CT(dev_priv) && *action != INTEL_GUC_ACTION_REGISTER_COMMAND_TRANSPORT_BUFFER && @@ -350,18 +353,15 @@ int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len) */ ret = __intel_wait_for_register_fw(dev_priv, guc_send_reg(guc, 0), - INTEL_GUC_RECV_MASK, - INTEL_GUC_RECV_MASK, + INTEL_GUC_MSG_TYPE_MASK, + INTEL_GUC_MSG_TYPE_RESPONSE << + INTEL_GUC_MSG_TYPE_SHIFT, 10, 10, &status); - if (status != INTEL_GUC_STATUS_SUCCESS) { - /* - * Either the GuC explicitly returned an error (which - * we convert to -EIO here) or no response at all was - * received within the timeout limit (-ETIMEDOUT) - */ - if (ret != -ETIMEDOUT) - ret = -EIO; + /* If GuC explicitly returned an error, convert it to -EIO */ + if (!ret && !INTEL_GUC_MSG_IS_RESPONSE_SUCCESS(status)) + ret = -EIO; + if (ret) { DRM_DEBUG_DRIVER("INTEL_GUC_SEND: Action 0x%X failed;" " ret=%d status=0x%08X response=0x%08X\n", action[0], ret, status, diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index a726283489d1..1dafa7a20d89 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -398,7 +398,7 @@ static int ctch_send(struct intel_guc *guc, err = wait_for_response(desc, fence, status); if (unlikely(err)) return err; - if (*status != INTEL_GUC_STATUS_SUCCESS) + if (!INTEL_GUC_MSG_IS_RESPONSE_SUCCESS(*status)) return -EIO; return 0; } diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h index 72941bd704fd..83143e8a0730 100644 --- a/drivers/gpu/drm/i915/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -560,7 +560,68 @@ struct guc_shared_ctx_data { struct guc_ctx_report preempt_ctx_report[GUC_MAX_ENGINES_NUM]; } __packed; -/* This Action will be programmed in C180 - SOFT_SCRATCH_O_REG */ +/** + * DOC: MMIO based communication + * + * The MMIO based communication between Host and GuC uses software scratch + * registers, where first register holds data treated as message header, + * and other registers are used to hold message payload. + * + * For Gen9+, GuC uses software scratch registers 0xC180-0xC1B8 + * + * +-----------+---------+---------+---------+ + * | MMIO[0] | MMIO[1] | ... | MMIO[n] | + * +-----------+---------+---------+---------+ + * | header | optional payload | + * +======+====+=========+=========+=========+ + * | 31:28|type| | | | + * +------+----+ | | | + * | 27:16|data| | | | + * +------+----+ | | | + * | 15:0|code| | | | + * +------+----+---------+---------+---------+ + * + * The message header consists of: + * + * - **type**, indicates message type + * - **code**, indicates message code, is specific for **type** + * - **data**, indicates message data, optional, depends on **code** + * + * The following message **types** are supported: + * + * - **REQUEST**, indicates Host-to-GuC request, requested GuC action code + * must be priovided in **code** field. Optional action specific parameters + * can be provided in remaining payload registers or **data** field. + * + * - **RESPONSE**, indicates GuC-to-Host response from earlier GuC request, + * action response status will be provided in **code** field. Optional + * response data can be returned in remaining payload registers or **data** + * field. + */ + +#define INTEL_GUC_MSG_TYPE_SHIFT 28 +#define INTEL_GUC_MSG_TYPE_MASK (0xF << INTEL_GUC_MSG_TYPE_SHIFT) +#define INTEL_GUC_MSG_DATA_SHIFT 16 +#define INTEL_GUC_MSG_DATA_MASK (0xFFF << INTEL_GUC_MSG_DATA_SHIFT) +#define INTEL_GUC_MSG_CODE_SHIFT 0 +#define INTEL_GUC_MSG_CODE_MASK (0xFFFF << INTEL_GUC_MSG_CODE_SHIFT) + +#define __INTEL_GUC_MSG_GET(T, m) \ + (((m) & INTEL_GUC_MSG_ ## T ## _MASK) >> INTEL_GUC_MSG_ ## T ## _SHIFT) +#define INTEL_GUC_MSG_TO_TYPE(m) __INTEL_GUC_MSG_GET(TYPE, m) +#define INTEL_GUC_MSG_TO_DATA(m) __INTEL_GUC_MSG_GET(DATA, m) +#define INTEL_GUC_MSG_TO_CODE(m) __INTEL_GUC_MSG_GET(CODE, m) + +enum intel_guc_msg_type { + INTEL_GUC_MSG_TYPE_REQUEST = 0x0, + INTEL_GUC_MSG_TYPE_RESPONSE = 0xF, +}; + +#define __INTEL_GUC_MSG_TYPE_IS(T, m) \ + (INTEL_GUC_MSG_TO_TYPE(m) == INTEL_GUC_MSG_TYPE_ ## T) +#define INTEL_GUC_MSG_IS_REQUEST(m) __INTEL_GUC_MSG_TYPE_IS(REQUEST, m) +#define INTEL_GUC_MSG_IS_RESPONSE(m) __INTEL_GUC_MSG_TYPE_IS(RESPONSE, m) + enum intel_guc_action { INTEL_GUC_ACTION_DEFAULT = 0x0, INTEL_GUC_ACTION_REQUEST_PREEMPTION = 0x2, @@ -597,24 +658,17 @@ enum intel_guc_report_status { #define GUC_LOG_CONTROL_VERBOSITY_MASK (0xF << GUC_LOG_CONTROL_VERBOSITY_SHIFT) #define GUC_LOG_CONTROL_DEFAULT_LOGGING (1 << 8) -/* - * The GuC sends its response to a command by overwriting the - * command in SS0. The response is distinguishable from a command - * by the fact that all the MASK bits are set. The remaining bits - * give more detail. - */ -#define INTEL_GUC_RECV_MASK ((u32)0xF0000000) -#define INTEL_GUC_RECV_IS_RESPONSE(x) ((u32)(x) >= INTEL_GUC_RECV_MASK) -#define INTEL_GUC_RECV_STATUS(x) (INTEL_GUC_RECV_MASK | (x)) - -/* GUC will return status back to SOFT_SCRATCH_O_REG */ -enum intel_guc_status { - INTEL_GUC_STATUS_SUCCESS = INTEL_GUC_RECV_STATUS(0x0), - INTEL_GUC_STATUS_ALLOCATE_DOORBELL_FAIL = INTEL_GUC_RECV_STATUS(0x10), - INTEL_GUC_STATUS_DEALLOCATE_DOORBELL_FAIL = INTEL_GUC_RECV_STATUS(0x20), - INTEL_GUC_STATUS_GENERIC_FAIL = INTEL_GUC_RECV_STATUS(0x0000F000) +enum intel_guc_response_status { + INTEL_GUC_RESPONSE_STATUS_SUCCESS = 0x0, + INTEL_GUC_RESPONSE_STATUS_GENERIC_FAIL = 0xF000, }; +#define INTEL_GUC_MSG_IS_RESPONSE_SUCCESS(m) \ + (typecheck(u32, (m)) && \ + ((m) & (INTEL_GUC_MSG_TYPE_MASK | INTEL_GUC_MSG_CODE_MASK)) == \ + ((INTEL_GUC_MSG_TYPE_RESPONSE << INTEL_GUC_MSG_TYPE_SHIFT) | \ + (INTEL_GUC_RESPONSE_STATUS_SUCCESS << INTEL_GUC_MSG_CODE_SHIFT))) + /* This action will be programmed in C1BC - SOFT_SCRATCH_15_REG */ enum intel_guc_recv_message { INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED = BIT(1), -- cgit v1.2.3 From b839a869dfc9f01aab72c5dd26cb7a7f2e264201 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 26 Mar 2018 19:48:19 +0000 Subject: drm/i915/guc: Add support for data reporting in GuC responses GuC may return additional data in the response message. Format and meaning of this data is action specific. We will use this non-negative data as a new success return value. Currently used actions don't return data that way yet. v2: fix prohibited space after '~' (Michel) update commit message (Daniele) v3: rebase Signed-off-by: Michal Wajdeczko Cc: Oscar Mateo Cc: Michel Thierry Cc: Daniele Ceraolo Spurio Reviewed-by: Michel Thierry Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180326194829.58836-3-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 3 +++ drivers/gpu/drm/i915/intel_guc_ct.c | 14 ++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 78e68b169cf2..1af32a0648db 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -366,6 +366,9 @@ int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len) " ret=%d status=0x%08X response=0x%08X\n", action[0], ret, status, I915_READ(SOFT_SCRATCH(15))); + } else { + /* Use data from the GuC response as our return value */ + ret = INTEL_GUC_MSG_TO_DATA(status); } intel_uncore_forcewake_put(dev_priv, guc->send_regs.fw_domains); diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index 1dafa7a20d89..fa522594d716 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -400,7 +400,9 @@ static int ctch_send(struct intel_guc *guc, return err; if (!INTEL_GUC_MSG_IS_RESPONSE_SUCCESS(*status)) return -EIO; - return 0; + + /* Use data from the GuC status as our return value */ + return INTEL_GUC_MSG_TO_DATA(*status); } /* @@ -410,18 +412,18 @@ static int intel_guc_send_ct(struct intel_guc *guc, const u32 *action, u32 len) { struct intel_guc_ct_channel *ctch = &guc->ct.host_channel; u32 status = ~0; /* undefined */ - int err; + int ret; mutex_lock(&guc->send_mutex); - err = ctch_send(guc, ctch, action, len, &status); - if (unlikely(err)) { + ret = ctch_send(guc, ctch, action, len, &status); + if (unlikely(ret < 0)) { DRM_ERROR("CT: send action %#X failed; err=%d status=%#X\n", - action[0], err, status); + action[0], ret, status); } mutex_unlock(&guc->send_mutex); - return err; + return ret; } /** -- cgit v1.2.3 From e09af3a6a62dfe0a9c4bc931c81447a3969177fb Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 26 Mar 2018 19:48:20 +0000 Subject: drm/i915/guc: Prepare send() function to accept bigger response This is a preparation step for the upcoming patches. We already can return some small data decoded from the command status, but we will need more in the future. v2: add explicit response buf size v3: squash with helper patch Signed-off-by: Michal Wajdeczko Cc: Oscar Mateo Cc: Michel Thierry Cc: Daniele Ceraolo Spurio Reviewed-by: Michel Thierry Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180326194829.58836-4-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 6 ++++-- drivers/gpu/drm/i915/intel_guc.h | 18 ++++++++++++++---- drivers/gpu/drm/i915/intel_guc_ct.c | 7 ++++--- 3 files changed, 22 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 1af32a0648db..ba5a962ca3d4 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -310,7 +310,8 @@ void intel_guc_init_params(struct intel_guc *guc) intel_uncore_forcewake_put(dev_priv, FORCEWAKE_BLITTER); } -int intel_guc_send_nop(struct intel_guc *guc, const u32 *action, u32 len) +int intel_guc_send_nop(struct intel_guc *guc, const u32 *action, u32 len, + u32 *response_buf, u32 response_buf_size) { WARN(1, "Unexpected send: action=%#x\n", *action); return -ENODEV; @@ -319,7 +320,8 @@ int intel_guc_send_nop(struct intel_guc *guc, const u32 *action, u32 len) /* * This function implements the MMIO based host to GuC interface. */ -int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len) +int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len, + u32 *response_buf, u32 response_buf_size) { struct drm_i915_private *dev_priv = guc_to_i915(guc); u32 status; diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 13f3d1dbf38d..7ee0732d8b79 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -88,7 +88,8 @@ struct intel_guc { struct mutex send_mutex; /* GuC's FW specific send function */ - int (*send)(struct intel_guc *guc, const u32 *data, u32 len); + int (*send)(struct intel_guc *guc, const u32 *data, u32 len, + u32 *response_buf, u32 response_buf_size); /* GuC's FW specific notify function */ void (*notify)(struct intel_guc *guc); @@ -97,7 +98,14 @@ struct intel_guc { static inline int intel_guc_send(struct intel_guc *guc, const u32 *action, u32 len) { - return guc->send(guc, action, len); + return guc->send(guc, action, len, NULL, 0); +} + +static inline int +intel_guc_send_and_receive(struct intel_guc *guc, const u32 *action, u32 len, + u32 *response_buf, u32 response_buf_size) +{ + return guc->send(guc, action, len, response_buf, response_buf_size); } static inline void intel_guc_notify(struct intel_guc *guc) @@ -140,8 +148,10 @@ int intel_guc_init_wq(struct intel_guc *guc); void intel_guc_fini_wq(struct intel_guc *guc); int intel_guc_init(struct intel_guc *guc); void intel_guc_fini(struct intel_guc *guc); -int intel_guc_send_nop(struct intel_guc *guc, const u32 *action, u32 len); -int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len); +int intel_guc_send_nop(struct intel_guc *guc, const u32 *action, u32 len, + u32 *response_buf, u32 response_buf_size); +int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len, + u32 *response_buf, u32 response_buf_size); void intel_guc_to_host_event_handler(struct intel_guc *guc); int intel_guc_sample_forcewake(struct intel_guc *guc); int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset); diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index fa522594d716..a54bf58c64ab 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -88,7 +88,7 @@ static int guc_action_register_ct_buffer(struct intel_guc *guc, int err; /* Can't use generic send(), CT registration must go over MMIO */ - err = intel_guc_send_mmio(guc, action, ARRAY_SIZE(action)); + err = intel_guc_send_mmio(guc, action, ARRAY_SIZE(action), NULL, 0); if (err) DRM_ERROR("CT: register %s buffer failed; err=%d\n", guc_ct_buffer_type_to_str(type), err); @@ -107,7 +107,7 @@ static int guc_action_deregister_ct_buffer(struct intel_guc *guc, int err; /* Can't use generic send(), CT deregistration must go over MMIO */ - err = intel_guc_send_mmio(guc, action, ARRAY_SIZE(action)); + err = intel_guc_send_mmio(guc, action, ARRAY_SIZE(action), NULL, 0); if (err) DRM_ERROR("CT: deregister %s buffer failed; owner=%d err=%d\n", guc_ct_buffer_type_to_str(type), owner, err); @@ -408,7 +408,8 @@ static int ctch_send(struct intel_guc *guc, /* * Command Transport (CT) buffer based GuC send function. */ -static int intel_guc_send_ct(struct intel_guc *guc, const u32 *action, u32 len) +static int intel_guc_send_ct(struct intel_guc *guc, const u32 *action, u32 len, + u32 *response_buf, u32 response_buf_size) { struct intel_guc_ct_channel *ctch = &guc->ct.host_channel; u32 status = ~0; /* undefined */ -- cgit v1.2.3 From f6a70b59705109edb935674d36a5065fe2a5b4ad Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 26 Mar 2018 19:48:21 +0000 Subject: drm/i915/guc: Implement response handling in send_mmio() We're using data encoded in the status MMIO as return value from send function, but GuC may also write more data in remaining MMIO regs. Let's copy content of these registers to the buffer provided by caller. v2: new line (Michel) v3: updated commit message Signed-off-by: Michal Wajdeczko Cc: Daniele Ceraolo Spurio Cc: Oscar Mateo Reviewed-by: Michel Thierry Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180326194829.58836-5-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index ba5a962ca3d4..b83a5ad9cb79 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -368,11 +368,20 @@ int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len, " ret=%d status=0x%08X response=0x%08X\n", action[0], ret, status, I915_READ(SOFT_SCRATCH(15))); - } else { - /* Use data from the GuC response as our return value */ - ret = INTEL_GUC_MSG_TO_DATA(status); + goto out; } + if (response_buf) { + int count = min(response_buf_size, guc->send_regs.count - 1); + + for (i = 0; i < count; i++) + response_buf[i] = I915_READ(guc_send_reg(guc, i + 1)); + } + + /* Use data from the GuC response as our return value */ + ret = INTEL_GUC_MSG_TO_DATA(status); + +out: intel_uncore_forcewake_put(dev_priv, guc->send_regs.fw_domains); mutex_unlock(&guc->send_mutex); -- cgit v1.2.3 From 769bfbf943235c8c54e189a0d12bf8d3195af0c5 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 26 Mar 2018 19:48:22 +0000 Subject: drm/i915/guc: Make event handler a virtual function On platforms with CTB based GuC communications, we will handle GuC events in a different way. Let's make event handler a virtual function to allow easy switch between those variants. Credits-to: Oscar Mateo Signed-off-by: Michal Wajdeczko Cc: Daniele Ceraolo Spurio Cc: Oscar Mateo Reviewed-by: Michel Thierry Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180326194829.58836-6-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 8 +++++++- drivers/gpu/drm/i915/intel_guc.h | 10 ++++++++++ drivers/gpu/drm/i915/intel_uc.c | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index b83a5ad9cb79..411c8e910583 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -69,6 +69,7 @@ void intel_guc_init_early(struct intel_guc *guc) mutex_init(&guc->send_mutex); spin_lock_init(&guc->irq_lock); guc->send = intel_guc_send_nop; + guc->handler = intel_guc_to_host_event_handler_nop; guc->notify = gen8_guc_raise_irq; } @@ -317,6 +318,11 @@ int intel_guc_send_nop(struct intel_guc *guc, const u32 *action, u32 len, return -ENODEV; } +void intel_guc_to_host_event_handler_nop(struct intel_guc *guc) +{ + WARN(1, "Unexpected event: no suitable handler\n"); +} + /* * This function implements the MMIO based host to GuC interface. */ @@ -388,7 +394,7 @@ out: return ret; } -void intel_guc_to_host_event_handler(struct intel_guc *guc) +void intel_guc_to_host_event_handler_mmio(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); u32 msg, val; diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 7ee0732d8b79..6dc109ab61bc 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -91,6 +91,9 @@ struct intel_guc { int (*send)(struct intel_guc *guc, const u32 *data, u32 len, u32 *response_buf, u32 response_buf_size); + /* GuC's FW specific event handler function */ + void (*handler)(struct intel_guc *guc); + /* GuC's FW specific notify function */ void (*notify)(struct intel_guc *guc); }; @@ -113,6 +116,11 @@ static inline void intel_guc_notify(struct intel_guc *guc) guc->notify(guc); } +static inline void intel_guc_to_host_event_handler(struct intel_guc *guc) +{ + guc->handler(guc); +} + /* GuC addresses above GUC_GGTT_TOP also don't map through the GTT */ #define GUC_GGTT_TOP 0xFEE00000 @@ -153,6 +161,8 @@ int intel_guc_send_nop(struct intel_guc *guc, const u32 *action, u32 len, int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len, u32 *response_buf, u32 response_buf_size); void intel_guc_to_host_event_handler(struct intel_guc *guc); +void intel_guc_to_host_event_handler_nop(struct intel_guc *guc); +void intel_guc_to_host_event_handler_mmio(struct intel_guc *guc); int intel_guc_sample_forcewake(struct intel_guc *guc); int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset); int intel_guc_suspend(struct intel_guc *guc); diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 4aad8442e789..081e42462aad 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -233,6 +233,7 @@ static int guc_enable_communication(struct intel_guc *guc) return intel_guc_ct_enable(&guc->ct); guc->send = intel_guc_send_mmio; + guc->handler = intel_guc_to_host_event_handler_mmio; return 0; } @@ -246,6 +247,7 @@ static void guc_disable_communication(struct intel_guc *guc) gen9_disable_guc_interrupts(dev_priv); guc->send = intel_guc_send_nop; + guc->handler = intel_guc_to_host_event_handler_nop; } int intel_uc_init_misc(struct drm_i915_private *dev_priv) -- cgit v1.2.3 From 1d407096002becab2fd5b19253cee0de65aab668 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 26 Mar 2018 19:48:23 +0000 Subject: drm/i915/guc: Prepare to handle messages from CT RECV buffer GuC can respond to our commands not only by updating SEND buffer descriptor, but can also send a response message over RECV buffer. Guc can also send unsolicited request messages over RECV buffer. Let's start reading those messages and make placeholders for actual response/request handlers. v2: misc improvements (Michal) v3: change response detection (Michal) invalid status is protocol error (Michal) v4: rebase v5: fix checkpatch (Michel) don't use fields before check (Jani) add some documentation (Michal) Signed-off-by: Michal Wajdeczko Cc: Oscar Mateo Cc: Michel Thierry Cc: Daniele Ceraolo Spurio Reviewed-by: Michel Thierry # 4.5 Cc: Jani Nikula Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180326194829.58836-7-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc_ct.c | 184 +++++++++++++++++++++++++++++++++++- 1 file changed, 183 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index a54bf58c64ab..14f55de342e7 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -273,6 +273,24 @@ static u32 ctch_get_next_fence(struct intel_guc_ct_channel *ctch) return ++ctch->next_fence; } +/** + * DOC: CTB Host to GuC request + * + * Format of the CTB Host to GuC request message is as follows:: + * + * +------------+---------+---------+---------+---------+ + * | msg[0] | [1] | [2] | ... | [n-1] | + * +------------+---------+---------+---------+---------+ + * | MESSAGE | MESSAGE PAYLOAD | + * + HEADER +---------+---------+---------+---------+ + * | | 0 | 1 | ... | n | + * +============+=========+=========+=========+=========+ + * | len >= 1 | FENCE | request specific data | + * +------+-----+---------+---------+---------+---------+ + * + * ^-----------------len-------------------^ + */ + static int ctb_write(struct intel_guc_ct_buffer *ctb, const u32 *action, u32 len /* in dwords */, @@ -305,7 +323,8 @@ static int ctb_write(struct intel_guc_ct_buffer *ctb, if (unlikely(used + len + 1 >= size)) return -ENOSPC; - /* Write the message. The format is the following: + /* + * Write the message. The format is the following: * DW0: header (including action code) * DW1: fence * DW2+: action data @@ -427,6 +446,167 @@ static int intel_guc_send_ct(struct intel_guc *guc, const u32 *action, u32 len, return ret; } +static inline unsigned int ct_header_get_len(u32 header) +{ + return (header >> GUC_CT_MSG_LEN_SHIFT) & GUC_CT_MSG_LEN_MASK; +} + +static inline unsigned int ct_header_get_action(u32 header) +{ + return (header >> GUC_CT_MSG_ACTION_SHIFT) & GUC_CT_MSG_ACTION_MASK; +} + +static inline bool ct_header_is_response(u32 header) +{ + return ct_header_get_action(header) == INTEL_GUC_ACTION_DEFAULT; +} + +static int ctb_read(struct intel_guc_ct_buffer *ctb, u32 *data) +{ + struct guc_ct_buffer_desc *desc = ctb->desc; + u32 head = desc->head / 4; /* in dwords */ + u32 tail = desc->tail / 4; /* in dwords */ + u32 size = desc->size / 4; /* in dwords */ + u32 *cmds = ctb->cmds; + s32 available; /* in dwords */ + unsigned int len; + unsigned int i; + + GEM_BUG_ON(desc->size % 4); + GEM_BUG_ON(desc->head % 4); + GEM_BUG_ON(desc->tail % 4); + GEM_BUG_ON(tail >= size); + GEM_BUG_ON(head >= size); + + /* tail == head condition indicates empty */ + available = tail - head; + if (unlikely(available == 0)) + return -ENODATA; + + /* beware of buffer wrap case */ + if (unlikely(available < 0)) + available += size; + GEM_BUG_ON(available < 0); + + data[0] = cmds[head]; + head = (head + 1) % size; + + /* message len with header */ + len = ct_header_get_len(data[0]) + 1; + if (unlikely(len > (u32)available)) { + DRM_ERROR("CT: incomplete message %*phn %*phn %*phn\n", + 4, data, + 4 * (head + available - 1 > size ? + size - head : available - 1), &cmds[head], + 4 * (head + available - 1 > size ? + available - 1 - size + head : 0), &cmds[0]); + return -EPROTO; + } + + for (i = 1; i < len; i++) { + data[i] = cmds[head]; + head = (head + 1) % size; + } + + desc->head = head * 4; + return 0; +} + +/** + * DOC: CTB GuC to Host response + * + * Format of the CTB GuC to Host response message is as follows:: + * + * +------------+---------+---------+---------+---------+---------+ + * | msg[0] | [1] | [2] | [3] | ... | [n-1] | + * +------------+---------+---------+---------+---------+---------+ + * | MESSAGE | MESSAGE PAYLOAD | + * + HEADER +---------+---------+---------+---------+---------+ + * | | 0 | 1 | 2 | ... | n | + * +============+=========+=========+=========+=========+=========+ + * | len >= 2 | FENCE | STATUS | response specific data | + * +------+-----+---------+---------+---------+---------+---------+ + * + * ^-----------------------len-----------------------^ + */ + +static int ct_handle_response(struct intel_guc_ct *ct, const u32 *msg) +{ + u32 header = msg[0]; + u32 len = ct_header_get_len(header); + u32 msglen = len + 1; /* total message length including header */ + u32 fence; + u32 status; + + GEM_BUG_ON(!ct_header_is_response(header)); + + /* Response payload shall at least include fence and status */ + if (unlikely(len < 2)) { + DRM_ERROR("CT: corrupted response %*phn\n", 4 * msglen, msg); + return -EPROTO; + } + + fence = msg[1]; + status = msg[2]; + + /* Format of the status follows RESPONSE message */ + if (unlikely(!INTEL_GUC_MSG_IS_RESPONSE(status))) { + DRM_ERROR("CT: corrupted response %*phn\n", 4 * msglen, msg); + return -EPROTO; + } + + /* XXX */ + return 0; +} + +static int ct_handle_request(struct intel_guc_ct *ct, const u32 *msg) +{ + u32 header = msg[0]; + + GEM_BUG_ON(ct_header_is_response(header)); + + /* XXX */ + return 0; +} + +static void ct_process_host_channel(struct intel_guc_ct *ct) +{ + struct intel_guc_ct_channel *ctch = &ct->host_channel; + struct intel_guc_ct_buffer *ctb = &ctch->ctbs[CTB_RECV]; + u32 msg[GUC_CT_MSG_LEN_MASK + 1]; /* one extra dw for the header */ + int err = 0; + + if (!ctch_is_open(ctch)) + return; + + do { + err = ctb_read(ctb, msg); + if (err) + break; + + if (ct_header_is_response(msg[0])) + err = ct_handle_response(ct, msg); + else + err = ct_handle_request(ct, msg); + } while (!err); + + if (GEM_WARN_ON(err == -EPROTO)) { + DRM_ERROR("CT: corrupted message detected!\n"); + ctb->desc->is_in_error = 1; + } +} + +/* + * When we're communicating with the GuC over CT, GuC uses events + * to notify us about new messages being posted on the RECV buffer. + */ +static void intel_guc_to_host_event_handler_ct(struct intel_guc *guc) +{ + struct intel_guc_ct *ct = &guc->ct; + + ct_process_host_channel(ct); +} + /** * intel_guc_ct_enable - Enable buffer based command transport. * @ct: pointer to CT struct @@ -450,6 +630,7 @@ int intel_guc_ct_enable(struct intel_guc_ct *ct) /* Switch into cmd transport buffer based send() */ guc->send = intel_guc_send_ct; + guc->handler = intel_guc_to_host_event_handler_ct; DRM_INFO("CT: %s\n", enableddisabled(true)); return 0; } @@ -475,5 +656,6 @@ void intel_guc_ct_disable(struct intel_guc_ct *ct) /* Disable send */ guc->send = intel_guc_send_nop; + guc->handler = intel_guc_to_host_event_handler_nop; DRM_INFO("CT: %s\n", enableddisabled(false)); } -- cgit v1.2.3 From 24827cd0dd86a3158abc90ee64dcaf18aa843970 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 26 Mar 2018 19:48:24 +0000 Subject: drm/i915/guc: Use better name for helper wait function In next patch we will introduce another way of waiting for the response that will use RECV buffer. To avoid misleading names, rename old wait function to reflect the fact that it is based on descriptor update. v2: fix comment style (Michal) v3: use more specific name (Michel) Signed-off-by: Michal Wajdeczko Reviewed-by: Michel Thierry Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180326194829.58836-8-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc_ct.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index 14f55de342e7..2d805a2fd1f0 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -351,16 +351,25 @@ static int ctb_write(struct intel_guc_ct_buffer *ctb, return 0; } -/* Wait for the response from the GuC. +/** + * wait_for_ctb_desc_update - Wait for the CT buffer descriptor update. + * @desc: buffer descriptor * @fence: response fence * @status: placeholder for status - * return: 0 response received (status is valid) - * -ETIMEDOUT no response within hardcoded timeout - * -EPROTO no response, ct buffer was in error + * + * Guc will update CT buffer descriptor with new fence and status + * after processing the command identified by the fence. Wait for + * specified fence and then read from the descriptor status of the + * command. + * + * Return: + * * 0 response received (status is valid) + * * -ETIMEDOUT no response within hardcoded timeout + * * -EPROTO no response, CT buffer is in error */ -static int wait_for_response(struct guc_ct_buffer_desc *desc, - u32 fence, - u32 *status) +static int wait_for_ctb_desc_update(struct guc_ct_buffer_desc *desc, + u32 fence, + u32 *status) { int err; @@ -414,7 +423,7 @@ static int ctch_send(struct intel_guc *guc, intel_guc_notify(guc); - err = wait_for_response(desc, fence, status); + err = wait_for_ctb_desc_update(desc, fence, status); if (unlikely(err)) return err; if (!INTEL_GUC_MSG_IS_RESPONSE_SUCCESS(*status)) -- cgit v1.2.3 From 9ef4c75e06006eb041c0bcc578548e3cdb8f9e03 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Tue, 27 Mar 2018 12:14:39 +0000 Subject: drm/i915/guc: Implement response handling in send_ct() Instead of returning small data in response status dword, GuC may append longer data as response message payload. If caller provides response buffer, we will copy received data and use number of received data dwords as new success return value. We will WARN if response from GuC does not match caller expectation. v2: fix timeout and checkpatch warnings (Michal) v3: fix checkpatch again (Michel) update wait function name (Michal) no need for spinlock_irqsave (MichalWi) no magic numbers (MichalWi) must check before use (Jani) add some more documentation (Michal) v4: update documentation (Michal) Signed-off-by: Michal Wajdeczko Cc: Oscar Mateo Cc: Michel Thierry Cc: Daniele Ceraolo Spurio Reviewed-by: Michel Thierry #2.5 Cc: Michal Winiarski Cc: Jani Nikula Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180327121439.70096-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc_ct.c | 142 ++++++++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_guc_ct.h | 6 ++ drivers/gpu/drm/i915/intel_guc_fwif.h | 52 +++++++++++++ 3 files changed, 186 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index 2d805a2fd1f0..41b071c6d757 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -24,6 +24,14 @@ #include "i915_drv.h" #include "intel_guc_ct.h" +struct ct_request { + struct list_head link; + u32 fence; + u32 status; + u32 response_len; + u32 *response_buf; +}; + enum { CTB_SEND = 0, CTB_RECV = 1 }; enum { CTB_OWNER_HOST = 0 }; @@ -36,6 +44,9 @@ void intel_guc_ct_init_early(struct intel_guc_ct *ct) { /* we're using static channel owners */ ct->host_channel.owner = CTB_OWNER_HOST; + + spin_lock_init(&ct->lock); + INIT_LIST_HEAD(&ct->pending_requests); } static inline struct intel_guc *ct_to_guc(struct intel_guc_ct *ct) @@ -294,7 +305,8 @@ static u32 ctch_get_next_fence(struct intel_guc_ct_channel *ctch) static int ctb_write(struct intel_guc_ct_buffer *ctb, const u32 *action, u32 len /* in dwords */, - u32 fence) + u32 fence, + bool want_response) { struct guc_ct_buffer_desc *desc = ctb->desc; u32 head = desc->head / 4; /* in dwords */ @@ -331,6 +343,7 @@ static int ctb_write(struct intel_guc_ct_buffer *ctb, */ header = (len << GUC_CT_MSG_LEN_SHIFT) | (GUC_CT_MSG_WRITE_FENCE_TO_DESC) | + (want_response ? GUC_CT_MSG_SEND_STATUS : 0) | (action[0] << GUC_CT_MSG_ACTION_SHIFT); cmds[tail] = header; @@ -401,36 +414,108 @@ static int wait_for_ctb_desc_update(struct guc_ct_buffer_desc *desc, return err; } -static int ctch_send(struct intel_guc *guc, +/** + * wait_for_ct_request_update - Wait for CT request state update. + * @req: pointer to pending request + * @status: placeholder for status + * + * For each sent request, Guc shall send bac CT response message. + * Our message handler will update status of tracked request once + * response message with given fence is received. Wait here and + * check for valid response status value. + * + * Return: + * * 0 response received (status is valid) + * * -ETIMEDOUT no response within hardcoded timeout + */ +static int wait_for_ct_request_update(struct ct_request *req, u32 *status) +{ + int err; + + /* + * Fast commands should complete in less than 10us, so sample quickly + * up to that length of time, then switch to a slower sleep-wait loop. + * No GuC command should ever take longer than 10ms. + */ +#define done INTEL_GUC_MSG_IS_RESPONSE(READ_ONCE(req->status)) + err = wait_for_us(done, 10); + if (err) + err = wait_for(done, 10); +#undef done + + if (unlikely(err)) + DRM_ERROR("CT: fence %u err %d\n", req->fence, err); + + *status = req->status; + return err; +} + +static int ctch_send(struct intel_guc_ct *ct, struct intel_guc_ct_channel *ctch, const u32 *action, u32 len, + u32 *response_buf, + u32 response_buf_size, u32 *status) { struct intel_guc_ct_buffer *ctb = &ctch->ctbs[CTB_SEND]; struct guc_ct_buffer_desc *desc = ctb->desc; + struct ct_request request; + unsigned long flags; u32 fence; int err; GEM_BUG_ON(!ctch_is_open(ctch)); GEM_BUG_ON(!len); GEM_BUG_ON(len & ~GUC_CT_MSG_LEN_MASK); + GEM_BUG_ON(!response_buf && response_buf_size); fence = ctch_get_next_fence(ctch); - err = ctb_write(ctb, action, len, fence); + request.fence = fence; + request.status = 0; + request.response_len = response_buf_size; + request.response_buf = response_buf; + + spin_lock_irqsave(&ct->lock, flags); + list_add_tail(&request.link, &ct->pending_requests); + spin_unlock_irqrestore(&ct->lock, flags); + + err = ctb_write(ctb, action, len, fence, !!response_buf); if (unlikely(err)) - return err; + goto unlink; - intel_guc_notify(guc); + intel_guc_notify(ct_to_guc(ct)); - err = wait_for_ctb_desc_update(desc, fence, status); + if (response_buf) + err = wait_for_ct_request_update(&request, status); + else + err = wait_for_ctb_desc_update(desc, fence, status); if (unlikely(err)) - return err; - if (!INTEL_GUC_MSG_IS_RESPONSE_SUCCESS(*status)) - return -EIO; + goto unlink; + + if (!INTEL_GUC_MSG_IS_RESPONSE_SUCCESS(*status)) { + err = -EIO; + goto unlink; + } + + if (response_buf) { + /* There shall be no data in the status */ + WARN_ON(INTEL_GUC_MSG_TO_DATA(request.status)); + /* Return actual response len */ + err = request.response_len; + } else { + /* There shall be no response payload */ + WARN_ON(request.response_len); + /* Return data decoded from the status dword */ + err = INTEL_GUC_MSG_TO_DATA(*status); + } - /* Use data from the GuC status as our return value */ - return INTEL_GUC_MSG_TO_DATA(*status); +unlink: + spin_lock_irqsave(&ct->lock, flags); + list_del(&request.link); + spin_unlock_irqrestore(&ct->lock, flags); + + return err; } /* @@ -439,13 +524,15 @@ static int ctch_send(struct intel_guc *guc, static int intel_guc_send_ct(struct intel_guc *guc, const u32 *action, u32 len, u32 *response_buf, u32 response_buf_size) { - struct intel_guc_ct_channel *ctch = &guc->ct.host_channel; + struct intel_guc_ct *ct = &guc->ct; + struct intel_guc_ct_channel *ctch = &ct->host_channel; u32 status = ~0; /* undefined */ int ret; mutex_lock(&guc->send_mutex); - ret = ctch_send(guc, ctch, action, len, &status); + ret = ctch_send(ct, ctch, action, len, response_buf, response_buf_size, + &status); if (unlikely(ret < 0)) { DRM_ERROR("CT: send action %#X failed; err=%d status=%#X\n", action[0], ret, status); @@ -546,8 +633,12 @@ static int ct_handle_response(struct intel_guc_ct *ct, const u32 *msg) u32 msglen = len + 1; /* total message length including header */ u32 fence; u32 status; + u32 datalen; + struct ct_request *req; + bool found = false; GEM_BUG_ON(!ct_header_is_response(header)); + GEM_BUG_ON(!in_irq()); /* Response payload shall at least include fence and status */ if (unlikely(len < 2)) { @@ -557,6 +648,7 @@ static int ct_handle_response(struct intel_guc_ct *ct, const u32 *msg) fence = msg[1]; status = msg[2]; + datalen = len - 2; /* Format of the status follows RESPONSE message */ if (unlikely(!INTEL_GUC_MSG_IS_RESPONSE(status))) { @@ -564,7 +656,29 @@ static int ct_handle_response(struct intel_guc_ct *ct, const u32 *msg) return -EPROTO; } - /* XXX */ + spin_lock(&ct->lock); + list_for_each_entry(req, &ct->pending_requests, link) { + if (unlikely(fence != req->fence)) { + DRM_DEBUG_DRIVER("CT: request %u awaits response\n", + req->fence); + continue; + } + if (unlikely(datalen > req->response_len)) { + DRM_ERROR("CT: response %u too long %*phn\n", + req->fence, 4 * msglen, msg); + datalen = 0; + } + if (datalen) + memcpy(req->response_buf, msg + 3, 4 * datalen); + req->response_len = datalen; + WRITE_ONCE(req->status, status); + found = true; + break; + } + spin_unlock(&ct->lock); + + if (!found) + DRM_ERROR("CT: unsolicited response %*phn\n", 4 * msglen, msg); return 0; } diff --git a/drivers/gpu/drm/i915/intel_guc_ct.h b/drivers/gpu/drm/i915/intel_guc_ct.h index 595c8ad5bd4a..fac6e53194c6 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.h +++ b/drivers/gpu/drm/i915/intel_guc_ct.h @@ -75,6 +75,12 @@ struct intel_guc_ct_channel { struct intel_guc_ct { struct intel_guc_ct_channel host_channel; /* other channels are tbd */ + + /** @lock: protects pending requests list */ + spinlock_t lock; + + /** @pending_requests: list of requests waiting for response */ + struct list_head pending_requests; }; void intel_guc_ct_init_early(struct intel_guc_ct *ct); diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h index 83143e8a0730..d73673f5d30c 100644 --- a/drivers/gpu/drm/i915/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -327,6 +327,58 @@ struct guc_stage_desc { u64 desc_private; } __packed; +/** + * DOC: CTB based communication + * + * The CTB (command transport buffer) communication between Host and GuC + * is based on u32 data stream written to the shared buffer. One buffer can + * be used to transmit data only in one direction (one-directional channel). + * + * Current status of the each buffer is stored in the buffer descriptor. + * Buffer descriptor holds tail and head fields that represents active data + * stream. The tail field is updated by the data producer (sender), and head + * field is updated by the data consumer (receiver):: + * + * +------------+ + * | DESCRIPTOR | +=================+============+========+ + * +============+ | | MESSAGE(s) | | + * | address |--------->+=================+============+========+ + * +------------+ + * | head | ^-----head--------^ + * +------------+ + * | tail | ^---------tail-----------------^ + * +------------+ + * | size | ^---------------size--------------------^ + * +------------+ + * + * Each message in data stream starts with the single u32 treated as a header, + * followed by optional set of u32 data that makes message specific payload:: + * + * +------------+---------+---------+---------+ + * | MESSAGE | + * +------------+---------+---------+---------+ + * | msg[0] | [1] | ... | [n-1] | + * +------------+---------+---------+---------+ + * | MESSAGE | MESSAGE PAYLOAD | + * + HEADER +---------+---------+---------+ + * | | 0 | ... | n | + * +======+=====+=========+=========+=========+ + * | 31:16| code| | | | + * +------+-----+ | | | + * | 15:5|flags| | | | + * +------+-----+ | | | + * | 4:0| len| | | | + * +------+-----+---------+---------+---------+ + * + * ^-------------len-------------^ + * + * The message header consists of: + * + * - **len**, indicates length of the message payload (in u32) + * - **code**, indicates message code + * - **flags**, holds various bits to control message handling + */ + /* * Describes single command transport buffer. * Used by both guc-master and clients. -- cgit v1.2.3 From 6c77a2b05841a4082f746bf58345209df57175c9 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 26 Mar 2018 19:48:26 +0000 Subject: drm/i915/guc: Prepare to process incoming requests from CT Requests are read from CT in the irq handler, but actual processing will be done in the work thread. Processing of specific actions will be added in the upcoming patches. v2: don't use GEM_BUG_ON (Chris) don't kmalloc too large buffer (Michal) v3: rebased v4: don't name it 'dispatch' (Michel) and fix checkpatch add some documentation (Michal) Signed-off-by: Michal Wajdeczko Cc: Oscar Mateo Cc: Michel Thierry Cc: Daniele Ceraolo Spurio Reviewed-by: Michel Thierry Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180326194829.58836-10-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc_ct.c | 95 ++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_guc_ct.h | 6 +++ 2 files changed, 100 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index 41b071c6d757..aa810aded442 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -32,10 +32,17 @@ struct ct_request { u32 *response_buf; }; +struct ct_incoming_request { + struct list_head link; + u32 msg[]; +}; + enum { CTB_SEND = 0, CTB_RECV = 1 }; enum { CTB_OWNER_HOST = 0 }; +static void ct_incoming_request_worker_func(struct work_struct *w); + /** * intel_guc_ct_init_early - Initialize CT state without requiring device access * @ct: pointer to CT struct @@ -47,6 +54,8 @@ void intel_guc_ct_init_early(struct intel_guc_ct *ct) spin_lock_init(&ct->lock); INIT_LIST_HEAD(&ct->pending_requests); + INIT_LIST_HEAD(&ct->incoming_requests); + INIT_WORK(&ct->worker, ct_incoming_request_worker_func); } static inline struct intel_guc *ct_to_guc(struct intel_guc_ct *ct) @@ -682,13 +691,97 @@ static int ct_handle_response(struct intel_guc_ct *ct, const u32 *msg) return 0; } +static void ct_process_request(struct intel_guc_ct *ct, + u32 action, u32 len, const u32 *payload) +{ + switch (action) { + default: + DRM_ERROR("CT: unexpected request %x %*phn\n", + action, 4 * len, payload); + break; + } +} + +static bool ct_process_incoming_requests(struct intel_guc_ct *ct) +{ + unsigned long flags; + struct ct_incoming_request *request; + u32 header; + u32 *payload; + bool done; + + spin_lock_irqsave(&ct->lock, flags); + request = list_first_entry_or_null(&ct->incoming_requests, + struct ct_incoming_request, link); + if (request) + list_del(&request->link); + done = !!list_empty(&ct->incoming_requests); + spin_unlock_irqrestore(&ct->lock, flags); + + if (!request) + return true; + + header = request->msg[0]; + payload = &request->msg[1]; + ct_process_request(ct, + ct_header_get_action(header), + ct_header_get_len(header), + payload); + + kfree(request); + return done; +} + +static void ct_incoming_request_worker_func(struct work_struct *w) +{ + struct intel_guc_ct *ct = container_of(w, struct intel_guc_ct, worker); + bool done; + + done = ct_process_incoming_requests(ct); + if (!done) + queue_work(system_unbound_wq, &ct->worker); +} + +/** + * DOC: CTB GuC to Host request + * + * Format of the CTB GuC to Host request message is as follows:: + * + * +------------+---------+---------+---------+---------+---------+ + * | msg[0] | [1] | [2] | [3] | ... | [n-1] | + * +------------+---------+---------+---------+---------+---------+ + * | MESSAGE | MESSAGE PAYLOAD | + * + HEADER +---------+---------+---------+---------+---------+ + * | | 0 | 1 | 2 | ... | n | + * +============+=========+=========+=========+=========+=========+ + * | len | request specific data | + * +------+-----+---------+---------+---------+---------+---------+ + * + * ^-----------------------len-----------------------^ + */ + static int ct_handle_request(struct intel_guc_ct *ct, const u32 *msg) { u32 header = msg[0]; + u32 len = ct_header_get_len(header); + u32 msglen = len + 1; /* total message length including header */ + struct ct_incoming_request *request; + unsigned long flags; GEM_BUG_ON(ct_header_is_response(header)); - /* XXX */ + request = kmalloc(sizeof(*request) + 4 * msglen, GFP_ATOMIC); + if (unlikely(!request)) { + DRM_ERROR("CT: dropping request %*phn\n", 4 * msglen, msg); + return 0; /* XXX: -ENOMEM ? */ + } + memcpy(request->msg, msg, 4 * msglen); + + spin_lock_irqsave(&ct->lock, flags); + list_add_tail(&request->link, &ct->incoming_requests); + spin_unlock_irqrestore(&ct->lock, flags); + + queue_work(system_unbound_wq, &ct->worker); return 0; } diff --git a/drivers/gpu/drm/i915/intel_guc_ct.h b/drivers/gpu/drm/i915/intel_guc_ct.h index fac6e53194c6..d774895ab143 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.h +++ b/drivers/gpu/drm/i915/intel_guc_ct.h @@ -81,6 +81,12 @@ struct intel_guc_ct { /** @pending_requests: list of requests waiting for response */ struct list_head pending_requests; + + /** @incoming_requests: list of incoming requests */ + struct list_head incoming_requests; + + /** @worker: worker for handling incoming requests */ + struct work_struct worker; }; void intel_guc_ct_init_early(struct intel_guc_ct *ct); -- cgit v1.2.3 From b6b0166d49f04ace13885a7ef42cb4a63ecf1f02 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Tue, 27 Mar 2018 21:41:24 +0000 Subject: drm/i915/guc: Handle default action received over CT When running on platform with CTB based GuC communication enabled, GuC to Host event data will be delivered as CT request message. However, content of the data[1] of this CT message follows format of the scratch register used in MMIO based communication, so some code reuse is still possible. v2: filter disabled messages (Daniele) Signed-off-by: Michal Wajdeczko Cc: Oscar Mateo Reviewed-by: Michel Thierry #1 Cc: Daniele Ceraolo Spurio Acked-by: Daniele Ceraolo Spurio Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180327214124.70680-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 8 ++++++++ drivers/gpu/drm/i915/intel_guc.h | 1 + drivers/gpu/drm/i915/intel_guc_ct.c | 9 +++++++++ 3 files changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 411c8e910583..a00a59a7d9ec 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -416,6 +416,14 @@ void intel_guc_to_host_event_handler_mmio(struct intel_guc *guc) I915_WRITE(SOFT_SCRATCH(15), val & ~msg); spin_unlock(&guc->irq_lock); + intel_guc_to_host_process_recv_msg(guc, msg); +} + +void intel_guc_to_host_process_recv_msg(struct intel_guc *guc, u32 msg) +{ + /* Make sure to handle only enabled messages */ + msg &= guc->msg_enabled_mask; + if (msg & (INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER | INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED)) intel_guc_log_handle_flush_event(&guc->log); diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 6dc109ab61bc..f1265e122d30 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -163,6 +163,7 @@ int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len, void intel_guc_to_host_event_handler(struct intel_guc *guc); void intel_guc_to_host_event_handler_nop(struct intel_guc *guc); void intel_guc_to_host_event_handler_mmio(struct intel_guc *guc); +void intel_guc_to_host_process_recv_msg(struct intel_guc *guc, u32 msg); int intel_guc_sample_forcewake(struct intel_guc *guc); int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset); int intel_guc_suspend(struct intel_guc *guc); diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index aa810aded442..e8370846c2c9 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -694,8 +694,17 @@ static int ct_handle_response(struct intel_guc_ct *ct, const u32 *msg) static void ct_process_request(struct intel_guc_ct *ct, u32 action, u32 len, const u32 *payload) { + struct intel_guc *guc = ct_to_guc(ct); + switch (action) { + case INTEL_GUC_ACTION_DEFAULT: + if (unlikely(len < 1)) + goto fail_unexpected; + intel_guc_to_host_process_recv_msg(guc, *payload); + break; + default: +fail_unexpected: DRM_ERROR("CT: unexpected request %x %*phn\n", action, 4 * len, payload); break; -- cgit v1.2.3 From 0a015ff9730c169aa0d581e3f7727752ba3ff5b3 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Mon, 26 Mar 2018 19:48:28 +0000 Subject: drm/i915/guc: Trace messages from CT while in debug During debug we may want to investigate all communication from the Guc. Add proper tracing macros in debug config. v2: convert remaining DRM_DEBUG into new CT_DEBUG (Michal) v3: use dedicated Kconfig (Daniele) v4: checkpatch Signed-off-by: Michal Wajdeczko Cc: Daniele Ceraolo Spurio Cc: Chris Wilson Acked-by: Daniele Ceraolo Spurio Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180326194829.58836-12-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/Kconfig.debug | 12 +++++++++++ drivers/gpu/drm/i915/intel_guc_ct.c | 43 ++++++++++++++++++++++++++----------- 2 files changed, 43 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug index dd5bf6389ead..80efee1ff7f3 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -90,6 +90,18 @@ config DRM_I915_SW_FENCE_CHECK_DAG If in doubt, say "N". +config DRM_I915_DEBUG_GUC + bool "Enable additional driver debugging for GuC" + depends on DRM_I915 + default n + help + Choose this option to turn on extra driver debugging that may affect + performance but will help resolve GuC related issues. + + Recommended for driver developers only. + + If in doubt, say "N". + config DRM_I915_SELFTEST bool "Enable selftests upon driver load" depends on DRM_I915 diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index e8370846c2c9..990141d5f195 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -24,6 +24,12 @@ #include "i915_drv.h" #include "intel_guc_ct.h" +#ifdef CONFIG_DRM_I915_DEBUG_GUC +#define CT_DEBUG_DRIVER(...) DRM_DEBUG_DRIVER(__VA_ARGS__) +#else +#define CT_DEBUG_DRIVER(...) do { } while (0) +#endif + struct ct_request { struct list_head link; u32 fence; @@ -78,8 +84,8 @@ static inline const char *guc_ct_buffer_type_to_str(u32 type) static void guc_ct_buffer_desc_init(struct guc_ct_buffer_desc *desc, u32 cmds_addr, u32 size, u32 owner) { - DRM_DEBUG_DRIVER("CT: desc %p init addr=%#x size=%u owner=%u\n", - desc, cmds_addr, size, owner); + CT_DEBUG_DRIVER("CT: desc %p init addr=%#x size=%u owner=%u\n", + desc, cmds_addr, size, owner); memset(desc, 0, sizeof(*desc)); desc->addr = cmds_addr; desc->size = size; @@ -88,8 +94,8 @@ static void guc_ct_buffer_desc_init(struct guc_ct_buffer_desc *desc, static void guc_ct_buffer_desc_reset(struct guc_ct_buffer_desc *desc) { - DRM_DEBUG_DRIVER("CT: desc %p reset head=%u tail=%u\n", - desc, desc->head, desc->tail); + CT_DEBUG_DRIVER("CT: desc %p reset head=%u tail=%u\n", + desc, desc->head, desc->tail); desc->head = 0; desc->tail = 0; desc->is_in_error = 0; @@ -185,8 +191,8 @@ static int ctch_init(struct intel_guc *guc, err = PTR_ERR(blob); goto err_vma; } - DRM_DEBUG_DRIVER("CT: vma base=%#x\n", - intel_guc_ggtt_offset(guc, ctch->vma)); + CT_DEBUG_DRIVER("CT: vma base=%#x\n", + intel_guc_ggtt_offset(guc, ctch->vma)); /* store pointers to desc and cmds */ for (i = 0; i < ARRAY_SIZE(ctch->ctbs); i++) { @@ -200,8 +206,8 @@ static int ctch_init(struct intel_guc *guc, err_vma: i915_vma_unpin_and_release(&ctch->vma); err_out: - DRM_DEBUG_DRIVER("CT: channel %d initialization failed; err=%d\n", - ctch->owner, err); + CT_DEBUG_DRIVER("CT: channel %d initialization failed; err=%d\n", + ctch->owner, err); return err; } @@ -221,8 +227,8 @@ static int ctch_open(struct intel_guc *guc, int err; int i; - DRM_DEBUG_DRIVER("CT: channel %d reopen=%s\n", - ctch->owner, yesno(ctch_is_open(ctch))); + CT_DEBUG_DRIVER("CT: channel %d reopen=%s\n", + ctch->owner, yesno(ctch_is_open(ctch))); if (!ctch->vma) { err = ctch_init(guc, ctch); @@ -355,6 +361,10 @@ static int ctb_write(struct intel_guc_ct_buffer *ctb, (want_response ? GUC_CT_MSG_SEND_STATUS : 0) | (action[0] << GUC_CT_MSG_ACTION_SHIFT); + CT_DEBUG_DRIVER("CT: writing %*phn %*phn %*phn\n", + 4, &header, 4, &fence, + 4 * (len - 1), &action[1]); + cmds[tail] = header; tail = (tail + 1) % size; @@ -545,6 +555,9 @@ static int intel_guc_send_ct(struct intel_guc *guc, const u32 *action, u32 len, if (unlikely(ret < 0)) { DRM_ERROR("CT: send action %#X failed; err=%d status=%#X\n", action[0], ret, status); + } else if (unlikely(ret)) { + CT_DEBUG_DRIVER("CT: send action %#x returned %d (%#x)\n", + action[0], ret, ret); } mutex_unlock(&guc->send_mutex); @@ -591,6 +604,7 @@ static int ctb_read(struct intel_guc_ct_buffer *ctb, u32 *data) /* beware of buffer wrap case */ if (unlikely(available < 0)) available += size; + CT_DEBUG_DRIVER("CT: available %d (%u:%u)\n", available, head, tail); GEM_BUG_ON(available < 0); data[0] = cmds[head]; @@ -612,6 +626,7 @@ static int ctb_read(struct intel_guc_ct_buffer *ctb, u32 *data) data[i] = cmds[head]; head = (head + 1) % size; } + CT_DEBUG_DRIVER("CT: received %*phn\n", 4 * len, data); desc->head = head * 4; return 0; @@ -665,11 +680,13 @@ static int ct_handle_response(struct intel_guc_ct *ct, const u32 *msg) return -EPROTO; } + CT_DEBUG_DRIVER("CT: response fence %u status %#x\n", fence, status); + spin_lock(&ct->lock); list_for_each_entry(req, &ct->pending_requests, link) { if (unlikely(fence != req->fence)) { - DRM_DEBUG_DRIVER("CT: request %u awaits response\n", - req->fence); + CT_DEBUG_DRIVER("CT: request %u awaits response\n", + req->fence); continue; } if (unlikely(datalen > req->response_len)) { @@ -696,6 +713,8 @@ static void ct_process_request(struct intel_guc_ct *ct, { struct intel_guc *guc = ct_to_guc(ct); + CT_DEBUG_DRIVER("CT: request %x %*phn\n", action, 4 * len, payload); + switch (action) { case INTEL_GUC_ACTION_DEFAULT: if (unlikely(len < 1)) -- cgit v1.2.3 From 4d07f6c40a764748f3c30c65d9f8e75a36fd1ad9 Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Wed, 28 Mar 2018 13:58:50 -0700 Subject: drm/i915/guc: enable guc interrupts unconditionally in uc_resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Probably lost while rebasing commit eacd8391f977 ("drm/i915/guc: Keep GuC interrupts enabled when using GuC"). Not really needed since i915_gem_init_hw is called before uc_resume, but it brings symmetry to uc_suspend. Signed-off-by: Michel Thierry Cc: Michał Winiarski Reviewed-by: Michał Winiarski Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180328205851.16188-1-michel.thierry@intel.com --- drivers/gpu/drm/i915/intel_uc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 081e42462aad..1cffaf7b5dbe 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -480,8 +480,7 @@ int intel_uc_resume(struct drm_i915_private *i915) if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS) return 0; - if (i915_modparams.guc_log_level) - gen9_enable_guc_interrupts(i915); + gen9_enable_guc_interrupts(i915); err = intel_guc_resume(guc); if (err) { -- cgit v1.2.3 From e770276079fd6e1088a255dee182a3c09a2d7aa9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 27 Mar 2018 22:01:57 +0100 Subject: drm/i915: Include the HW breadcrumb whenever we trace the global_seqno When we include a request's global_seqno in a GEM_TRACE it often helps to know how that relates to the current breadcrumb as seen by the hardware. Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180327210157.16896-3-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin --- drivers/gpu/drm/i915/i915_request.c | 28 +++++++++++++++++----------- drivers/gpu/drm/i915/intel_lrc.c | 6 ++++-- 2 files changed, 21 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 2314a26cd7f8..585242831974 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -214,8 +214,11 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno) struct i915_gem_timeline *timeline; struct intel_timeline *tl = engine->timeline; - GEM_TRACE("%s seqno %d -> %d\n", - engine->name, tl->seqno, seqno); + GEM_TRACE("%s seqno %d (current %d) -> %d\n", + engine->name, + tl->seqno, + intel_engine_get_seqno(engine), + seqno); if (!i915_seqno_passed(seqno, tl->seqno)) { /* Flush any waiters before we reuse the seqno */ @@ -386,10 +389,11 @@ static void i915_request_retire(struct i915_request *request) struct intel_engine_cs *engine = request->engine; struct i915_gem_active *active, *next; - GEM_TRACE("%s(%d) fence %llx:%d, global_seqno %d\n", - engine->name, intel_engine_get_seqno(engine), + GEM_TRACE("%s fence %llx:%d, global_seqno %d, current %d\n", + engine->name, request->fence.context, request->fence.seqno, - request->global_seqno); + request->global_seqno, + intel_engine_get_seqno(engine)); lockdep_assert_held(&request->i915->drm.struct_mutex); GEM_BUG_ON(!i915_sw_fence_signaled(&request->submit)); @@ -508,10 +512,11 @@ void __i915_request_submit(struct i915_request *request) struct intel_engine_cs *engine = request->engine; u32 seqno; - GEM_TRACE("%s fence %llx:%d -> global_seqno %d\n", - request->engine->name, + GEM_TRACE("%s fence %llx:%d -> global_seqno %d, current %d\n", + engine->name, request->fence.context, request->fence.seqno, - engine->timeline->seqno + 1); + engine->timeline->seqno + 1, + intel_engine_get_seqno(engine)); GEM_BUG_ON(!irqs_disabled()); lockdep_assert_held(&engine->timeline->lock); @@ -557,10 +562,11 @@ void __i915_request_unsubmit(struct i915_request *request) { struct intel_engine_cs *engine = request->engine; - GEM_TRACE("%s fence %llx:%d <- global_seqno %d\n", - request->engine->name, + GEM_TRACE("%s fence %llx:%d <- global_seqno %d, current %d\n", + engine->name, request->fence.context, request->fence.seqno, - request->global_seqno); + request->global_seqno, + intel_engine_get_seqno(engine)); GEM_BUG_ON(!irqs_disabled()); lockdep_assert_held(&engine->timeline->lock); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 654634254b64..f60b61bf8b3b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -454,10 +454,11 @@ static void execlists_submit_ports(struct intel_engine_cs *engine) desc = execlists_update_context(rq); GEM_DEBUG_EXEC(port[n].context_id = upper_32_bits(desc)); - GEM_TRACE("%s in[%d]: ctx=%d.%d, seqno=%x, prio=%d\n", + GEM_TRACE("%s in[%d]: ctx=%d.%d, seqno=%d (current %d), prio=%d\n", engine->name, n, port[n].context_id, count, rq->global_seqno, + intel_engine_get_seqno(engine), rq_prio(rq)); } else { GEM_BUG_ON(!n); @@ -999,10 +1000,11 @@ static void execlists_submission_tasklet(unsigned long data) EXECLISTS_ACTIVE_USER)); rq = port_unpack(port, &count); - GEM_TRACE("%s out[0]: ctx=%d.%d, seqno=%x, prio=%d\n", + GEM_TRACE("%s out[0]: ctx=%d.%d, seqno=%d (current %d), prio=%d\n", engine->name, port->context_id, count, rq ? rq->global_seqno : 0, + intel_engine_get_seqno(engine), rq ? rq_prio(rq) : 0); /* Check the context/desc id for this event matches */ -- cgit v1.2.3 From 1de401c08fa805f3ac34604af1d43f48aeb17eb4 Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Mon, 26 Mar 2018 14:39:48 +0100 Subject: drm/i915/perf: enable perf support on ICL No significant changes from either context offsets, nor report formats, nor register whitelist. v2: Also drop slice/unslice clock ratio changes (Matt) Signed-off-by: Lionel Landwerlin Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20180326133949.12469-3-lionel.g.landwerlin@intel.com --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/i915_oa_icl.c | 118 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_oa_icl.h | 34 +++++++++++ drivers/gpu/drm/i915/i915_perf.c | 7 ++- 4 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/i915/i915_oa_icl.c create mode 100644 drivers/gpu/drm/i915/i915_oa_icl.h (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 552e43e9663f..0c79c19223af 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -172,7 +172,8 @@ i915-y += i915_perf.o \ i915_oa_glk.o \ i915_oa_cflgt2.o \ i915_oa_cflgt3.o \ - i915_oa_cnl.o + i915_oa_cnl.o \ + i915_oa_icl.o ifeq ($(CONFIG_DRM_I915_GVT),y) i915-y += intel_gvt.o diff --git a/drivers/gpu/drm/i915/i915_oa_icl.c b/drivers/gpu/drm/i915/i915_oa_icl.c new file mode 100644 index 000000000000..a5667926e3de --- /dev/null +++ b/drivers/gpu/drm/i915/i915_oa_icl.c @@ -0,0 +1,118 @@ +/* + * Autogenerated file by GPU Top : https://github.com/rib/gputop + * DO NOT EDIT manually! + * + * + * Copyright (c) 2015 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 + +#include "i915_drv.h" +#include "i915_oa_icl.h" + +static const struct i915_oa_reg b_counter_config_test_oa[] = { + { _MMIO(0x2740), 0x00000000 }, + { _MMIO(0x2710), 0x00000000 }, + { _MMIO(0x2714), 0xf0800000 }, + { _MMIO(0x2720), 0x00000000 }, + { _MMIO(0x2724), 0xf0800000 }, + { _MMIO(0x2770), 0x00000004 }, + { _MMIO(0x2774), 0x0000ffff }, + { _MMIO(0x2778), 0x00000003 }, + { _MMIO(0x277c), 0x0000ffff }, + { _MMIO(0x2780), 0x00000007 }, + { _MMIO(0x2784), 0x0000ffff }, + { _MMIO(0x2788), 0x00100002 }, + { _MMIO(0x278c), 0x0000fff7 }, + { _MMIO(0x2790), 0x00100002 }, + { _MMIO(0x2794), 0x0000ffcf }, + { _MMIO(0x2798), 0x00100082 }, + { _MMIO(0x279c), 0x0000ffef }, + { _MMIO(0x27a0), 0x001000c2 }, + { _MMIO(0x27a4), 0x0000ffe7 }, + { _MMIO(0x27a8), 0x00100001 }, + { _MMIO(0x27ac), 0x0000ffe7 }, +}; + +static const struct i915_oa_reg flex_eu_config_test_oa[] = { +}; + +static const struct i915_oa_reg mux_config_test_oa[] = { + { _MMIO(0xd04), 0x00000200 }, + { _MMIO(0x9840), 0x00000000 }, + { _MMIO(0x9884), 0x00000000 }, + { _MMIO(0x9888), 0x10060000 }, + { _MMIO(0x9888), 0x22060000 }, + { _MMIO(0x9888), 0x16060000 }, + { _MMIO(0x9888), 0x24060000 }, + { _MMIO(0x9888), 0x18060000 }, + { _MMIO(0x9888), 0x1a060000 }, + { _MMIO(0x9888), 0x12060000 }, + { _MMIO(0x9888), 0x14060000 }, + { _MMIO(0x9888), 0x10060000 }, + { _MMIO(0x9888), 0x22060000 }, + { _MMIO(0x9884), 0x00000003 }, + { _MMIO(0x9888), 0x16130000 }, + { _MMIO(0x9888), 0x24000001 }, + { _MMIO(0x9888), 0x0e130056 }, + { _MMIO(0x9888), 0x10130000 }, + { _MMIO(0x9888), 0x1a130000 }, + { _MMIO(0x9888), 0x541f0001 }, + { _MMIO(0x9888), 0x181f0000 }, + { _MMIO(0x9888), 0x4c1f0000 }, + { _MMIO(0x9888), 0x301f0000 }, +}; + +static ssize_t +show_test_oa_id(struct device *kdev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "1\n"); +} + +void +i915_perf_load_test_config_icl(struct drm_i915_private *dev_priv) +{ + strlcpy(dev_priv->perf.oa.test_config.uuid, + "a291665e-244b-4b76-9b9a-01de9d3c8068", + sizeof(dev_priv->perf.oa.test_config.uuid)); + dev_priv->perf.oa.test_config.id = 1; + + dev_priv->perf.oa.test_config.mux_regs = mux_config_test_oa; + dev_priv->perf.oa.test_config.mux_regs_len = ARRAY_SIZE(mux_config_test_oa); + + dev_priv->perf.oa.test_config.b_counter_regs = b_counter_config_test_oa; + dev_priv->perf.oa.test_config.b_counter_regs_len = ARRAY_SIZE(b_counter_config_test_oa); + + dev_priv->perf.oa.test_config.flex_regs = flex_eu_config_test_oa; + dev_priv->perf.oa.test_config.flex_regs_len = ARRAY_SIZE(flex_eu_config_test_oa); + + dev_priv->perf.oa.test_config.sysfs_metric.name = "a291665e-244b-4b76-9b9a-01de9d3c8068"; + dev_priv->perf.oa.test_config.sysfs_metric.attrs = dev_priv->perf.oa.test_config.attrs; + + dev_priv->perf.oa.test_config.attrs[0] = &dev_priv->perf.oa.test_config.sysfs_metric_id.attr; + + dev_priv->perf.oa.test_config.sysfs_metric_id.attr.name = "id"; + dev_priv->perf.oa.test_config.sysfs_metric_id.attr.mode = 0444; + dev_priv->perf.oa.test_config.sysfs_metric_id.show = show_test_oa_id; +} diff --git a/drivers/gpu/drm/i915/i915_oa_icl.h b/drivers/gpu/drm/i915/i915_oa_icl.h new file mode 100644 index 000000000000..ae1c24aafe4f --- /dev/null +++ b/drivers/gpu/drm/i915/i915_oa_icl.h @@ -0,0 +1,34 @@ +/* + * Autogenerated file by GPU Top : https://github.com/rib/gputop + * DO NOT EDIT manually! + * + * + * Copyright (c) 2015 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 __I915_OA_ICL_H__ +#define __I915_OA_ICL_H__ + +extern void i915_perf_load_test_config_icl(struct drm_i915_private *dev_priv); + +#endif diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index abaca6edeb71..30444bb3aaa1 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -209,6 +209,7 @@ #include "i915_oa_cflgt2.h" #include "i915_oa_cflgt3.h" #include "i915_oa_cnl.h" +#include "i915_oa_icl.h" /* HW requires this to be a power of two, between 128k and 16M, though driver * is currently generally designed assuming the largest 16M size is used such @@ -1840,7 +1841,7 @@ static int gen8_enable_metric_set(struct drm_i915_private *dev_priv, * be read back from automatically triggered reports, as part of the * RPT_ID field. */ - if (IS_GEN9(dev_priv) || IS_GEN10(dev_priv)) { + if (IS_GEN(dev_priv, 9, 11)) { I915_WRITE(GEN8_OA_DEBUG, _MASKED_BIT_ENABLE(GEN9_OA_DEBUG_DISABLE_CLK_RATIO_REPORTS | GEN9_OA_DEBUG_INCLUDE_CLK_RATIO)); @@ -2935,6 +2936,8 @@ void i915_perf_register(struct drm_i915_private *dev_priv) i915_perf_load_test_config_cflgt3(dev_priv); } else if (IS_CANNONLAKE(dev_priv)) { i915_perf_load_test_config_cnl(dev_priv); + } else if (IS_ICELAKE(dev_priv)) { + i915_perf_load_test_config_icl(dev_priv); } if (dev_priv->perf.oa.test_config.id == 0) @@ -3467,7 +3470,7 @@ void i915_perf_init(struct drm_i915_private *dev_priv) dev_priv->perf.oa.gen8_valid_ctx_bit = (1<<16); } - } else if (IS_GEN10(dev_priv)) { + } else if (IS_GEN(dev_priv, 10, 11)) { dev_priv->perf.oa.ops.is_valid_b_counter_reg = gen7_is_valid_b_counter_addr; dev_priv->perf.oa.ops.is_valid_mux_reg = -- cgit v1.2.3 From b6dd47b9c82d619195370c38b7579fe18a8f6055 Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Mon, 26 Mar 2018 10:08:22 +0100 Subject: drm/i915/perf: check the value of PROP_SAMPLE_OA uapi parameter We've been a bit loose about this opening parameter. We should only add the flag for writing OA reports when the value of this parameter is != 0. Signed-off-by: Lionel Landwerlin Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20180326090831.22686-3-lionel.g.landwerlin@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 30444bb3aaa1..21a985bd4413 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -2746,7 +2746,8 @@ static int read_properties_unlocked(struct drm_i915_private *dev_priv, props->ctx_handle = value; break; case DRM_I915_PERF_PROP_SAMPLE_OA: - props->sample_flags |= SAMPLE_OA_REPORT; + if (value) + props->sample_flags |= SAMPLE_OA_REPORT; break; case DRM_I915_PERF_PROP_OA_METRICS_SET: if (value == 0) { -- cgit v1.2.3 From 11051303344bd4b3334a7b456f6152f4d6032c61 Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Mon, 26 Mar 2018 10:08:23 +0100 Subject: drm/i915/perf: simplify OA unit enabling on gen7 In commit d79651522e89c ("drm/i915: Enable i915 perf stream for Haswell OA unit") the enable/disable vfunc hadn't appear yet and the same function would deal with enabling/disabling the OA unit. This was split later on for gen8 but the gen7 retained some code that isn't actually useful anymore. Signed-off-by: Lionel Landwerlin Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20180326090831.22686-4-lionel.g.landwerlin@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 21a985bd4413..f1af58a1cc5a 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1886,6 +1886,13 @@ static void gen10_disable_metric_set(struct drm_i915_private *dev_priv) static void gen7_oa_enable(struct drm_i915_private *dev_priv) { + struct i915_gem_context *ctx = + dev_priv->perf.oa.exclusive_stream->ctx; + u32 ctx_id = dev_priv->perf.oa.specific_ctx_id; + bool periodic = dev_priv->perf.oa.periodic; + u32 period_exponent = dev_priv->perf.oa.period_exponent; + u32 report_format = dev_priv->perf.oa.oa_buffer.format; + /* * Reset buf pointers so we don't forward reports from before now. * @@ -1897,25 +1904,14 @@ static void gen7_oa_enable(struct drm_i915_private *dev_priv) */ gen7_init_oa_buffer(dev_priv); - if (dev_priv->perf.oa.exclusive_stream->enabled) { - struct i915_gem_context *ctx = - dev_priv->perf.oa.exclusive_stream->ctx; - u32 ctx_id = dev_priv->perf.oa.specific_ctx_id; - - bool periodic = dev_priv->perf.oa.periodic; - u32 period_exponent = dev_priv->perf.oa.period_exponent; - u32 report_format = dev_priv->perf.oa.oa_buffer.format; - - I915_WRITE(GEN7_OACONTROL, - (ctx_id & GEN7_OACONTROL_CTX_MASK) | - (period_exponent << - GEN7_OACONTROL_TIMER_PERIOD_SHIFT) | - (periodic ? GEN7_OACONTROL_TIMER_ENABLE : 0) | - (report_format << GEN7_OACONTROL_FORMAT_SHIFT) | - (ctx ? GEN7_OACONTROL_PER_CTX_ENABLE : 0) | - GEN7_OACONTROL_ENABLE); - } else - I915_WRITE(GEN7_OACONTROL, 0); + I915_WRITE(GEN7_OACONTROL, + (ctx_id & GEN7_OACONTROL_CTX_MASK) | + (period_exponent << + GEN7_OACONTROL_TIMER_PERIOD_SHIFT) | + (periodic ? GEN7_OACONTROL_TIMER_ENABLE : 0) | + (report_format << GEN7_OACONTROL_FORMAT_SHIFT) | + (ctx ? GEN7_OACONTROL_PER_CTX_ENABLE : 0) | + GEN7_OACONTROL_ENABLE); } static void gen8_oa_enable(struct drm_i915_private *dev_priv) -- cgit v1.2.3 From 53744104bec47a3357622f9d6815fda1c0d0f842 Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Mon, 26 Mar 2018 10:08:25 +0100 Subject: drm/i915/perf: remove empty line This was added by mistake in commit 28964cf25ee67 ("drm/i915/perf: disable NOA logic when not used"). Signed-off-by: Lionel Landwerlin Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20180326090831.22686-6-lionel.g.landwerlin@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index f1af58a1cc5a..b5c65ab2615e 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1871,7 +1871,6 @@ static void gen8_disable_metric_set(struct drm_i915_private *dev_priv) I915_WRITE(GDT_CHICKEN_BITS, (I915_READ(GDT_CHICKEN_BITS) & ~GT_NOA_ENABLE)); - } static void gen10_disable_metric_set(struct drm_i915_private *dev_priv) -- cgit v1.2.3 From b82ed43de5c01e41a7e5d756da3287fc66e7600b Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Mon, 26 Mar 2018 10:08:26 +0100 Subject: drm/i915: rename PPGTT/GGTT fields OA registers We had a generic field name used across 2 registers but it feels like it's clearer we make it obvious what register this field belongs to. Signed-off-by: Lionel Landwerlin Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20180326090831.22686-7-lionel.g.landwerlin@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 7 ++++--- drivers/gpu/drm/i915/i915_reg.h | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index b5c65ab2615e..d41a2529bb76 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1043,7 +1043,7 @@ static int gen7_append_oa_reports(struct i915_perf_stream *stream, I915_WRITE(GEN7_OASTATUS2, ((head & GEN7_OASTATUS2_HEAD_MASK) | - OA_MEM_SELECT_GGTT)); + GEN7_OASTATUS2_MEM_SELECT_GGTT)); dev_priv->perf.oa.oa_buffer.head = head; spin_unlock_irqrestore(&dev_priv->perf.oa.oa_buffer.ptr_lock, flags); @@ -1333,7 +1333,8 @@ static void gen7_init_oa_buffer(struct drm_i915_private *dev_priv) /* Pre-DevBDW: OABUFFER must be set with counters off, * before OASTATUS1, but after OASTATUS2 */ - I915_WRITE(GEN7_OASTATUS2, gtt_offset | OA_MEM_SELECT_GGTT); /* head */ + I915_WRITE(GEN7_OASTATUS2, + gtt_offset | GEN7_OASTATUS2_MEM_SELECT_GGTT); /* head */ dev_priv->perf.oa.oa_buffer.head = gtt_offset; I915_WRITE(GEN7_OABUFFER, gtt_offset); @@ -1393,7 +1394,7 @@ static void gen8_init_oa_buffer(struct drm_i915_private *dev_priv) * bit." */ I915_WRITE(GEN8_OABUFFER, gtt_offset | - OABUFFER_SIZE_16M | OA_MEM_SELECT_GGTT); + OABUFFER_SIZE_16M | GEN8_OABUFFER_MEM_SELECT_GGTT); I915_WRITE(GEN8_OATAILPTR, gtt_offset & GEN8_OATAILPTR_MASK); /* Mark that we need updated tail pointers to read from... */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5a53d0e1583c..b926520803b6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -536,6 +536,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define GEN8_OABUFFER_UDW _MMIO(0x23b4) #define GEN8_OABUFFER _MMIO(0x2b14) +#define GEN8_OABUFFER_MEM_SELECT_GGTT (1 << 0) /* 0: PPGTT, 1: GGTT */ #define GEN7_OASTATUS1 _MMIO(0x2364) #define GEN7_OASTATUS1_TAIL_MASK 0xffffffc0 @@ -544,7 +545,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define GEN7_OASTATUS1_REPORT_LOST (1<<0) #define GEN7_OASTATUS2 _MMIO(0x2368) -#define GEN7_OASTATUS2_HEAD_MASK 0xffffffc0 +#define GEN7_OASTATUS2_HEAD_MASK 0xffffffc0 +#define GEN7_OASTATUS2_MEM_SELECT_GGTT (1 << 0) /* 0: PPGTT, 1: GGTT */ #define GEN8_OASTATUS _MMIO(0x2b08) #define GEN8_OASTATUS_OVERRUN_STATUS (1<<3) @@ -566,8 +568,6 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define OABUFFER_SIZE_8M (6<<3) #define OABUFFER_SIZE_16M (7<<3) -#define OA_MEM_SELECT_GGTT (1<<0) - /* * Flexible, Aggregate EU Counter Registers. * Note: these aren't contiguous -- cgit v1.2.3 From 9bd9be666008499bb9071e9e5472ded24e522f0b Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Mon, 26 Mar 2018 10:08:28 +0100 Subject: drm/i915/perf: add more debug message on perf open & configs This will make it easier to spot issues related to config creation/usage. Signed-off-by: Lionel Landwerlin Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20180326090831.22686-9-lionel.g.landwerlin@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index d41a2529bb76..bfc906cd4e5e 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -2096,13 +2096,17 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, if (stream->ctx) { ret = oa_get_render_ctx_id(stream); - if (ret) + if (ret) { + DRM_DEBUG("Invalid context id to filter with\n"); return ret; + } } ret = get_oa_config(dev_priv, props->metrics_set, &stream->oa_config); - if (ret) + if (ret) { + DRM_DEBUG("Invalid OA config id=%i\n", props->metrics_set); goto err_config; + } /* PRM - observability performance counters: * @@ -2129,8 +2133,10 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, ret = dev_priv->perf.oa.ops.enable_metric_set(dev_priv, stream->oa_config); - if (ret) + if (ret) { + DRM_DEBUG("Unable to enable metric set\n"); goto err_enable; + } stream->ops = &i915_oa_stream_ops; @@ -3292,6 +3298,8 @@ int i915_perf_add_config_ioctl(struct drm_device *dev, void *data, mutex_unlock(&dev_priv->perf.metrics_lock); + DRM_DEBUG("Added config %s id=%i\n", oa_config->uuid, oa_config->id); + return oa_config->id; sysfs_err: @@ -3348,6 +3356,9 @@ int i915_perf_remove_config_ioctl(struct drm_device *dev, void *data, &oa_config->sysfs_metric); idr_remove(&dev_priv->perf.metrics_idr, *arg); + + DRM_DEBUG("Removed config %s id=%i\n", oa_config->uuid, oa_config->id); + put_oa_config(dev_priv, oa_config); config_err: -- cgit v1.2.3 From 5807e1c21dbd56c87f0e86ae6fe49ec745660c0d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 29 Mar 2018 23:45:18 +0100 Subject: drm/i915: Avoid sleeping inside per-engine reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only sleep and repeat when asked for a full device reset (ALL_ENGINES) and avoid using sleeping waits when asked for a per-engine reset. The goal is to be able to use a per-engine reset from hardirq/softirq/timer context. A consequence is that our individual wait timeouts are a thousand times shorter, on the order of a hundred microseconds rather than hundreds of millisecond. This may make hitting the timeouts more common, but hopefully the fallover to the full-device reset will be sufficient to pick up the pieces. Note, that the sleeps inside older gen (pre-gen8) have been left as they are only used in full device reset mode. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Michał Winiarski CC: Michel Thierry Cc: Jeff McGee Cc: Tvrtko Ursulin Reviewed-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180329224519.13598-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_uncore.c | 51 ++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index f37ecfc69e49..a0d7e0cfbd32 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1702,11 +1702,10 @@ static void gen3_stop_engine(struct intel_engine_cs *engine) const i915_reg_t mode = RING_MI_MODE(base); I915_WRITE_FW(mode, _MASKED_BIT_ENABLE(STOP_RING)); - if (intel_wait_for_register_fw(dev_priv, - mode, - MODE_IDLE, - MODE_IDLE, - 500)) + if (__intel_wait_for_register_fw(dev_priv, + mode, MODE_IDLE, MODE_IDLE, + 500, 0, + NULL)) DRM_DEBUG_DRIVER("%s: timed out on STOP_RING\n", engine->name); @@ -1860,9 +1859,10 @@ static int gen6_hw_domain_reset(struct drm_i915_private *dev_priv, __raw_i915_write32(dev_priv, GEN6_GDRST, hw_domain_mask); /* Wait for the device to ack the reset requests */ - err = intel_wait_for_register_fw(dev_priv, - GEN6_GDRST, hw_domain_mask, 0, - 500); + err = __intel_wait_for_register_fw(dev_priv, + GEN6_GDRST, hw_domain_mask, 0, + 500, 0, + NULL); if (err) DRM_DEBUG_DRIVER("Wait for 0x%08x engines reset failed\n", hw_domain_mask); @@ -2027,11 +2027,12 @@ static int gen8_reset_engine_start(struct intel_engine_cs *engine) I915_WRITE_FW(RING_RESET_CTL(engine->mmio_base), _MASKED_BIT_ENABLE(RESET_CTL_REQUEST_RESET)); - ret = intel_wait_for_register_fw(dev_priv, - RING_RESET_CTL(engine->mmio_base), - RESET_CTL_READY_TO_RESET, - RESET_CTL_READY_TO_RESET, - 700); + ret = __intel_wait_for_register_fw(dev_priv, + RING_RESET_CTL(engine->mmio_base), + RESET_CTL_READY_TO_RESET, + RESET_CTL_READY_TO_RESET, + 700, 0, + NULL); if (ret) DRM_ERROR("%s: reset request timeout\n", engine->name); @@ -2094,15 +2095,31 @@ int intel_gpu_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) int retry; int ret; - might_sleep(); + /* + * We want to perform per-engine reset from atomic context (e.g. + * softirq), which imposes the constraint that we cannot sleep. + * However, experience suggests that spending a bit of time waiting + * for a reset helps in various cases, so for a full-device reset + * we apply the opposite rule and wait if we want to. As we should + * always follow up a failed per-engine reset with a full device reset, + * being a little faster, stricter and more error prone for the + * atomic case seems an acceptable compromise. + * + * Unfortunately this leads to a bimodal routine, when the goal was + * to have a single reset function that worked for resetting any + * number of engines simultaneously. + */ + might_sleep_if(engine_mask == ALL_ENGINES); - /* If the power well sleeps during the reset, the reset + /* + * If the power well sleeps during the reset, the reset * request may be dropped and never completes (causing -EIO). */ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); for (retry = 0; retry < 3; retry++) { - /* We stop engines, otherwise we might get failed reset and a + /* + * We stop engines, otherwise we might get failed reset and a * dead gpu (on elk). Also as modern gpu as kbl can suffer * from system hang if batchbuffer is progressing when * the reset is issued, regardless of READY_TO_RESET ack. @@ -2120,7 +2137,7 @@ int intel_gpu_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) GEM_TRACE("engine_mask=%x\n", engine_mask); ret = reset(dev_priv, engine_mask); } - if (ret != -ETIMEDOUT) + if (ret != -ETIMEDOUT || engine_mask != ALL_ENGINES) break; cond_resched(); -- cgit v1.2.3 From 3df82dd43be4b6efde20f819d5829c8ed5e95476 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 29 Mar 2018 23:45:19 +0100 Subject: drm/i915: Only warn for might_sleep() before a slow wait_for_register As intel_wait_for_register_fw() may use, and if successful only use, a busy-wait loop, the might_sleep() warning is a little over-zealous. Restrict it to a might_sleep_if() a slow timeout is specified (and so the caller authorises use of a usleep). Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180329224519.13598-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_uncore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index a0d7e0cfbd32..e7540bb9786c 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1996,7 +1996,7 @@ int __intel_wait_for_register(struct drm_i915_private *dev_priv, u32 reg_value; int ret; - might_sleep(); + might_sleep_if(slow_timeout_ms); spin_lock_irq(&dev_priv->uncore.lock); intel_uncore_forcewake_get__locked(dev_priv, fw); @@ -2008,7 +2008,7 @@ int __intel_wait_for_register(struct drm_i915_private *dev_priv, intel_uncore_forcewake_put__locked(dev_priv, fw); spin_unlock_irq(&dev_priv->uncore.lock); - if (ret) + if (ret && slow_timeout_ms) ret = __wait_for(reg_value = I915_READ_NOTRACE(reg), (reg_value & mask) == value, slow_timeout_ms * 1000, 10, 1000); -- cgit v1.2.3 From 6ce9b78a7388c37b33293666aa6fc61c177046e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 28 Mar 2018 15:30:39 -0700 Subject: drm/i915/psr: Nuke aux frame sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit eDP spec states that aux frame is required to do PSR2 selective update but i915 don't fully implement it. It sends the aux frame sync messages but the value is always zero as the GTC is not enabled in driver. Through tests was findout that pannels can do selective update when the y-coordinate is also included in SDP, that is why it is required to run PSR2 in i915. A dummy value is not useful at all to sink, so removing everything related to aux frame sync, if GTC is enabled we can bring this back. Cc: Vathsala Nagaraju Acked-by: Rodrigo Vivi Reviewed-by: Dhinakaran Pandiyan Signed-off-by: José Roberto de Souza Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180328223046.16125-3-jose.souza@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_psr.c | 24 +----------------------- 2 files changed, 1 insertion(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 800230ba1c3b..fade9029b6f5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -603,7 +603,6 @@ struct i915_psr { struct delayed_work work; unsigned busy_frontbuffer_bits; bool psr2_support; - bool aux_frame_sync; bool link_standby; bool y_cord_support; bool colorimetry_support; diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index b8e083e10029..c0a6f63b586f 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -137,16 +137,9 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) if (INTEL_GEN(dev_priv) >= 9 && (intel_dp->psr_dpcd[0] & DP_PSR2_IS_SUPPORTED)) { - uint8_t frame_sync_cap; dev_priv->psr.sink_support = true; - if (drm_dp_dpcd_readb(&intel_dp->aux, - DP_SINK_DEVICE_AUX_FRAME_SYNC_CAP, - &frame_sync_cap) != 1) - frame_sync_cap = 0; - dev_priv->psr.aux_frame_sync = frame_sync_cap & DP_AUX_FRAME_SYNC_CAP; - /* PSR2 needs frame sync as well */ - dev_priv->psr.psr2_support = dev_priv->psr.aux_frame_sync; + dev_priv->psr.psr2_support = true; DRM_DEBUG_KMS("PSR2 %s on sink", dev_priv->psr.psr2_support ? "supported" : "not supported"); @@ -268,12 +261,6 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp) struct drm_device *dev = dig_port->base.base.dev; struct drm_i915_private *dev_priv = to_i915(dev); - - /* Enable AUX frame sync at sink */ - if (dev_priv->psr.aux_frame_sync) - drm_dp_dpcd_writeb(&intel_dp->aux, - DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF, - DP_AUX_FRAME_SYNC_ENABLE); /* Enable ALPM at sink for psr2 */ if (dev_priv->psr.psr2_support && dev_priv->psr.alpm) drm_dp_dpcd_writeb(&intel_dp->aux, @@ -712,11 +699,6 @@ static void hsw_psr_disable(struct intel_dp *intel_dp, i915_reg_t psr_status; u32 psr_status_mask; - if (dev_priv->psr.aux_frame_sync) - drm_dp_dpcd_writeb(&intel_dp->aux, - DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF, - 0); - if (dev_priv->psr.psr2_support) { psr_status = EDP_PSR2_STATUS; psr_status_mask = EDP_PSR2_STATUS_STATE_MASK; @@ -860,10 +842,6 @@ static void intel_psr_exit(struct drm_i915_private *dev_priv) return; if (HAS_DDI(dev_priv)) { - if (dev_priv->psr.aux_frame_sync) - drm_dp_dpcd_writeb(&intel_dp->aux, - DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF, - 0); if (dev_priv->psr.psr2_support) { val = I915_READ(EDP_PSR2_CTL); WARN_ON(!(val & EDP_PSR2_ENABLE)); -- cgit v1.2.3 From aee3bac0a3a89ea12644533142ba69eebb602e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 28 Mar 2018 15:30:40 -0700 Subject: drm/i915/psr: Tie PSR2 support to Y coordinate requirement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although i915 don't implement aux sync frame through tests was findout that pannels can do selective update when the y-coordinate is also included in SDP, that is why it is required to run PSR2 in i915. So moving to only one place the sink requirements that the actual driver needs to enable PSR2. Also intel_psr2_config_valid() is called every time the crtc config is computed, wasting some time every time it was checking for Y coordinate requirement. This allow us to nuke y_cord_support and some of VSC setup code that was handling a scenario that would never happen(PSR2 without Y coordinate). Also here renaming intel_dp_get_y_cord_status() to intel_dp_get_y_coord_required() as it more accurate to the name and function of bit according to eDP spec. Cc: Rodrigo Vivi Reviewed-by: Dhinakaran Pandiyan Signed-off-by: José Roberto de Souza Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180328223046.16125-4-jose.souza@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_psr.c | 46 +++++++++++++++++----------------------- 2 files changed, 19 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fade9029b6f5..92cf6f4e9e00 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -604,7 +604,6 @@ struct i915_psr { unsigned busy_frontbuffer_bits; bool psr2_support; bool link_standby; - bool y_cord_support; bool colorimetry_support; bool alpm; bool has_hw_tracking; diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index c0a6f63b586f..fb2d0fe7106b 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -93,7 +93,7 @@ static void psr_aux_io_power_put(struct intel_dp *intel_dp) intel_display_power_put(dev_priv, psr_aux_domain(intel_dp)); } -static bool intel_dp_get_y_cord_status(struct intel_dp *intel_dp) +static bool intel_dp_get_y_coord_required(struct intel_dp *intel_dp) { uint8_t psr_caps = 0; @@ -130,22 +130,29 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd, sizeof(intel_dp->psr_dpcd)); - if (intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED) { + if (intel_dp->psr_dpcd[0]) { dev_priv->psr.sink_support = true; DRM_DEBUG_KMS("Detected EDP PSR Panel.\n"); } if (INTEL_GEN(dev_priv) >= 9 && - (intel_dp->psr_dpcd[0] & DP_PSR2_IS_SUPPORTED)) { - - dev_priv->psr.sink_support = true; - dev_priv->psr.psr2_support = true; + (intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_IS_SUPPORTED)) { + /* + * All panels that supports PSR version 03h (PSR2 + + * Y-coordinate) can handle Y-coordinates in VSC but we are + * only sure that it is going to be used when required by the + * panel. This way panel is capable to do selective update + * without a aux frame sync. + * + * To support PSR version 02h and PSR version 03h without + * Y-coordinate requirement panels we would need to enable + * GTC first. + */ + dev_priv->psr.psr2_support = intel_dp_get_y_coord_required(intel_dp); DRM_DEBUG_KMS("PSR2 %s on sink", dev_priv->psr.psr2_support ? "supported" : "not supported"); if (dev_priv->psr.psr2_support) { - dev_priv->psr.y_cord_support = - intel_dp_get_y_cord_status(intel_dp); dev_priv->psr.colorimetry_support = intel_dp_get_colorimetry_status(intel_dp); dev_priv->psr.alpm = @@ -191,16 +198,12 @@ static void hsw_psr_setup_vsc(struct intel_dp *intel_dp, memset(&psr_vsc, 0, sizeof(psr_vsc)); psr_vsc.sdp_header.HB0 = 0; psr_vsc.sdp_header.HB1 = 0x7; - if (dev_priv->psr.colorimetry_support && - dev_priv->psr.y_cord_support) { + if (dev_priv->psr.colorimetry_support) { psr_vsc.sdp_header.HB2 = 0x5; psr_vsc.sdp_header.HB3 = 0x13; - } else if (dev_priv->psr.y_cord_support) { + } else { psr_vsc.sdp_header.HB2 = 0x4; psr_vsc.sdp_header.HB3 = 0xe; - } else { - psr_vsc.sdp_header.HB2 = 0x3; - psr_vsc.sdp_header.HB3 = 0xc; } } else { /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */ @@ -457,15 +460,6 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, return false; } - /* - * FIXME:enable psr2 only for y-cordinate psr2 panels - * After gtc implementation , remove this restriction. - */ - if (!dev_priv->psr.y_cord_support) { - DRM_DEBUG_KMS("PSR2 not enabled, panel does not support Y coordinate\n"); - return false; - } - return true; } @@ -565,7 +559,6 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp, struct drm_device *dev = dig_port->base.base.dev; struct drm_i915_private *dev_priv = to_i915(dev); enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - u32 chicken; psr_aux_io_power_get(intel_dp); @@ -576,9 +569,8 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp, hsw_psr_setup_aux(intel_dp); if (dev_priv->psr.psr2_support) { - chicken = PSR2_VSC_ENABLE_PROG_HEADER; - if (dev_priv->psr.y_cord_support) - chicken |= PSR2_ADD_VERTICAL_LINE_COUNT; + u32 chicken = PSR2_VSC_ENABLE_PROG_HEADER + | PSR2_ADD_VERTICAL_LINE_COUNT; I915_WRITE(CHICKEN_TRANS(cpu_transcoder), chicken); I915_WRITE(EDP_PSR_DEBUG, -- cgit v1.2.3 From 5e87325f5c57ba59cc6908bf38efd40146d7ad9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 28 Mar 2018 15:30:41 -0700 Subject: drm/i915/psr/cnl: Enable Y-coordinate support in source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For Geminilake and Cannonlake+ the Y-coordinate support must be enabled in PSR2_CTL too. Spec: 7713 and 7720 Cc: Dhinakaran Pandiyan Reviewed-by: Rodrigo Vivi Signed-off-by: José Roberto de Souza Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180328223046.16125-5-jose.souza@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_psr.c | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b926520803b6..6566f6bc5417 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4058,6 +4058,8 @@ enum { #define EDP_PSR2_CTL _MMIO(0x6f900) #define EDP_PSR2_ENABLE (1<<31) #define EDP_SU_TRACK_ENABLE (1<<30) +#define EDP_Y_COORDINATE_VALID (1<<26) /* GLK and CNL+ */ +#define EDP_Y_COORDINATE_ENABLE (1<<25) /* GLK and CNL+ */ #define EDP_MAX_SU_DISABLE_TIME(t) ((t)<<20) #define EDP_MAX_SU_DISABLE_TIME_MASK (0x1f<<20) #define EDP_PSR2_TP2_TIME_500 (0<<8) @@ -7042,6 +7044,7 @@ 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 VSC_DATA_SEL_SOFTWARE_CONTROL (1<<25) /* GLK and CNL+ */ #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 */ diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index fb2d0fe7106b..84e1f8be5c48 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -386,8 +386,10 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) /* FIXME: selective update is probably totally broken because it doesn't * mesh at all with our frontbuffer tracking. And the hw alone isn't * good enough. */ - val |= EDP_PSR2_ENABLE | - EDP_SU_TRACK_ENABLE; + val |= EDP_PSR2_ENABLE | EDP_SU_TRACK_ENABLE; + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { + val |= EDP_Y_COORDINATE_VALID | EDP_Y_COORDINATE_ENABLE; + } if (drm_dp_dpcd_readb(&intel_dp->aux, DP_SYNCHRONIZATION_LATENCY_IN_SINK, @@ -569,8 +571,14 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp, hsw_psr_setup_aux(intel_dp); if (dev_priv->psr.psr2_support) { - u32 chicken = PSR2_VSC_ENABLE_PROG_HEADER - | PSR2_ADD_VERTICAL_LINE_COUNT; + u32 chicken = I915_READ(CHICKEN_TRANS(cpu_transcoder)); + + if (INTEL_GEN(dev_priv) == 9 && !IS_GEMINILAKE(dev_priv)) + chicken |= (PSR2_VSC_ENABLE_PROG_HEADER + | PSR2_ADD_VERTICAL_LINE_COUNT); + + else + chicken &= ~VSC_DATA_SEL_SOFTWARE_CONTROL; I915_WRITE(CHICKEN_TRANS(cpu_transcoder), chicken); I915_WRITE(EDP_PSR_DEBUG, -- cgit v1.2.3 From 95f28d2ec75ac388a8cc988e2e5496ce4adef4e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 28 Mar 2018 15:30:42 -0700 Subject: drm/i915/psr: Do not override PSR2 sink support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sink can support our PSR2 requirements but userspace can request a resolution that PSR2 hardware do not support, in this case it was overwritten the PSR2 sink support. Adding another flag here, this way if requested resolution changed to a value that PSR2 hardware can handle, PSR2 can be enabled. Cc: Dhinakaran Pandiyan Reviewed-by: Rodrigo Vivi Signed-off-by: José Roberto de Souza Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180328223046.16125-6-jose.souza@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++-- drivers/gpu/drm/i915/i915_drv.h | 3 ++- drivers/gpu/drm/i915/intel_psr.c | 33 +++++++++++++++++---------------- 3 files changed, 21 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index ff90577da450..1dba2c451255 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2630,7 +2630,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) yesno(work_busy(&dev_priv->psr.work.work))); if (HAS_DDI(dev_priv)) { - if (dev_priv->psr.psr2_support) + if (dev_priv->psr.psr2_enabled) enabled = I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE; else enabled = I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE; @@ -2678,7 +2678,7 @@ 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) { + if (dev_priv->psr.psr2_enabled) { u32 psr2 = I915_READ(EDP_PSR2_STATUS); seq_printf(m, "EDP_PSR2_STATUS: %x [%s]\n", diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 92cf6f4e9e00..46cae097201c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -602,11 +602,12 @@ struct i915_psr { bool active; struct delayed_work work; unsigned busy_frontbuffer_bits; - bool psr2_support; + bool sink_psr2_support; bool link_standby; bool colorimetry_support; bool alpm; bool has_hw_tracking; + bool psr2_enabled; void (*enable_source)(struct intel_dp *, const struct intel_crtc_state *); diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 84e1f8be5c48..5efddd920681 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -148,11 +148,12 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) * Y-coordinate requirement panels we would need to enable * GTC first. */ - dev_priv->psr.psr2_support = intel_dp_get_y_coord_required(intel_dp); - DRM_DEBUG_KMS("PSR2 %s on sink", - dev_priv->psr.psr2_support ? "supported" : "not supported"); + dev_priv->psr.sink_psr2_support = + intel_dp_get_y_coord_required(intel_dp); + DRM_DEBUG_KMS("PSR2 %s on sink", dev_priv->psr.sink_psr2_support + ? "supported" : "not supported"); - if (dev_priv->psr.psr2_support) { + if (dev_priv->psr.sink_psr2_support) { dev_priv->psr.colorimetry_support = intel_dp_get_colorimetry_status(intel_dp); dev_priv->psr.alpm = @@ -193,7 +194,7 @@ static void hsw_psr_setup_vsc(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev); struct edp_vsc_psr psr_vsc; - if (dev_priv->psr.psr2_support) { + if (dev_priv->psr.psr2_enabled) { /* Prepare VSC Header for SU as per EDP 1.4 spec, Table 6.11 */ memset(&psr_vsc, 0, sizeof(psr_vsc)); psr_vsc.sdp_header.HB0 = 0; @@ -265,7 +266,7 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = to_i915(dev); /* Enable ALPM at sink for psr2 */ - if (dev_priv->psr.psr2_support && dev_priv->psr.alpm) + if (dev_priv->psr.psr2_enabled && dev_priv->psr.alpm) drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, DP_ALPM_ENABLE); @@ -424,7 +425,7 @@ static void hsw_psr_activate(struct intel_dp *intel_dp) */ /* psr1 and psr2 are mutually exclusive.*/ - if (dev_priv->psr.psr2_support) + if (dev_priv->psr.psr2_enabled) hsw_activate_psr2(intel_dp); else hsw_activate_psr1(intel_dp); @@ -444,7 +445,7 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, * dynamically during PSR enable, and extracted from sink * caps during eDP detection. */ - if (!dev_priv->psr.psr2_support) + if (!dev_priv->psr.sink_psr2_support) return false; if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { @@ -543,7 +544,7 @@ static void intel_psr_activate(struct intel_dp *intel_dp) struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = to_i915(dev); - if (dev_priv->psr.psr2_support) + if (dev_priv->psr.psr2_enabled) WARN_ON(I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE); else WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE); @@ -570,7 +571,7 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp, if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) hsw_psr_setup_aux(intel_dp); - if (dev_priv->psr.psr2_support) { + if (dev_priv->psr.psr2_enabled) { u32 chicken = I915_READ(CHICKEN_TRANS(cpu_transcoder)); if (INTEL_GEN(dev_priv) == 9 && !IS_GEMINILAKE(dev_priv)) @@ -629,7 +630,7 @@ void intel_psr_enable(struct intel_dp *intel_dp, goto unlock; } - dev_priv->psr.psr2_support = crtc_state->has_psr2; + dev_priv->psr.psr2_enabled = crtc_state->has_psr2; dev_priv->psr.busy_frontbuffer_bits = 0; dev_priv->psr.setup_vsc(intel_dp, crtc_state); @@ -699,7 +700,7 @@ static void hsw_psr_disable(struct intel_dp *intel_dp, i915_reg_t psr_status; u32 psr_status_mask; - if (dev_priv->psr.psr2_support) { + if (dev_priv->psr.psr2_enabled) { psr_status = EDP_PSR2_STATUS; psr_status_mask = EDP_PSR2_STATUS_STATE_MASK; @@ -723,7 +724,7 @@ static void hsw_psr_disable(struct intel_dp *intel_dp, dev_priv->psr.active = false; } else { - if (dev_priv->psr.psr2_support) + if (dev_priv->psr.psr2_enabled) WARN_ON(I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE); else WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE); @@ -783,7 +784,7 @@ static void intel_psr_work(struct work_struct *work) * and be ready for re-enable. */ if (HAS_DDI(dev_priv)) { - if (dev_priv->psr.psr2_support) { + if (dev_priv->psr.psr2_enabled) { if (intel_wait_for_register(dev_priv, EDP_PSR2_STATUS, EDP_PSR2_STATUS_STATE_MASK, @@ -842,7 +843,7 @@ static void intel_psr_exit(struct drm_i915_private *dev_priv) return; if (HAS_DDI(dev_priv)) { - if (dev_priv->psr.psr2_support) { + if (dev_priv->psr.psr2_enabled) { val = I915_READ(EDP_PSR2_CTL); WARN_ON(!(val & EDP_PSR2_ENABLE)); I915_WRITE(EDP_PSR2_CTL, val & ~EDP_PSR2_ENABLE); @@ -1011,7 +1012,7 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, /* By definition flush = invalidate + flush */ if (frontbuffer_bits) { - if (dev_priv->psr.psr2_support || + if (dev_priv->psr.psr2_enabled || IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { intel_psr_exit(dev_priv); } else { -- cgit v1.2.3 From fe36181be371f3d98441cc23ccbfa89783fa55b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 28 Mar 2018 15:30:43 -0700 Subject: drm/i915/psr: Use PSR2 macro for PSR2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cosmetic change. Reviewed-by: Rodrigo Vivi Signed-off-by: José Roberto de Souza Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180328223046.16125-7-jose.souza@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 3 ++- drivers/gpu/drm/i915/intel_psr.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6566f6bc5417..17b86919cddf 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4069,8 +4069,9 @@ enum { #define EDP_PSR2_TP2_TIME_MASK (3<<8) #define EDP_PSR2_FRAME_BEFORE_SU_SHIFT 4 #define EDP_PSR2_FRAME_BEFORE_SU_MASK (0xf<<4) -#define EDP_PSR2_IDLE_MASK 0xf #define EDP_PSR2_FRAME_BEFORE_SU(a) ((a)<<4) +#define EDP_PSR2_IDLE_FRAME_MASK 0xf +#define EDP_PSR2_IDLE_FRAME_SHIFT 0 #define EDP_PSR2_STATUS _MMIO(0x6f940) #define EDP_PSR2_STATUS_STATE_MASK (0xf<<28) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 5efddd920681..bec455e28943 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -382,7 +382,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) uint32_t val; uint8_t sink_latency; - val = idle_frames << EDP_PSR_IDLE_FRAME_SHIFT; + val = idle_frames << EDP_PSR2_IDLE_FRAME_SHIFT; /* FIXME: selective update is probably totally broken because it doesn't * mesh at all with our frontbuffer tracking. And the hw alone isn't -- cgit v1.2.3 From 26e5378d115501a7cab25fdfc6ab10ccb5e4106f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 28 Mar 2018 15:30:44 -0700 Subject: drm/i915/psr: Cache sink synchronization latency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This value do not change overtime so better cache it than fetch it every PSR enable. Cc: Dhinakaran Pandiyan Reviewed-by: Rodrigo Vivi Signed-off-by: José Roberto de Souza Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180328223046.16125-8-jose.souza@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_psr.c | 28 ++++++++++++++++------------ 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 46cae097201c..5373b171bb96 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -608,6 +608,7 @@ struct i915_psr { bool alpm; bool has_hw_tracking; bool psr2_enabled; + u8 sink_sync_latency; void (*enable_source)(struct intel_dp *, const struct intel_crtc_state *); diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index bec455e28943..d079cf0b034c 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -122,6 +122,18 @@ static bool intel_dp_get_alpm_status(struct intel_dp *intel_dp) return alpm_caps & DP_ALPM_CAP; } +static u8 intel_dp_get_sink_sync_latency(struct intel_dp *intel_dp) +{ + u8 val = 0; + + if (drm_dp_dpcd_readb(&intel_dp->aux, + DP_SYNCHRONIZATION_LATENCY_IN_SINK, &val) == 1) + val &= DP_MAX_RESYNC_FRAME_COUNT_MASK; + else + DRM_ERROR("Unable to get sink synchronization latency\n"); + return val; +} + void intel_psr_init_dpcd(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = @@ -158,6 +170,8 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) intel_dp_get_colorimetry_status(intel_dp); dev_priv->psr.alpm = intel_dp_get_alpm_status(intel_dp); + dev_priv->psr.sink_sync_latency = + intel_dp_get_sink_sync_latency(intel_dp); } } } @@ -379,10 +393,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) * with the 5 or 6 idle patterns. */ uint32_t idle_frames = max(6, dev_priv->vbt.psr.idle_frames); - uint32_t val; - uint8_t sink_latency; - - val = idle_frames << EDP_PSR2_IDLE_FRAME_SHIFT; + u32 val = idle_frames << EDP_PSR2_IDLE_FRAME_SHIFT; /* FIXME: selective update is probably totally broken because it doesn't * mesh at all with our frontbuffer tracking. And the hw alone isn't @@ -392,14 +403,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) val |= EDP_Y_COORDINATE_VALID | EDP_Y_COORDINATE_ENABLE; } - if (drm_dp_dpcd_readb(&intel_dp->aux, - DP_SYNCHRONIZATION_LATENCY_IN_SINK, - &sink_latency) == 1) { - sink_latency &= DP_MAX_RESYNC_FRAME_COUNT_MASK; - } else { - sink_latency = 0; - } - val |= EDP_PSR2_FRAME_BEFORE_SU(sink_latency + 1); + val |= EDP_PSR2_FRAME_BEFORE_SU(dev_priv->psr.sink_sync_latency + 1); if (dev_priv->vbt.psr.tp2_tp3_wakeup_time > 5) val |= EDP_PSR2_TP2_TIME_2500; -- cgit v1.2.3 From 4df4925b1b26f285aa76f89d95db3388a2d55281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 28 Mar 2018 15:30:45 -0700 Subject: drm/i915/psr: Set DPCD PSR2 enable bit when needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the 2 eDP1.4a pannels tested set or not set bit have no effect but is better set it and comply with specification. Signed-off-by: José Roberto de Souza Cc: Dhinakaran Pandiyan Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180328223046.16125-9-jose.souza@intel.com --- drivers/gpu/drm/i915/intel_psr.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index d079cf0b034c..2d53f7398a6d 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -278,18 +278,19 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = dig_port->base.base.dev; struct drm_i915_private *dev_priv = to_i915(dev); + u8 dpcd_val = DP_PSR_ENABLE; /* Enable ALPM at sink for psr2 */ if (dev_priv->psr.psr2_enabled && dev_priv->psr.alpm) drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, DP_ALPM_ENABLE); + + if (dev_priv->psr.psr2_enabled) + dpcd_val |= DP_PSR_ENABLE_PSR2; if (dev_priv->psr.link_standby) - drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, - DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE); - else - drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, - DP_PSR_ENABLE); + dpcd_val |= DP_PSR_MAIN_LINK_ACTIVE; + drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, dpcd_val); drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0); } -- cgit v1.2.3 From f26052079070cd0e8940717a7a7cb7cdd512ac05 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 31 Mar 2018 14:06:26 +0100 Subject: drm/i915/execlists: Track begin/end of execlists submission sequences We would like to start doing some bookkeeping at the beginning, between contexts and at the end of execlists submission. We already mark the beginning and end using EXECLISTS_ACTIVE_USER, to provide an indication when the HW is idle. This give us a pair of sequence points we can then expand on for further bookkeeping. v2: Refactor guc submission to share the same begin/end. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Francisco Jerez Reviewed-by: Francisco Jerez Reviewed-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180331130626.10712-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_guc_submission.c | 17 ++++++---- drivers/gpu/drm/i915/intel_lrc.c | 50 ++++++++++++++++++++++------- drivers/gpu/drm/i915/intel_ringbuffer.h | 15 ++++++++- 3 files changed, 63 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 207cda062626..749f27916a02 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -728,7 +728,7 @@ done: execlists->first = rb; if (submit) { port_assign(port, last); - execlists_set_active(execlists, EXECLISTS_ACTIVE_USER); + execlists_user_begin(execlists, execlists->port); guc_submit(engine); } @@ -748,17 +748,20 @@ static void guc_submission_tasklet(unsigned long data) struct execlist_port *port = execlists->port; struct i915_request *rq; - rq = port_request(&port[0]); + rq = port_request(port); while (rq && i915_request_completed(rq)) { trace_i915_request_out(rq); i915_request_put(rq); - execlists_port_complete(execlists, port); - - rq = port_request(&port[0]); + port = execlists_port_complete(execlists, port); + if (port_isset(port)) { + execlists_user_begin(execlists, port); + rq = port_request(port); + } else { + execlists_user_end(execlists); + rq = NULL; + } } - if (!rq) - execlists_clear_active(execlists, EXECLISTS_ACTIVE_USER); if (execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT) && intel_read_status_page(engine, I915_GEM_HWS_PREEMPT_INDEX) == diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index f60b61bf8b3b..4d08875422b6 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -374,6 +374,19 @@ execlists_context_status_change(struct i915_request *rq, unsigned long status) status, rq); } +inline void +execlists_user_begin(struct intel_engine_execlists *execlists, + const struct execlist_port *port) +{ + execlists_set_active_once(execlists, EXECLISTS_ACTIVE_USER); +} + +inline void +execlists_user_end(struct intel_engine_execlists *execlists) +{ + execlists_clear_active(execlists, EXECLISTS_ACTIVE_USER); +} + static inline void execlists_context_schedule_in(struct i915_request *rq) { @@ -711,7 +724,7 @@ unlock: spin_unlock_irq(&engine->timeline->lock); if (submit) { - execlists_set_active(execlists, EXECLISTS_ACTIVE_USER); + execlists_user_begin(execlists, execlists->port); execlists_submit_ports(engine); } @@ -742,7 +755,7 @@ execlists_cancel_port_requests(struct intel_engine_execlists * const execlists) port++; } - execlists_clear_active(execlists, EXECLISTS_ACTIVE_USER); + execlists_user_end(execlists); } static void clear_gtiir(struct intel_engine_cs *engine) @@ -873,7 +886,7 @@ static void execlists_submission_tasklet(unsigned long data) { struct intel_engine_cs * const engine = (struct intel_engine_cs *)data; struct intel_engine_execlists * const execlists = &engine->execlists; - struct execlist_port * const port = execlists->port; + struct execlist_port *port = execlists->port; struct drm_i915_private *dev_priv = engine->i915; bool fw = false; @@ -1012,10 +1025,28 @@ static void execlists_submission_tasklet(unsigned long data) GEM_BUG_ON(count == 0); if (--count == 0) { + /* + * On the final event corresponding to the + * submission of this context, we expect either + * an element-switch event or a completion + * event (and on completion, the active-idle + * marker). No more preemptions, lite-restore + * or otherwise. + */ GEM_BUG_ON(status & GEN8_CTX_STATUS_PREEMPTED); GEM_BUG_ON(port_isset(&port[1]) && !(status & GEN8_CTX_STATUS_ELEMENT_SWITCH)); + GEM_BUG_ON(!port_isset(&port[1]) && + !(status & GEN8_CTX_STATUS_ACTIVE_IDLE)); + + /* + * We rely on the hardware being strongly + * ordered, that the breadcrumb write is + * coherent (visible from the CPU) before the + * user interrupt and CSB is processed. + */ GEM_BUG_ON(!i915_request_completed(rq)); + execlists_context_schedule_out(rq); trace_i915_request_out(rq); i915_request_put(rq); @@ -1023,17 +1054,14 @@ static void execlists_submission_tasklet(unsigned long data) GEM_TRACE("%s completed ctx=%d\n", engine->name, port->context_id); - execlists_port_complete(execlists, port); + port = execlists_port_complete(execlists, port); + if (port_isset(port)) + execlists_user_begin(execlists, port); + else + execlists_user_end(execlists); } else { port_set(port, port_pack(rq, count)); } - - /* After the final element, the hw should be idle */ - GEM_BUG_ON(port_count(port) == 0 && - !(status & GEN8_CTX_STATUS_ACTIVE_IDLE)); - if (port_count(port) == 0) - execlists_clear_active(execlists, - EXECLISTS_ACTIVE_USER); } if (head != execlists->csb_head) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index a02c7b3b9d55..40461e29cdab 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -638,6 +638,13 @@ execlists_set_active(struct intel_engine_execlists *execlists, __set_bit(bit, (unsigned long *)&execlists->active); } +static inline bool +execlists_set_active_once(struct intel_engine_execlists *execlists, + unsigned int bit) +{ + return !__test_and_set_bit(bit, (unsigned long *)&execlists->active); +} + static inline void execlists_clear_active(struct intel_engine_execlists *execlists, unsigned int bit) @@ -652,6 +659,10 @@ execlists_is_active(const struct intel_engine_execlists *execlists, return test_bit(bit, (unsigned long *)&execlists->active); } +void execlists_user_begin(struct intel_engine_execlists *execlists, + const struct execlist_port *port); +void execlists_user_end(struct intel_engine_execlists *execlists); + void execlists_cancel_port_requests(struct intel_engine_execlists * const execlists); @@ -664,7 +675,7 @@ execlists_num_ports(const struct intel_engine_execlists * const execlists) return execlists->port_mask + 1; } -static inline void +static inline struct execlist_port * execlists_port_complete(struct intel_engine_execlists * const execlists, struct execlist_port * const port) { @@ -675,6 +686,8 @@ execlists_port_complete(struct intel_engine_execlists * const execlists, memmove(port, port + 1, m * sizeof(struct execlist_port)); memset(port + m, 0, sizeof(struct execlist_port)); + + return port; } static inline unsigned int -- cgit v1.2.3 From 2a694feb93556e979793081b5086f26fa8d65156 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 3 Apr 2018 19:35:37 +0100 Subject: drm/i915: Store preemption capability in engine->flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's avoid having to delve down the pointer chain to see if the i915 device has support for preemption and store that on the engine, which made the decision in the first place! v2: Refactor common preemption policy between execlists/guc. Signed-off-by: Chris Wilson Cc: Tomasz Lis Cc: Daniele Ceraolo Spurio Cc: Michał Winiarski Cc: Tvrtko Ursulin Reviewed-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20180403183537.5522-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_guc_submission.c | 16 +++++++++++++--- drivers/gpu/drm/i915/intel_lrc.c | 7 +++++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 18 ++++++++++++++++-- 3 files changed, 34 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 749f27916a02..97121230656c 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -657,6 +657,16 @@ static void port_assign(struct execlist_port *port, struct i915_request *rq) port_set(port, i915_request_get(rq)); } +static inline int rq_prio(const struct i915_request *rq) +{ + return rq->priotree.priority; +} + +static inline int port_prio(const struct execlist_port *port) +{ + return rq_prio(port_request(port)); +} + static void guc_dequeue(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; @@ -672,12 +682,12 @@ static void guc_dequeue(struct intel_engine_cs *engine) GEM_BUG_ON(rb_first(&execlists->queue) != rb); if (port_isset(port)) { - if (engine->i915->preempt_context) { + if (intel_engine_has_preemption(engine)) { struct guc_preempt_work *preempt_work = &engine->i915->guc.preempt_work[engine->id]; + int prio = execlists->queue_priority; - if (execlists->queue_priority > - max(port_request(port)->priotree.priority, 0)) { + if (__execlists_need_preempt(prio, port_prio(port))) { execlists_set_active(execlists, EXECLISTS_ACTIVE_PREEMPT); queue_work(engine->i915->guc.preempt_wq, diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 4d08875422b6..88472845ce96 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -183,7 +183,8 @@ static inline bool need_preempt(const struct intel_engine_cs *engine, const struct i915_request *last, int prio) { - return engine->i915->preempt_context && prio > max(rq_prio(last), 0); + return (intel_engine_has_preemption(engine) && + __execlists_need_preempt(prio, rq_prio(last))); } /** @@ -2117,11 +2118,13 @@ static void execlists_set_default_submission(struct intel_engine_cs *engine) engine->unpark = NULL; engine->flags |= I915_ENGINE_SUPPORTS_STATS; + if (engine->i915->preempt_context) + engine->flags |= I915_ENGINE_HAS_PREEMPTION; engine->i915->caps.scheduler = I915_SCHEDULER_CAP_ENABLED | I915_SCHEDULER_CAP_PRIORITY; - if (engine->i915->preempt_context) + if (intel_engine_has_preemption(engine)) engine->i915->caps.scheduler |= I915_SCHEDULER_CAP_PREEMPTION; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 40461e29cdab..256d58487559 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -562,6 +562,7 @@ struct intel_engine_cs { #define I915_ENGINE_NEEDS_CMD_PARSER BIT(0) #define I915_ENGINE_SUPPORTS_STATS BIT(1) +#define I915_ENGINE_HAS_PREEMPTION BIT(2) unsigned int flags; /* @@ -621,16 +622,29 @@ struct intel_engine_cs { } stats; }; -static inline bool intel_engine_needs_cmd_parser(struct intel_engine_cs *engine) +static inline bool +intel_engine_needs_cmd_parser(const struct intel_engine_cs *engine) { return engine->flags & I915_ENGINE_NEEDS_CMD_PARSER; } -static inline bool intel_engine_supports_stats(struct intel_engine_cs *engine) +static inline bool +intel_engine_supports_stats(const struct intel_engine_cs *engine) { return engine->flags & I915_ENGINE_SUPPORTS_STATS; } +static inline bool +intel_engine_has_preemption(const struct intel_engine_cs *engine) +{ + return engine->flags & I915_ENGINE_HAS_PREEMPTION; +} + +static inline bool __execlists_need_preempt(int prio, int last) +{ + return prio > max(0, last); +} + static inline void execlists_set_active(struct intel_engine_execlists *execlists, unsigned int bit) -- cgit v1.2.3 From 4bfbec68966082f046232a011d6f371e8554bb40 Mon Sep 17 00:00:00 2001 From: Ramalingam C Date: Mon, 2 Apr 2018 17:20:22 +0530 Subject: drm/i915: Read HDCP R0 thrice in case of mismatch As per DP spec when R0 mismatch is detected, HDCP source supported re-read the R0 atleast twice. And For HDMI and DP minimum wait required for the R0 availability is 100mSec. So this patch changes the wait time to 100mSec but retries twice with the time interval of 100mSec for each attempt. This patch is needed for DP HDCP1.4 CTS Test: 1A-06. v2: No Change v3: Comment on R0 retry is moved closer to the code[Seanpaul] v4: Removing unwanted noise introduced in v3. Signed-off-by: Ramalingam C Reviewed-by: Sean Paul Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/1522669822-2508-1-git-send-email-ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_hdcp.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 14ca5d3057a7..f2cf2e3acd3c 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -506,15 +506,26 @@ static int intel_hdcp_auth(struct intel_digital_port *intel_dig_port, */ wait_remaining_ms_from_jiffies(r0_prime_gen_start, 300); - ri.reg = 0; - ret = shim->read_ri_prime(intel_dig_port, ri.shim); - if (ret) - return ret; - I915_WRITE(PORT_HDCP_RPRIME(port), ri.reg); + tries = 3; - /* Wait for Ri prime match */ - if (wait_for(I915_READ(PORT_HDCP_STATUS(port)) & - (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) { + /* + * DP HDCP Spec mandates the two more reattempt to read R0, incase + * of R0 mismatch. + */ + for (i = 0; i < tries; i++) { + ri.reg = 0; + ret = shim->read_ri_prime(intel_dig_port, ri.shim); + if (ret) + return ret; + I915_WRITE(PORT_HDCP_RPRIME(port), ri.reg); + + /* Wait for Ri prime match */ + if (!wait_for(I915_READ(PORT_HDCP_STATUS(port)) & + (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) + break; + } + + if (i == tries) { DRM_ERROR("Timed out waiting for Ri prime match (%x)\n", I915_READ(PORT_HDCP_STATUS(port))); return -ETIMEDOUT; -- cgit v1.2.3 From 41baafae293d617dc89ba320be662afffc5ada6d Mon Sep 17 00:00:00 2001 From: Ramalingam C Date: Mon, 2 Apr 2018 15:40:32 +0530 Subject: drm/i915: Read Vprime thrice incase of mismatch In case of V prime mismatch, DP HDCP spec mandates the re-read of Vprime atleast twice. This patch needed for DP HDCP1.4 CTS Test: 1B-05. v2: Moved the V' validation into a function for retry. [Sean Paul] v3: Removed Inline keyword and DRM_DEBUG_KMS are used [Sean Paul] Signed-off-by: Ramalingam C Reviewed-by: Sean Paul Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/1522663834-24482-3-git-send-email-ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_hdcp.c | 112 ++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index f2cf2e3acd3c..d9dec32c368e 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -142,53 +142,17 @@ bool intel_hdcp_is_ksv_valid(u8 *ksv) return true; } -/* Implements Part 2 of the HDCP authorization procedure */ static -int intel_hdcp_auth_downstream(struct intel_digital_port *intel_dig_port, - const struct intel_hdcp_shim *shim) +int intel_hdcp_validate_v_prime(struct intel_digital_port *intel_dig_port, + const struct intel_hdcp_shim *shim, + u8 *ksv_fifo, u8 num_downstream, u8 *bstatus) { struct drm_i915_private *dev_priv; u32 vprime, sha_text, sha_leftovers, rep_ctl; - u8 bstatus[2], num_downstream, *ksv_fifo; int ret, i, j, sha_idx; dev_priv = intel_dig_port->base.base.dev->dev_private; - ret = intel_hdcp_poll_ksv_fifo(intel_dig_port, shim); - if (ret) { - DRM_ERROR("KSV list failed to become ready (%d)\n", ret); - return ret; - } - - ret = shim->read_bstatus(intel_dig_port, bstatus); - if (ret) - return ret; - - if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) || - DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) { - DRM_ERROR("Max Topology Limit Exceeded\n"); - return -EPERM; - } - - /* - * When repeater reports 0 device count, HDCP1.4 spec allows disabling - * the HDCP encryption. That implies that repeater can't have its own - * display. As there is no consumption of encrypted content in the - * repeater with 0 downstream devices, we are failing the - * authentication. - */ - num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]); - if (num_downstream == 0) - return -EINVAL; - - ksv_fifo = kzalloc(num_downstream * DRM_HDCP_KSV_LEN, GFP_KERNEL); - if (!ksv_fifo) - return -ENOMEM; - - ret = shim->read_ksv_fifo(intel_dig_port, num_downstream, ksv_fifo); - if (ret) - return ret; - /* Process V' values from the receiver */ for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++) { ret = shim->read_v_prime_part(intel_dig_port, i, &vprime); @@ -353,7 +317,8 @@ int intel_hdcp_auth_downstream(struct intel_digital_port *intel_dig_port, return ret; sha_idx += sizeof(sha_text); } else { - DRM_ERROR("Invalid number of leftovers %d\n", sha_leftovers); + DRM_DEBUG_KMS("Invalid number of leftovers %d\n", + sha_leftovers); return -EINVAL; } @@ -381,14 +346,77 @@ int intel_hdcp_auth_downstream(struct intel_digital_port *intel_dig_port, if (intel_wait_for_register(dev_priv, HDCP_REP_CTL, HDCP_SHA1_COMPLETE, HDCP_SHA1_COMPLETE, 1)) { - DRM_ERROR("Timed out waiting for SHA1 complete\n"); + DRM_DEBUG_KMS("Timed out waiting for SHA1 complete\n"); return -ETIMEDOUT; } if (!(I915_READ(HDCP_REP_CTL) & HDCP_SHA1_V_MATCH)) { - DRM_ERROR("SHA-1 mismatch, HDCP failed\n"); + DRM_DEBUG_KMS("SHA-1 mismatch, HDCP failed\n"); return -ENXIO; } + return 0; +} + +/* Implements Part 2 of the HDCP authorization procedure */ +static +int intel_hdcp_auth_downstream(struct intel_digital_port *intel_dig_port, + const struct intel_hdcp_shim *shim) +{ + u8 bstatus[2], num_downstream, *ksv_fifo; + int ret, i, tries = 3; + + ret = intel_hdcp_poll_ksv_fifo(intel_dig_port, shim); + if (ret) { + DRM_ERROR("KSV list failed to become ready (%d)\n", ret); + return ret; + } + + ret = shim->read_bstatus(intel_dig_port, bstatus); + if (ret) + return ret; + + if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) || + DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) { + DRM_ERROR("Max Topology Limit Exceeded\n"); + return -EPERM; + } + + /* + * When repeater reports 0 device count, HDCP1.4 spec allows disabling + * the HDCP encryption. That implies that repeater can't have its own + * display. As there is no consumption of encrypted content in the + * repeater with 0 downstream devices, we are failing the + * authentication. + */ + num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]); + if (num_downstream == 0) + return -EINVAL; + + ksv_fifo = kzalloc(num_downstream * DRM_HDCP_KSV_LEN, GFP_KERNEL); + if (!ksv_fifo) + return -ENOMEM; + + ret = shim->read_ksv_fifo(intel_dig_port, num_downstream, ksv_fifo); + if (ret) + return ret; + + /* + * When V prime mismatches, DP Spec mandates re-read of + * V prime atleast twice. + */ + for (i = 0; i < tries; i++) { + ret = intel_hdcp_validate_v_prime(intel_dig_port, shim, + ksv_fifo, num_downstream, + bstatus); + if (!ret) + break; + } + + if (i == tries) { + DRM_ERROR("V Prime validation failed.(%d)\n", ret); + return ret; + } + DRM_DEBUG_KMS("HDCP is enabled (%d downstream devices)\n", num_downstream); return 0; -- cgit v1.2.3 From 6308a31544284c1f60ab9a3052ee05b7877421ca Mon Sep 17 00:00:00 2001 From: Ramalingam C Date: Mon, 2 Apr 2018 15:40:33 +0530 Subject: drm/i915: Check hdcp key loadability HDCP1.4 key can be loaded, only when Power well #1 is enabled and cdclk is enabled. Using the I915 power well infrastruture, above requirement is verified. This patch enables the hdcp initialization for HSW, BDW, and BXT. v2: Choose the PW# based on the platform. v3: No Changes. Signed-off-by: Ramalingam C Reviewed-by: Sean Paul Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/1522663834-24482-4-git-send-email-ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_hdcp.c | 41 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index d9dec32c368e..98a9c81e2dc1 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -37,6 +37,43 @@ static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *intel_dig_port, return 0; } +static bool hdcp_key_loadable(struct drm_i915_private *dev_priv) +{ + struct i915_power_domains *power_domains = &dev_priv->power_domains; + struct i915_power_well *power_well; + enum i915_power_well_id id; + bool enabled = false; + + /* + * On HSW and BDW, Display HW loads the Key as soon as Display resumes. + * On all BXT+, SW can load the keys only when the PW#1 is turned on. + */ + if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) + id = HSW_DISP_PW_GLOBAL; + else + id = SKL_DISP_PW_1; + + mutex_lock(&power_domains->lock); + + /* PG1 (power well #1) needs to be enabled */ + for_each_power_well(dev_priv, power_well) { + if (power_well->id == id) { + enabled = power_well->ops->is_enabled(dev_priv, + power_well); + break; + } + } + mutex_unlock(&power_domains->lock); + + /* + * Another req for hdcp key loadability is enabled state of pll for + * cdclk. Without active crtc we wont land here. So we are assuming that + * cdclk is already on. + */ + + return enabled; +} + static void intel_hdcp_clear_keys(struct drm_i915_private *dev_priv) { I915_WRITE(HDCP_KEY_CONF, HDCP_CLEAR_KEYS_TRIGGER); @@ -619,8 +656,8 @@ static int _intel_hdcp_enable(struct intel_connector *connector) DRM_DEBUG_KMS("[%s:%d] HDCP is being enabled...\n", connector->base.name, connector->base.base.id); - if (!(I915_READ(SKL_FUSE_STATUS) & SKL_FUSE_PG_DIST_STATUS(1))) { - DRM_ERROR("PG1 is disabled, cannot load keys\n"); + if (!hdcp_key_loadable(dev_priv)) { + DRM_ERROR("HDCP key Load is not possible\n"); return -ENXIO; } -- cgit v1.2.3 From 6be1187dbffa0027ea379c53f7ca0c782515c610 Mon Sep 17 00:00:00 2001 From: Xidong Wang Date: Wed, 4 Apr 2018 10:38:24 +0100 Subject: drm/i915: Do no use kfree() to free a kmem_cache_alloc() return value Along the eb_lookup_vmas() error path, the return value from kmem_cache_alloc() was freed using kfree(). Fix it to use the proper kmem_cache_free() instead. Fixes: d1b48c1e7184 ("drm/i915: Replace execbuf vma ht with an idr") Signed-off-by: Xidong Wang Cc: Chris Wilson Cc: Tvrtko Ursulin Cc: # v4.14+ Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180404093824.9313-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 8c170db8495d..0414228cd2b5 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -728,7 +728,7 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) err = radix_tree_insert(handles_vma, handle, vma); if (unlikely(err)) { - kfree(lut); + kmem_cache_free(eb->i915->luts, lut); goto err_obj; } -- cgit v1.2.3 From 2c66555ec19235efd689741c44bbeb893aa8e7de Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Apr 2018 10:33:29 +0100 Subject: drm/i915/selftests: Add basic sanitychecks for execlists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before adding a new feature to execlists submission, we should endeavour to cover the baseline behaviour with selftests. So start the ball rolling. Signed-off-by: Chris Wilson Cc: Michał Winiarski CC: Michel Thierry Cc: Jeff McGee Cc: Tvrtko Ursulin Cc: Mika Kuoppala Reviewed-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20180404093329.5383-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 4 + .../gpu/drm/i915/selftests/i915_live_selftests.h | 1 + drivers/gpu/drm/i915/selftests/intel_lrc.c | 507 +++++++++++++++++++++ 3 files changed, 512 insertions(+) create mode 100644 drivers/gpu/drm/i915/selftests/intel_lrc.c (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 88472845ce96..3592288e4696 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -2609,3 +2609,7 @@ void intel_lr_context_resume(struct drm_i915_private *dev_priv) } } } + +#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) +#include "selftests/intel_lrc.c" +#endif diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h index 9c76f0305b6a..8bf6aa573226 100644 --- a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h +++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h @@ -20,4 +20,5 @@ selftest(evict, i915_gem_evict_live_selftests) selftest(hugepages, i915_gem_huge_page_live_selftests) selftest(contexts, i915_gem_context_live_selftests) selftest(hangcheck, intel_hangcheck_live_selftests) +selftest(execlists, intel_execlists_live_selftests) selftest(guc, intel_guc_live_selftest) diff --git a/drivers/gpu/drm/i915/selftests/intel_lrc.c b/drivers/gpu/drm/i915/selftests/intel_lrc.c new file mode 100644 index 000000000000..0481e2e01146 --- /dev/null +++ b/drivers/gpu/drm/i915/selftests/intel_lrc.c @@ -0,0 +1,507 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright © 2018 Intel Corporation + */ + +#include "../i915_selftest.h" + +#include "mock_context.h" + +struct spinner { + struct drm_i915_private *i915; + struct drm_i915_gem_object *hws; + struct drm_i915_gem_object *obj; + u32 *batch; + void *seqno; +}; + +static int spinner_init(struct spinner *spin, struct drm_i915_private *i915) +{ + unsigned int mode; + void *vaddr; + int err; + + GEM_BUG_ON(INTEL_GEN(i915) < 8); + + memset(spin, 0, sizeof(*spin)); + spin->i915 = i915; + + spin->hws = i915_gem_object_create_internal(i915, PAGE_SIZE); + if (IS_ERR(spin->hws)) { + err = PTR_ERR(spin->hws); + goto err; + } + + spin->obj = i915_gem_object_create_internal(i915, PAGE_SIZE); + if (IS_ERR(spin->obj)) { + err = PTR_ERR(spin->obj); + goto err_hws; + } + + i915_gem_object_set_cache_level(spin->hws, I915_CACHE_LLC); + vaddr = i915_gem_object_pin_map(spin->hws, I915_MAP_WB); + if (IS_ERR(vaddr)) { + err = PTR_ERR(vaddr); + goto err_obj; + } + spin->seqno = memset(vaddr, 0xff, PAGE_SIZE); + + mode = HAS_LLC(i915) ? I915_MAP_WB : I915_MAP_WC; + vaddr = i915_gem_object_pin_map(spin->obj, mode); + if (IS_ERR(vaddr)) { + err = PTR_ERR(vaddr); + goto err_unpin_hws; + } + spin->batch = vaddr; + + return 0; + +err_unpin_hws: + i915_gem_object_unpin_map(spin->hws); +err_obj: + i915_gem_object_put(spin->obj); +err_hws: + i915_gem_object_put(spin->hws); +err: + return err; +} + +static unsigned int seqno_offset(u64 fence) +{ + return offset_in_page(sizeof(u32) * fence); +} + +static u64 hws_address(const struct i915_vma *hws, + const struct i915_request *rq) +{ + return hws->node.start + seqno_offset(rq->fence.context); +} + +static int emit_recurse_batch(struct spinner *spin, + struct i915_request *rq, + u32 arbitration_command) +{ + struct i915_address_space *vm = &rq->ctx->ppgtt->base; + struct i915_vma *hws, *vma; + u32 *batch; + int err; + + vma = i915_vma_instance(spin->obj, vm, NULL); + if (IS_ERR(vma)) + return PTR_ERR(vma); + + hws = i915_vma_instance(spin->hws, vm, NULL); + if (IS_ERR(hws)) + return PTR_ERR(hws); + + err = i915_vma_pin(vma, 0, 0, PIN_USER); + if (err) + return err; + + err = i915_vma_pin(hws, 0, 0, PIN_USER); + if (err) + goto unpin_vma; + + i915_vma_move_to_active(vma, rq, 0); + if (!i915_gem_object_has_active_reference(vma->obj)) { + i915_gem_object_get(vma->obj); + i915_gem_object_set_active_reference(vma->obj); + } + + i915_vma_move_to_active(hws, rq, 0); + if (!i915_gem_object_has_active_reference(hws->obj)) { + i915_gem_object_get(hws->obj); + i915_gem_object_set_active_reference(hws->obj); + } + + batch = spin->batch; + + *batch++ = MI_STORE_DWORD_IMM_GEN4; + *batch++ = lower_32_bits(hws_address(hws, rq)); + *batch++ = upper_32_bits(hws_address(hws, rq)); + *batch++ = rq->fence.seqno; + + *batch++ = arbitration_command; + + *batch++ = MI_BATCH_BUFFER_START | 1 << 8 | 1; + *batch++ = lower_32_bits(vma->node.start); + *batch++ = upper_32_bits(vma->node.start); + *batch++ = MI_BATCH_BUFFER_END; /* not reached */ + + i915_gem_chipset_flush(spin->i915); + + err = rq->engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, 0); + + i915_vma_unpin(hws); +unpin_vma: + i915_vma_unpin(vma); + return err; +} + +static struct i915_request * +spinner_create_request(struct spinner *spin, + struct i915_gem_context *ctx, + struct intel_engine_cs *engine, + u32 arbitration_command) +{ + struct i915_request *rq; + int err; + + rq = i915_request_alloc(engine, ctx); + if (IS_ERR(rq)) + return rq; + + err = emit_recurse_batch(spin, rq, arbitration_command); + if (err) { + __i915_request_add(rq, false); + return ERR_PTR(err); + } + + return rq; +} + +static u32 hws_seqno(const struct spinner *spin, const struct i915_request *rq) +{ + u32 *seqno = spin->seqno + seqno_offset(rq->fence.context); + + return READ_ONCE(*seqno); +} + +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); + + GEM_TRACE("%pS timed out.\n", w->symbol); + GEM_TRACE_DUMP(); + + 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 spinner_end(struct spinner *spin) +{ + *spin->batch = MI_BATCH_BUFFER_END; + i915_gem_chipset_flush(spin->i915); +} + +static void spinner_fini(struct spinner *spin) +{ + spinner_end(spin); + + i915_gem_object_unpin_map(spin->obj); + i915_gem_object_put(spin->obj); + + i915_gem_object_unpin_map(spin->hws); + i915_gem_object_put(spin->hws); +} + +static bool wait_for_spinner(struct spinner *spin, struct i915_request *rq) +{ + if (!wait_event_timeout(rq->execute, + READ_ONCE(rq->global_seqno), + msecs_to_jiffies(10))) + return false; + + return !(wait_for_us(i915_seqno_passed(hws_seqno(spin, rq), + rq->fence.seqno), + 10) && + wait_for(i915_seqno_passed(hws_seqno(spin, rq), + rq->fence.seqno), + 1000)); +} + +static int live_sanitycheck(void *arg) +{ + struct drm_i915_private *i915 = arg; + struct intel_engine_cs *engine; + struct i915_gem_context *ctx; + enum intel_engine_id id; + struct spinner spin; + int err = -ENOMEM; + + if (!HAS_LOGICAL_RING_CONTEXTS(i915)) + return 0; + + mutex_lock(&i915->drm.struct_mutex); + + if (spinner_init(&spin, i915)) + goto err_unlock; + + ctx = kernel_context(i915); + if (!ctx) + goto err_spin; + + for_each_engine(engine, i915, id) { + struct i915_request *rq; + + rq = spinner_create_request(&spin, ctx, engine, MI_NOOP); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + goto err_ctx; + } + + i915_request_add(rq); + if (!wait_for_spinner(&spin, rq)) { + GEM_TRACE("spinner failed to start\n"); + GEM_TRACE_DUMP(); + i915_gem_set_wedged(i915); + err = -EIO; + goto err_ctx; + } + + spinner_end(&spin); + if (flush_test(i915, I915_WAIT_LOCKED)) { + err = -EIO; + goto err_ctx; + } + } + + err = 0; +err_ctx: + kernel_context_close(ctx); +err_spin: + spinner_fini(&spin); +err_unlock: + flush_test(i915, I915_WAIT_LOCKED); + mutex_unlock(&i915->drm.struct_mutex); + return err; +} + +static int live_preempt(void *arg) +{ + struct drm_i915_private *i915 = arg; + struct i915_gem_context *ctx_hi, *ctx_lo; + struct spinner spin_hi, spin_lo; + struct intel_engine_cs *engine; + enum intel_engine_id id; + int err = -ENOMEM; + + if (!HAS_LOGICAL_RING_PREEMPTION(i915)) + return 0; + + mutex_lock(&i915->drm.struct_mutex); + + if (spinner_init(&spin_hi, i915)) + goto err_unlock; + + if (spinner_init(&spin_lo, i915)) + goto err_spin_hi; + + ctx_hi = kernel_context(i915); + if (!ctx_hi) + goto err_spin_lo; + ctx_hi->priority = I915_CONTEXT_MAX_USER_PRIORITY; + + ctx_lo = kernel_context(i915); + if (!ctx_lo) + goto err_ctx_hi; + ctx_lo->priority = I915_CONTEXT_MIN_USER_PRIORITY; + + for_each_engine(engine, i915, id) { + struct i915_request *rq; + + rq = spinner_create_request(&spin_lo, ctx_lo, engine, + MI_ARB_CHECK); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + goto err_ctx_lo; + } + + i915_request_add(rq); + if (!wait_for_spinner(&spin_lo, rq)) { + GEM_TRACE("lo spinner failed to start\n"); + GEM_TRACE_DUMP(); + i915_gem_set_wedged(i915); + err = -EIO; + goto err_ctx_lo; + } + + rq = spinner_create_request(&spin_hi, ctx_hi, engine, + MI_ARB_CHECK); + if (IS_ERR(rq)) { + spinner_end(&spin_lo); + err = PTR_ERR(rq); + goto err_ctx_lo; + } + + i915_request_add(rq); + if (!wait_for_spinner(&spin_hi, rq)) { + GEM_TRACE("hi spinner failed to start\n"); + GEM_TRACE_DUMP(); + i915_gem_set_wedged(i915); + err = -EIO; + goto err_ctx_lo; + } + + spinner_end(&spin_hi); + spinner_end(&spin_lo); + if (flush_test(i915, I915_WAIT_LOCKED)) { + err = -EIO; + goto err_ctx_lo; + } + } + + err = 0; +err_ctx_lo: + kernel_context_close(ctx_lo); +err_ctx_hi: + kernel_context_close(ctx_hi); +err_spin_lo: + spinner_fini(&spin_lo); +err_spin_hi: + spinner_fini(&spin_hi); +err_unlock: + flush_test(i915, I915_WAIT_LOCKED); + mutex_unlock(&i915->drm.struct_mutex); + return err; +} + +static int live_late_preempt(void *arg) +{ + struct drm_i915_private *i915 = arg; + struct i915_gem_context *ctx_hi, *ctx_lo; + struct spinner spin_hi, spin_lo; + struct intel_engine_cs *engine; + enum intel_engine_id id; + int err = -ENOMEM; + + if (!HAS_LOGICAL_RING_PREEMPTION(i915)) + return 0; + + mutex_lock(&i915->drm.struct_mutex); + + if (spinner_init(&spin_hi, i915)) + goto err_unlock; + + if (spinner_init(&spin_lo, i915)) + goto err_spin_hi; + + ctx_hi = kernel_context(i915); + if (!ctx_hi) + goto err_spin_lo; + + ctx_lo = kernel_context(i915); + if (!ctx_lo) + goto err_ctx_hi; + + for_each_engine(engine, i915, id) { + struct i915_request *rq; + + rq = spinner_create_request(&spin_lo, ctx_lo, engine, + MI_ARB_CHECK); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + goto err_ctx_lo; + } + + i915_request_add(rq); + if (!wait_for_spinner(&spin_lo, rq)) { + pr_err("First context failed to start\n"); + goto err_wedged; + } + + rq = spinner_create_request(&spin_hi, ctx_hi, engine, MI_NOOP); + if (IS_ERR(rq)) { + spinner_end(&spin_lo); + err = PTR_ERR(rq); + goto err_ctx_lo; + } + + i915_request_add(rq); + if (wait_for_spinner(&spin_hi, rq)) { + pr_err("Second context overtook first?\n"); + goto err_wedged; + } + + engine->schedule(rq, I915_PRIORITY_MAX); + + if (!wait_for_spinner(&spin_hi, rq)) { + pr_err("High priority context failed to preempt the low priority context\n"); + GEM_TRACE_DUMP(); + goto err_wedged; + } + + spinner_end(&spin_hi); + spinner_end(&spin_lo); + if (flush_test(i915, I915_WAIT_LOCKED)) { + err = -EIO; + goto err_ctx_lo; + } + } + + err = 0; +err_ctx_lo: + kernel_context_close(ctx_lo); +err_ctx_hi: + kernel_context_close(ctx_hi); +err_spin_lo: + spinner_fini(&spin_lo); +err_spin_hi: + spinner_fini(&spin_hi); +err_unlock: + flush_test(i915, I915_WAIT_LOCKED); + mutex_unlock(&i915->drm.struct_mutex); + return err; + +err_wedged: + spinner_end(&spin_hi); + spinner_end(&spin_lo); + i915_gem_set_wedged(i915); + err = -EIO; + goto err_ctx_lo; +} + +int intel_execlists_live_selftests(struct drm_i915_private *i915) +{ + static const struct i915_subtest tests[] = { + SUBTEST(live_sanitycheck), + SUBTEST(live_preempt), + SUBTEST(live_late_preempt), + }; + return i915_subtests(tests, i915); +} -- cgit v1.2.3 From 40da1d310e8a155a09cd64b5b3fd3548a9dcfda0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 5 Apr 2018 13:37:14 +0100 Subject: drm/i915: Only call finish_reset after a prepare_reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we skip the intel_prepare_reset(), we should also skip the intel_display_reset(). If we we use a flag set by intel_prepare_reset() then we do not have to second guess based on external user controlled state whether or not the prepare was called before deciding to finish it after the reset. igt/gem_eio is one such example that may tweak i915.reset faster than the code is expecting, leading to [ 190.233528] ===================================== [ 190.233534] WARNING: bad unlock balance detected! [ 190.233540] 4.16.0-rc7-g335ef9849310-drmtip_10+ #1 Tainted: G U [ 190.233547] ------------------------------------- [ 190.233553] gem_eio/1348 is trying to release lock (crtc_ww_class_acquire) at: [ 190.233569] [] drm_modeset_acquire_fini+0x0/0x60 [ 190.233575] but there are no more locks to release! [ 190.233580] other info that might help us debug this: [ 190.233588] 3 locks held by gem_eio/1348: [ 190.233592] #0: (&f->f_pos_lock){+.+.}, at: [<00000000ab90c784>] __fdget_pos+0x3a/0x50 [ 190.233607] #1: (sb_writers#11){.+.+}, at: [<00000000e1529265>] vfs_write+0x188/0x1a0 [ 190.233622] #2: (&attr->mutex){+.+.}, at: [<0000000011f40afe>] simple_attr_write+0x36/0xd0 [ 190.233635] stack backtrace: [ 190.233644] CPU: 0 PID: 1348 Comm: gem_eio Tainted: G U 4.16.0-rc7-g335ef9849310-drmtip_10+ #1 [ 190.233655] Hardware name: Dell Inc. OptiPlex GX280 /0G8310, BIOS A04 02/09/2005 [ 190.233664] Call Trace: [ 190.233674] dump_stack+0x67/0x95 [ 190.233682] ? drm_modeset_backoff+0x1b0/0x1b0 [ 190.233690] print_unlock_imbalance_bug+0xd2/0xe0 [ 190.233698] ? drm_modeset_backoff+0x1b0/0x1b0 [ 190.233704] lock_release+0x23e/0x300 [ 190.233712] drm_modeset_acquire_fini+0x16/0x60 [ 190.233835] intel_finish_reset+0x72/0x160 [i915] [ 190.233894] i915_reset_device+0x1e9/0x240 [i915] [ 190.233953] ? __intel_get_crtc_scanline+0x1c0/0x1c0 [i915] [ 190.233962] ? work_on_cpu_safe+0x50/0x50 [ 190.234020] i915_handle_error+0x1f2/0x470 [i915] [ 190.234031] ? __might_fault+0x39/0x90 [ 190.234037] ? __might_fault+0x39/0x90 [ 190.234099] i915_wedged_set+0x7f/0xc0 [i915] [ 190.234107] simple_attr_write+0xb0/0xd0 [ 190.234117] full_proxy_write+0x51/0x80 [ 190.234125] __vfs_write+0x21/0x140 [ 190.234133] ? rcu_read_lock_sched_held+0x6f/0x80 [ 190.234140] ? rcu_sync_lockdep_assert+0x29/0x50 [ 190.234147] ? __sb_start_write+0x152/0x1f0 [ 190.234152] ? __sb_start_write+0x168/0x1f0 [ 190.234159] vfs_write+0xbd/0x1a0 [ 190.234166] SyS_write+0x40/0xa0 [ 190.234173] ? do_syscall_64+0x19/0x1b0 [ 190.234180] do_syscall_64+0x6b/0x1b0 [ 190.234188] entry_SYSCALL_64_after_hwframe+0x42/0xb7 [ 190.234196] RIP: 0033:0x7f84c1b392b7 [ 190.234201] RSP: 002b:00007f84b6755b00 EFLAGS: 00000293 ORIG_RAX: 0000000000000001 [ 190.234211] RAX: ffffffffffffffda RBX: 0000000000000046 RCX: 00007f84c1b392b7 [ 190.234218] RDX: 0000000000000002 RSI: 000055ec20abc8d6 RDI: 0000000000000046 [ 190.234225] RBP: 000055ec20abc8d6 R08: 0000000000000000 R09: 0000000000000000 [ 190.234231] R10: 0000000000000000 R11: 0000000000000293 R12: 0000000000000002 [ 190.234238] R13: 0000000000000000 R14: 00007f84b0000b20 R15: 000055ec20ce4eb8 Testcase: igt/gem_eio Signed-off-by: Chris Wilson Cc: Ville Syrjälä Cc: Maarten Lankhorst Reviewed-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20180405123714.3638-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_display.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3acd75753a31..6de2e1b1a4a7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3677,7 +3677,6 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv) struct drm_atomic_state *state; int ret; - /* reset doesn't touch the display */ if (!i915_modparams.force_reset_modeset_test && !gpu_reset_clobbers_display(dev_priv)) @@ -3731,19 +3730,17 @@ void intel_finish_reset(struct drm_i915_private *dev_priv) { struct drm_device *dev = &dev_priv->drm; struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx; - struct drm_atomic_state *state = dev_priv->modeset_restore_state; + struct drm_atomic_state *state; int ret; /* reset doesn't touch the display */ - if (!i915_modparams.force_reset_modeset_test && - !gpu_reset_clobbers_display(dev_priv)) + if (!test_bit(I915_RESET_MODESET, &dev_priv->gpu_error.flags)) return; + state = fetch_and_zero(&dev_priv->modeset_restore_state); if (!state) goto unlock; - dev_priv->modeset_restore_state = NULL; - /* reset doesn't touch the display */ if (!gpu_reset_clobbers_display(dev_priv)) { /* for testing only restore the display */ -- cgit v1.2.3 From 46a67c4d16ec86ca84a93f7dc92c54138e38a129 Mon Sep 17 00:00:00 2001 From: Radhakrishna Sripada Date: Wed, 4 Apr 2018 15:59:57 -0700 Subject: drm/i915: Fix memory leak in intel_hdcp auth Static code analysis tool reported memory leak in intel_hdcp_auth_downstream. Fixing the memory leak. v2: Rebase, move free to a cleanup label(Jani) Cc: Jani Nikula Cc: Anusha Srivatsa Signed-off-by: Radhakrishna Sripada Reviewed-by: Anusha Srivatsa Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180404225957.7457-1-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/intel_hdcp.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 98a9c81e2dc1..2db5da550a1c 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -435,7 +435,7 @@ int intel_hdcp_auth_downstream(struct intel_digital_port *intel_dig_port, ret = shim->read_ksv_fifo(intel_dig_port, num_downstream, ksv_fifo); if (ret) - return ret; + goto err; /* * When V prime mismatches, DP Spec mandates re-read of @@ -451,12 +451,15 @@ int intel_hdcp_auth_downstream(struct intel_digital_port *intel_dig_port, if (i == tries) { DRM_ERROR("V Prime validation failed.(%d)\n", ret); - return ret; + goto err; } DRM_DEBUG_KMS("HDCP is enabled (%d downstream devices)\n", num_downstream); - return 0; + ret = 0; +err: + kfree(ksv_fifo); + return ret; } /* Implements Part 1 of the HDCP authorization procedure */ -- cgit v1.2.3 From b651bd2a3ae33f6a98d6ea36ef2518f5211bdc4f Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Thu, 5 Apr 2018 22:12:24 +0530 Subject: drm/i915/audio: Fix audio enumeration issue on BXT On Apollolake, with stress test warm reboot, audio card was not getting enumerated after reboot. This was a spurious issue happening on Apollolake. HW codec and HD audio controller link was going out of sync for which there was a fix in i915 driver but was not getting invoked for BXT. Extending this fix to BXT as well. Tested on apollolake chromebook by stress test warm reboot with 2500 iterations. Bspec: 21829 Signed-off-by: Gaurav K Singh Reviewed-by: Dhinakaran Pandiyan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/1522946544-11524-1-git-send-email-gaurav.k.singh@intel.com --- drivers/gpu/drm/i915/intel_audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 709d6ca68074..656f6c931341 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -729,7 +729,7 @@ static void i915_audio_component_codec_wake_override(struct device *kdev, struct drm_i915_private *dev_priv = kdev_to_i915(kdev); u32 tmp; - if (!IS_GEN9_BC(dev_priv)) + if (!IS_GEN9_BC(dev_priv) && !IS_BROXTON(dev_priv)) return; i915_audio_component_get_power(kdev); -- cgit v1.2.3 From 028666793a0291b63eb61bae7252345821326a1b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 30 Mar 2018 14:18:01 +0100 Subject: drm/i915/selftests: Avoid repeatedly harming the same innocent context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't handle resetting the kernel context very well, or presumably any context executing its breadcrumb commands in the ring as opposed to the batchbuffer and flush. If we trigger a device reset twice in quick succession while the kernel context is executing, we may end up skipping the breadcrumb. This is really only a problem for the selftest as normally there is a large interlude between resets (hangcheck), or we focus on resetting just one engine and so avoid repeatedly resetting innocents. Something to try would be a preempt-to-idle to quiesce the engine before reset, so that innocent contexts would be spared the reset. Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Michał Winiarski CC: Michel Thierry Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180330131801.18327-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.c | 3 ++ drivers/gpu/drm/i915/selftests/intel_hangcheck.c | 48 ++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index d354627882e3..684060ed8db6 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1886,6 +1886,8 @@ void i915_reset(struct drm_i915_private *i915) int ret; int i; + GEM_TRACE("flags=%lx\n", error->flags); + might_sleep(); lockdep_assert_held(&i915->drm.struct_mutex); GEM_BUG_ON(!test_bit(I915_RESET_BACKOFF, &error->flags)); @@ -2016,6 +2018,7 @@ int i915_reset_engine(struct intel_engine_cs *engine, const char *msg) struct i915_request *active_request; int ret; + GEM_TRACE("%s flags=%lx\n", engine->name, error->flags); GEM_BUG_ON(!test_bit(I915_RESET_ENGINE + engine->id, &error->flags)); active_request = i915_gem_reset_prepare_engine(engine); diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 9e4e0ad62724..d03abe7f8a53 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -979,6 +979,23 @@ unlock: return err; } +static int wait_for_others(struct drm_i915_private *i915, + struct intel_engine_cs *exclude) +{ + struct intel_engine_cs *engine; + enum intel_engine_id id; + + for_each_engine(engine, i915, id) { + if (engine == exclude) + continue; + + if (wait_for(intel_engine_is_idle(engine), 10)) + return -EIO; + } + + return 0; +} + static int igt_reset_queue(void *arg) { struct drm_i915_private *i915 = arg; @@ -1027,13 +1044,36 @@ static int igt_reset_queue(void *arg) i915_request_get(rq); __i915_request_add(rq, true); + /* + * XXX We don't handle resetting the kernel context + * very well. If we trigger a device reset twice in + * quick succession while the kernel context is + * executing, we may end up skipping the breadcrumb. + * This is really only a problem for the selftest as + * normally there is a large interlude between resets + * (hangcheck), or we focus on resetting just one + * engine and so avoid repeatedly resetting innocents. + */ + err = wait_for_others(i915, engine); + if (err) { + pr_err("%s(%s): Failed to idle other inactive engines after device reset\n", + __func__, engine->name); + i915_request_put(rq); + i915_request_put(prev); + + GEM_TRACE_DUMP(); + i915_gem_set_wedged(i915); + goto fini; + } + if (!wait_for_hang(&h, prev)) { struct drm_printer p = drm_info_printer(i915->drm.dev); - pr_err("%s: Failed to start request %x, at %x\n", - __func__, prev->fence.seqno, hws_seqno(&h, prev)); - intel_engine_dump(prev->engine, &p, - "%s\n", prev->engine->name); + pr_err("%s(%s): Failed to start request %x, at %x\n", + __func__, engine->name, + prev->fence.seqno, hws_seqno(&h, prev)); + intel_engine_dump(engine, &p, + "%s\n", engine->name); i915_request_put(rq); i915_request_put(prev); -- cgit v1.2.3 From 99d7e4eeea778374ecea279d0379fbecb0b297bf Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Fri, 6 Apr 2018 11:05:57 +0300 Subject: drm/i915: Describe the bottom of stack in processing a batchbuffer Now that "DOC: User command execution" of i915_gem_execbuffer.c is included in the i915.rst, it is benecifial (for new developers) to read what happens at the bottom of the driver stack (in terms of bytes written to be read by the GPU) when processing a user-space batchbuffer. v5: Typo correction of lacking double tick. Signed-off-by: Kevin Rogovin Reviewed-by: Joonas Lahtinen [Joonas: correcting the patch title] Signed-off-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/1523001957-6427-4-git-send-email-kevin.rogovin@intel.com --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 0414228cd2b5..c74f5df3fb5a 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -81,6 +81,35 @@ enum { * but this remains just a hint as the kernel may choose a new location for * any object in the future. * + * At the level of talking to the hardware, submitting a batchbuffer for the + * GPU to execute is to add content to a buffer from which the HW + * command streamer is reading. + * + * 1. Add a command to load the HW context. For Logical Ring Contexts, i.e. + * Execlists, this command is not placed on the same buffer as the + * remaining items. + * + * 2. Add a command to invalidate caches to the buffer. + * + * 3. Add a batchbuffer start command to the buffer; the start command is + * essentially a token together with the GPU address of the batchbuffer + * to be executed. + * + * 4. Add a pipeline flush to the buffer. + * + * 5. Add a memory write command to the buffer to record when the GPU + * is done executing the batchbuffer. The memory write writes the + * global sequence number of the request, ``i915_request::global_seqno``; + * the i915 driver uses the current value in the register to determine + * if the GPU has completed the batchbuffer. + * + * 6. Add a user interrupt command to the buffer. This command instructs + * the GPU to issue an interrupt when the command, pipeline flush and + * memory write are completed. + * + * 7. Inform the hardware of the additional commands added to the buffer + * (by updating the tail pointer). + * * Processing an execbuf ioctl is conceptually split up into a few phases. * * 1. Validation - Ensure all the pointers, handles and flags are valid. -- cgit v1.2.3 From e34b0345e6a531f980a6560fdc3b651de9cfcc67 Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Thu, 5 Apr 2018 17:00:48 +0300 Subject: drm/i915/icl: Add reset control register changes The bits used to reset the different engines/domains have changed in GEN11, this patch maps the reset engine mask bits with the new bits in the reset control register. v2: Use shift-left instead of BIT macro to match the file style (Paulo). v3: Reuse gen8_reset_engines (Daniele). v4: Do not call intel_uncore_forcewake_reset after reset, we may be using the forcewake to read protected registers elsewhere and those results may be clobbered by the concurrent dropping of forcewake. bspec: 19212 Cc: Oscar Mateo Cc: Antonio Argenziano Cc: Paulo Zanoni Cc: Daniele Ceraolo Spurio Acked-by: Daniele Ceraolo Spurio Signed-off-by: Michel Thierry Reviewed-by: Oscar Mateo Signed-off-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180405140052.10682-1-mika.kuoppala@linux.intel.com --- drivers/gpu/drm/i915/i915_reg.h | 11 ++++++++ drivers/gpu/drm/i915/intel_uncore.c | 53 +++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 176dca6554f4..b2a2d8fbbc68 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -301,6 +301,17 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define GEN6_GRDOM_VECS (1 << 4) #define GEN9_GRDOM_GUC (1 << 5) #define GEN8_GRDOM_MEDIA2 (1 << 7) +/* GEN11 changed all bit defs except for FULL & RENDER */ +#define GEN11_GRDOM_FULL GEN6_GRDOM_FULL +#define GEN11_GRDOM_RENDER GEN6_GRDOM_RENDER +#define GEN11_GRDOM_BLT (1 << 2) +#define GEN11_GRDOM_GUC (1 << 3) +#define GEN11_GRDOM_MEDIA (1 << 5) +#define GEN11_GRDOM_MEDIA2 (1 << 6) +#define GEN11_GRDOM_MEDIA3 (1 << 7) +#define GEN11_GRDOM_MEDIA4 (1 << 8) +#define GEN11_GRDOM_VECS (1 << 13) +#define GEN11_GRDOM_VECS2 (1 << 14) #define RING_PP_DIR_BASE(engine) _MMIO((engine)->mmio_base+0x228) #define RING_PP_DIR_BASE_READ(engine) _MMIO((engine)->mmio_base+0x518) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index e7540bb9786c..d6e20f0f4c28 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1909,6 +1909,50 @@ static int gen6_reset_engines(struct drm_i915_private *dev_priv, return gen6_hw_domain_reset(dev_priv, hw_mask); } +/** + * gen11_reset_engines - reset individual engines + * @dev_priv: i915 device + * @engine_mask: mask of intel_ring_flag() engines or ALL_ENGINES for full reset + * + * This function will reset the individual engines that are set in engine_mask. + * If you provide ALL_ENGINES as mask, full global domain reset will be issued. + * + * Note: It is responsibility of the caller to handle the difference between + * asking full domain reset versus reset for all available individual engines. + * + * Returns 0 on success, nonzero on error. + */ +static int gen11_reset_engines(struct drm_i915_private *dev_priv, + unsigned engine_mask) +{ + struct intel_engine_cs *engine; + const u32 hw_engine_mask[I915_NUM_ENGINES] = { + [RCS] = GEN11_GRDOM_RENDER, + [BCS] = GEN11_GRDOM_BLT, + [VCS] = GEN11_GRDOM_MEDIA, + [VCS2] = GEN11_GRDOM_MEDIA2, + [VCS3] = GEN11_GRDOM_MEDIA3, + [VCS4] = GEN11_GRDOM_MEDIA4, + [VECS] = GEN11_GRDOM_VECS, + [VECS2] = GEN11_GRDOM_VECS2, + }; + u32 hw_mask; + + BUILD_BUG_ON(VECS2 + 1 != I915_NUM_ENGINES); + + if (engine_mask == ALL_ENGINES) { + hw_mask = GEN11_GRDOM_FULL; + } else { + unsigned int tmp; + + hw_mask = 0; + for_each_engine_masked(engine, dev_priv, engine_mask, tmp) + hw_mask |= hw_engine_mask[engine->id]; + } + + return gen6_hw_domain_reset(dev_priv, hw_mask); +} + /** * __intel_wait_for_register_fw - wait until register matches expected state * @dev_priv: the i915 device @@ -2057,7 +2101,10 @@ static int gen8_reset_engines(struct drm_i915_private *dev_priv, if (gen8_reset_engine_start(engine)) goto not_ready; - return gen6_reset_engines(dev_priv, engine_mask); + if (INTEL_GEN(dev_priv) >= 11) + return gen11_reset_engines(dev_priv, engine_mask); + else + return gen6_reset_engines(dev_priv, engine_mask); not_ready: for_each_engine_masked(engine, dev_priv, engine_mask, tmp) @@ -2160,12 +2207,14 @@ bool intel_has_reset_engine(struct drm_i915_private *dev_priv) int intel_reset_guc(struct drm_i915_private *dev_priv) { + u32 guc_domain = INTEL_GEN(dev_priv) >= 11 ? GEN11_GRDOM_GUC : + GEN9_GRDOM_GUC; int ret; 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); + ret = gen6_hw_domain_reset(dev_priv, guc_domain); intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); return ret; -- cgit v1.2.3 From f744dbc2a64d5de0d9b3f883b536c007b1e98fab Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 6 Apr 2018 12:31:45 +0300 Subject: drm/i915/icl: Use hw engine class, instance to find irq handler Interrupt identity register we already read from hardware contains engine class and instance fields. Leverage these fields to find correct engine to handle the interrupt. v3: rebase on top of rps intr use correct class / instance limits (Michel) v4: split engine/other handling v5: empty iir is not err (Daniele, Michel) Suggested-by: Daniele Ceraolo Spurio Cc: Daniele Ceraolo Spurio Cc: Chris Wilson Cc: Tvrtko Ursulin Cc: Michel Thierry Signed-off-by: Mika Kuoppala Reviewed-by: Daniele Ceraolo Spurio Reviewed-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180406093145.14389-1-mika.kuoppala@linux.intel.com --- drivers/gpu/drm/i915/i915_irq.c | 99 ++++++++++++++++++++++------------------- drivers/gpu/drm/i915/i915_reg.h | 4 +- 2 files changed, 56 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 27aee25429b7..45f72a0ece04 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2732,47 +2732,9 @@ static void __fini_wedge(struct wedge_me *w) (W)->i915; \ __fini_wedge((W))) -static void -gen11_gt_engine_irq_handler(struct drm_i915_private * const i915, - const unsigned int bank, - const unsigned int engine_n, - const u16 iir) -{ - struct intel_engine_cs ** const engine = i915->engine; - - switch (bank) { - case 0: - switch (engine_n) { - - case GEN11_RCS0: - return gen8_cs_irq_handler(engine[RCS], iir); - - case GEN11_BCS: - return gen8_cs_irq_handler(engine[BCS], iir); - } - case 1: - switch (engine_n) { - - case GEN11_VCS(0): - return gen8_cs_irq_handler(engine[_VCS(0)], iir); - case GEN11_VCS(1): - return gen8_cs_irq_handler(engine[_VCS(1)], iir); - case GEN11_VCS(2): - return gen8_cs_irq_handler(engine[_VCS(2)], iir); - case GEN11_VCS(3): - return gen8_cs_irq_handler(engine[_VCS(3)], iir); - - case GEN11_VECS(0): - return gen8_cs_irq_handler(engine[_VECS(0)], iir); - case GEN11_VECS(1): - return gen8_cs_irq_handler(engine[_VECS(1)], iir); - } - } -} - static u32 -gen11_gt_engine_intr(struct drm_i915_private * const i915, - const unsigned int bank, const unsigned int bit) +gen11_gt_engine_identity(struct drm_i915_private * const i915, + const unsigned int bank, const unsigned int bit) { void __iomem * const regs = i915->regs; u32 timeout_ts; @@ -2799,7 +2761,54 @@ gen11_gt_engine_intr(struct drm_i915_private * const i915, raw_reg_write(regs, GEN11_INTR_IDENTITY_REG(bank), GEN11_INTR_DATA_VALID); - return ident & GEN11_INTR_ENGINE_MASK; + return ident; +} + +static void +gen11_other_irq_handler(struct drm_i915_private * const i915, + const u8 instance, const u16 iir) +{ + WARN_ONCE(1, "unhandled other interrupt instance=0x%x, iir=0x%x\n", + instance, iir); +} + +static void +gen11_engine_irq_handler(struct drm_i915_private * const i915, + const u8 class, const u8 instance, const u16 iir) +{ + struct intel_engine_cs *engine; + + if (instance <= MAX_ENGINE_INSTANCE) + engine = i915->engine_class[class][instance]; + else + engine = NULL; + + if (likely(engine)) + return gen8_cs_irq_handler(engine, iir); + + WARN_ONCE(1, "unhandled engine interrupt class=0x%x, instance=0x%x\n", + class, instance); +} + +static void +gen11_gt_identity_handler(struct drm_i915_private * const i915, + const u32 identity) +{ + const u8 class = GEN11_INTR_ENGINE_CLASS(identity); + const u8 instance = GEN11_INTR_ENGINE_INSTANCE(identity); + const u16 intr = GEN11_INTR_ENGINE_INTR(identity); + + if (unlikely(!intr)) + return; + + if (class <= COPY_ENGINE_CLASS) + return gen11_engine_irq_handler(i915, class, instance, intr); + + if (class == OTHER_CLASS) + return gen11_other_irq_handler(i915, instance, intr); + + WARN_ONCE(1, "unknown interrupt class=0x%x, instance=0x%x, intr=0x%x\n", + class, instance, intr); } static void @@ -2824,12 +2833,10 @@ gen11_gt_irq_handler(struct drm_i915_private * const i915, } for_each_set_bit(bit, &intr_dw, 32) { - const u16 iir = gen11_gt_engine_intr(i915, bank, bit); - - if (unlikely(!iir)) - continue; + const u32 ident = gen11_gt_engine_identity(i915, + bank, bit); - gen11_gt_engine_irq_handler(i915, bank, bit, iir); + gen11_gt_identity_handler(i915, ident); } /* Clear must be after shared has been served for engine */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b2a2d8fbbc68..d4b5fba7a2dc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6998,7 +6998,9 @@ enum { #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_ENGINE_CLASS(x) (((x) & GENMASK(18, 16)) >> 16) +#define GEN11_INTR_ENGINE_INSTANCE(x) (((x) & GENMASK(25, 20)) >> 20) +#define GEN11_INTR_ENGINE_INTR(x) ((x) & 0xffff) #define GEN11_INTR_IDENTITY_REG(x) _MMIO(0x190060 + (x * 4)) -- cgit v1.2.3 From d02b98b8e28278f9f0c0f4dd3f172ffcc20fbdbd Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 5 Apr 2018 17:00:50 +0300 Subject: drm/i915/icl: Handle RPS interrupts correctly for Gen11 Using the new hierarchical interrupt infrastructure. v2: Rebase v3: Rebase v4: use class/instance handler (Mika) Cc: Tvrtko Ursulin Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Paulo Zanoni Signed-off-by: Oscar Mateo Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180405140052.10682-3-mika.kuoppala@linux.intel.com --- drivers/gpu/drm/i915/i915_irq.c | 73 ++++++++++++++++++++++++++++++++++------ drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 6 ++-- 4 files changed, 67 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 45f72a0ece04..36a635475a74 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -308,17 +308,29 @@ void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask) static i915_reg_t gen6_pm_iir(struct drm_i915_private *dev_priv) { + WARN_ON_ONCE(INTEL_GEN(dev_priv) >= 11); + return INTEL_GEN(dev_priv) >= 8 ? GEN8_GT_IIR(2) : GEN6_PMIIR; } static i915_reg_t gen6_pm_imr(struct drm_i915_private *dev_priv) { - return INTEL_GEN(dev_priv) >= 8 ? GEN8_GT_IMR(2) : GEN6_PMIMR; + if (INTEL_GEN(dev_priv) >= 11) + return GEN11_GPM_WGBOXPERF_INTR_MASK; + else if (INTEL_GEN(dev_priv) >= 8) + return GEN8_GT_IMR(2); + else + return GEN6_PMIMR; } static i915_reg_t gen6_pm_ier(struct drm_i915_private *dev_priv) { - return INTEL_GEN(dev_priv) >= 8 ? GEN8_GT_IER(2) : GEN6_PMIER; + if (INTEL_GEN(dev_priv) >= 11) + return GEN11_GPM_WGBOXPERF_INTR_ENABLE; + else if (INTEL_GEN(dev_priv) >= 8) + return GEN8_GT_IER(2); + else + return GEN6_PMIER; } /** @@ -400,6 +412,32 @@ static void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, u32 disable_m /* though a barrier is missing here, but don't really need a one */ } +static u32 +gen11_gt_engine_identity(struct drm_i915_private * const i915, + const unsigned int bank, const unsigned int bit); + +void gen11_reset_rps_interrupts(struct drm_i915_private *dev_priv) +{ + u32 dw; + + spin_lock_irq(&dev_priv->irq_lock); + + /* + * According to the BSpec, DW_IIR bits cannot be cleared without + * first servicing the Selector & Shared IIR registers. + */ + dw = I915_READ_FW(GEN11_GT_INTR_DW0); + while (dw & BIT(GEN11_GTPM)) { + gen11_gt_engine_identity(dev_priv, 0, GEN11_GTPM); + I915_WRITE_FW(GEN11_GT_INTR_DW0, BIT(GEN11_GTPM)); + dw = I915_READ_FW(GEN11_GT_INTR_DW0); + } + + dev_priv->gt_pm.rps.pm_iir = 0; + + spin_unlock_irq(&dev_priv->irq_lock); +} + void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv) { spin_lock_irq(&dev_priv->irq_lock); @@ -415,12 +453,12 @@ void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv) if (READ_ONCE(rps->interrupts_enabled)) return; - if (WARN_ON_ONCE(IS_GEN11(dev_priv))) - return; - spin_lock_irq(&dev_priv->irq_lock); WARN_ON_ONCE(rps->pm_iir); - WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events); + if (INTEL_GEN(dev_priv) >= 11) + WARN_ON_ONCE(I915_READ_FW(GEN11_GT_INTR_DW0) & BIT(GEN11_GTPM)); + else + WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events); rps->interrupts_enabled = true; gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); @@ -434,9 +472,6 @@ void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv) if (!READ_ONCE(rps->interrupts_enabled)) return; - if (WARN_ON_ONCE(IS_GEN11(dev_priv))) - return; - spin_lock_irq(&dev_priv->irq_lock); rps->interrupts_enabled = false; @@ -453,7 +488,10 @@ void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv) * state of the worker can be discarded. */ cancel_work_sync(&rps->work); - gen6_reset_rps_interrupts(dev_priv); + if (INTEL_GEN(dev_priv) >= 11) + gen11_reset_rps_interrupts(dev_priv); + else + gen6_reset_rps_interrupts(dev_priv); } void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv) @@ -2768,6 +2806,9 @@ static void gen11_other_irq_handler(struct drm_i915_private * const i915, const u8 instance, const u16 iir) { + if (instance == OTHER_GTPM_INSTANCE) + return gen6_rps_irq_handler(i915, iir); + WARN_ONCE(1, "unhandled other interrupt instance=0x%x, iir=0x%x\n", instance, iir); } @@ -3330,6 +3371,9 @@ static void gen11_gt_irq_reset(struct drm_i915_private *dev_priv) I915_WRITE(GEN11_VCS0_VCS1_INTR_MASK, ~0); I915_WRITE(GEN11_VCS2_VCS3_INTR_MASK, ~0); I915_WRITE(GEN11_VECS0_VECS1_INTR_MASK, ~0); + + I915_WRITE(GEN11_GPM_WGBOXPERF_INTR_ENABLE, 0); + I915_WRITE(GEN11_GPM_WGBOXPERF_INTR_MASK, ~0); } static void gen11_irq_reset(struct drm_device *dev) @@ -3868,7 +3912,14 @@ static void gen11_gt_irq_postinstall(struct drm_i915_private *dev_priv) I915_WRITE(GEN11_VCS2_VCS3_INTR_MASK, ~(irqs | irqs << 16)); I915_WRITE(GEN11_VECS0_VECS1_INTR_MASK, ~(irqs | irqs << 16)); - dev_priv->pm_imr = 0xffffffff; /* TODO */ + /* + * RPS interrupts will get enabled/disabled on demand when RPS itself + * is enabled/disabled. + */ + dev_priv->pm_ier = 0x0; + dev_priv->pm_imr = ~dev_priv->pm_ier; + I915_WRITE(GEN11_GPM_WGBOXPERF_INTR_ENABLE, 0); + I915_WRITE(GEN11_GPM_WGBOXPERF_INTR_MASK, ~0); } static int gen11_irq_postinstall(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d4b5fba7a2dc..b3a6428aa71d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -188,6 +188,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define OTHER_CLASS 4 #define MAX_ENGINE_CLASS 4 +#define OTHER_GTPM_INSTANCE 1 #define MAX_ENGINE_INSTANCE 3 /* PCI config space */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d1452fd2a58d..85e483e9a45b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1329,6 +1329,7 @@ void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); void gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask); void gen6_unmask_pm_irq(struct drm_i915_private *dev_priv, u32 mask); +void gen11_reset_rps_interrupts(struct drm_i915_private *dev_priv); void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv); void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv); void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 19e82aaa9863..a018c9abc2b9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -8028,10 +8028,10 @@ void intel_sanitize_gt_powersave(struct drm_i915_private *dev_priv) dev_priv->gt_pm.rc6.enabled = true; /* force RC6 disabling */ intel_disable_gt_powersave(dev_priv); - if (INTEL_GEN(dev_priv) < 11) - gen6_reset_rps_interrupts(dev_priv); + if (INTEL_GEN(dev_priv) >= 11) + gen11_reset_rps_interrupts(dev_priv); else - WARN_ON_ONCE(1); + gen6_reset_rps_interrupts(dev_priv); } static inline void intel_disable_llc_pstate(struct drm_i915_private *i915) -- cgit v1.2.3 From 96606f3beb8668de2c936d7719a7e385cff9ff01 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Fri, 6 Apr 2018 12:32:37 +0300 Subject: drm/i915/icl: Deal with GT INT DW correctly BSpec says: "Second level interrupt events are stored in the GT INT DW. GT INT DW is a double buffered structure. A snapshot of events is taken when SW reads GT INT DW. From the time of read to the time of SW completely clearing GT INT DW (to indicate end of service), all incoming interrupts are logged in a secondary storage structure. this guarantees that the record of interrupts SW is servicing will not change while under service". We read GT INT DW in several places now: - The IRQ handler (banks 0 and 1) where, hopefully, it is completely cleared (operation now covered with the irq lock). - The 'reset' interrupts functions for RPS and GuC logs, where we clear the bit we are interested in and leave the others for the normal interrupt handler. - The 'enable' interrupts functions for RPS and GuC logs, as a measure of precaution. Here we could relax a bit and don't check GT INT DW at all or, if we do, at least we should clear the offending bit (which is what this patch does). Note that, if every bit is cleared on reading GT INT DW, the register won't be locked. Also note that, according to the BSpec, GT INT DW cannot be cleared without first servicing the Selector & Shared IIR registers. v2: - Remove some code duplication (Tvrtko) - Make sure GT_INTR_DW are protected by the irq spinlock, since it's a global resource (Tvrtko) v3: Optimize the spinlock (Tvrtko) v4: Rebase. v5: - take spinlock on outer scope to please sparse (Mika) - use raw_reg accessors (Mika) v6: omit the continue in looping banks (Michel) Cc: Tvrtko Ursulin Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Signed-off-by: Oscar Mateo Reviewed-by: Tvrtko Ursulin (v4) Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180406093237.14548-1-mika.kuoppala@linux.intel.com --- drivers/gpu/drm/i915/i915_irq.c | 110 ++++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 36a635475a74..c2f878ace0ea 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -243,6 +243,41 @@ void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv, spin_unlock_irq(&dev_priv->irq_lock); } +static u32 +gen11_gt_engine_identity(struct drm_i915_private * const i915, + const unsigned int bank, const unsigned int bit); + +static bool gen11_reset_one_iir(struct drm_i915_private * const i915, + const unsigned int bank, + const unsigned int bit) +{ + void __iomem * const regs = i915->regs; + u32 dw; + + lockdep_assert_held(&i915->irq_lock); + + dw = raw_reg_read(regs, GEN11_GT_INTR_DW(bank)); + if (dw & BIT(bit)) { + /* + * According to the BSpec, DW_IIR bits cannot be cleared without + * first servicing the Selector & Shared IIR registers. + */ + gen11_gt_engine_identity(i915, bank, bit); + + /* + * We locked GT INT DW by reading it. If we want to (try + * to) recover from this succesfully, we need to clear + * our bit, otherwise we are locking the register for + * everybody. + */ + raw_reg_write(regs, GEN11_GT_INTR_DW(bank), BIT(bit)); + + return true; + } + + return false; +} + /** * ilk_update_display_irq - update DEIMR * @dev_priv: driver private @@ -412,26 +447,12 @@ static void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, u32 disable_m /* though a barrier is missing here, but don't really need a one */ } -static u32 -gen11_gt_engine_identity(struct drm_i915_private * const i915, - const unsigned int bank, const unsigned int bit); - void gen11_reset_rps_interrupts(struct drm_i915_private *dev_priv) { - u32 dw; - spin_lock_irq(&dev_priv->irq_lock); - /* - * According to the BSpec, DW_IIR bits cannot be cleared without - * first servicing the Selector & Shared IIR registers. - */ - dw = I915_READ_FW(GEN11_GT_INTR_DW0); - while (dw & BIT(GEN11_GTPM)) { - gen11_gt_engine_identity(dev_priv, 0, GEN11_GTPM); - I915_WRITE_FW(GEN11_GT_INTR_DW0, BIT(GEN11_GTPM)); - dw = I915_READ_FW(GEN11_GT_INTR_DW0); - } + while (gen11_reset_one_iir(dev_priv, 0, GEN11_GTPM)) + ; dev_priv->gt_pm.rps.pm_iir = 0; @@ -455,10 +476,12 @@ void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv) spin_lock_irq(&dev_priv->irq_lock); WARN_ON_ONCE(rps->pm_iir); + if (INTEL_GEN(dev_priv) >= 11) - WARN_ON_ONCE(I915_READ_FW(GEN11_GT_INTR_DW0) & BIT(GEN11_GTPM)); + WARN_ON_ONCE(gen11_reset_one_iir(dev_priv, 0, GEN11_GTPM)); else WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events); + rps->interrupts_enabled = true; gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); @@ -2778,6 +2801,8 @@ gen11_gt_engine_identity(struct drm_i915_private * const i915, u32 timeout_ts; u32 ident; + lockdep_assert_held(&i915->irq_lock); + raw_reg_write(regs, GEN11_IIR_REG_SELECTOR(bank), BIT(bit)); /* @@ -2853,36 +2878,47 @@ gen11_gt_identity_handler(struct drm_i915_private * const i915, } static void -gen11_gt_irq_handler(struct drm_i915_private * const i915, - const u32 master_ctl) +gen11_gt_bank_handler(struct drm_i915_private * const i915, + const unsigned int bank) { void __iomem * const regs = i915->regs; - unsigned int bank; + unsigned long intr_dw; + unsigned int bit; - for (bank = 0; bank < 2; bank++) { - unsigned long intr_dw; - unsigned int bit; + lockdep_assert_held(&i915->irq_lock); - if (!(master_ctl & GEN11_GT_DW_IRQ(bank))) - continue; + intr_dw = raw_reg_read(regs, GEN11_GT_INTR_DW(bank)); - intr_dw = raw_reg_read(regs, GEN11_GT_INTR_DW(bank)); + if (unlikely(!intr_dw)) { + DRM_ERROR("GT_INTR_DW%u blank!\n", bank); + return; + } - if (unlikely(!intr_dw)) { - DRM_ERROR("GT_INTR_DW%u blank!\n", bank); - continue; - } + for_each_set_bit(bit, &intr_dw, 32) { + const u32 ident = gen11_gt_engine_identity(i915, + bank, bit); - for_each_set_bit(bit, &intr_dw, 32) { - const u32 ident = gen11_gt_engine_identity(i915, - bank, bit); + gen11_gt_identity_handler(i915, ident); + } - gen11_gt_identity_handler(i915, ident); - } + /* Clear must be after shared has been served for engine */ + raw_reg_write(regs, GEN11_GT_INTR_DW(bank), intr_dw); +} - /* Clear must be after shared has been served for engine */ - raw_reg_write(regs, GEN11_GT_INTR_DW(bank), intr_dw); +static void +gen11_gt_irq_handler(struct drm_i915_private * const i915, + const u32 master_ctl) +{ + unsigned int bank; + + spin_lock(&i915->irq_lock); + + for (bank = 0; bank < 2; bank++) { + if (master_ctl & GEN11_GT_DW_IRQ(bank)) + gen11_gt_bank_handler(i915, bank); } + + spin_unlock(&i915->irq_lock); } static irqreturn_t gen11_irq_handler(int irq, void *arg) -- cgit v1.2.3 From 2b2874efe2413c43f9e330023a03ec5203b372b2 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 5 Apr 2018 17:00:52 +0300 Subject: drm/i915/icl: Enable RC6 and RPS in Gen11 AFAICT, once the new interrupt is in place, the rest should behave the same as Gen10. v2: Update ring frequencies (Sagar) v3: Rebase. Cc: Daniele Ceraolo Spurio Cc: Sagar Arun Kamble Cc: Paulo Zanoni Signed-off-by: Oscar Mateo Reviewed-by: Michel Thierry Signed-off-by: Mika Kuoppala Link: https://patchwork.freedesktop.org/patch/msgid/20180405140052.10682-5-mika.kuoppala@linux.intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 10 +++++----- drivers/gpu/drm/i915/intel_pm.c | 10 ++++------ 2 files changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 1dba2c451255..785b710e4ee4 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1215,20 +1215,20 @@ static int i915_frequency_info(struct seq_file *m, void *unused) max_freq = (IS_GEN9_LP(dev_priv) ? rp_state_cap >> 0 : rp_state_cap >> 16) & 0xff; max_freq *= (IS_GEN9_BC(dev_priv) || - IS_CANNONLAKE(dev_priv) ? GEN9_FREQ_SCALER : 1); + INTEL_GEN(dev_priv) >= 10 ? GEN9_FREQ_SCALER : 1); seq_printf(m, "Lowest (RPN) frequency: %dMHz\n", intel_gpu_freq(dev_priv, max_freq)); max_freq = (rp_state_cap & 0xff00) >> 8; max_freq *= (IS_GEN9_BC(dev_priv) || - IS_CANNONLAKE(dev_priv) ? GEN9_FREQ_SCALER : 1); + INTEL_GEN(dev_priv) >= 10 ? GEN9_FREQ_SCALER : 1); seq_printf(m, "Nominal (RP1) frequency: %dMHz\n", intel_gpu_freq(dev_priv, max_freq)); max_freq = (IS_GEN9_LP(dev_priv) ? rp_state_cap >> 16 : rp_state_cap >> 0) & 0xff; max_freq *= (IS_GEN9_BC(dev_priv) || - IS_CANNONLAKE(dev_priv) ? GEN9_FREQ_SCALER : 1); + INTEL_GEN(dev_priv) >= 10 ? GEN9_FREQ_SCALER : 1); seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", intel_gpu_freq(dev_priv, max_freq)); seq_printf(m, "Max overclocked frequency: %dMHz\n", @@ -1811,7 +1811,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) min_gpu_freq = rps->min_freq; max_gpu_freq = rps->max_freq; - if (IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv)) { + if (IS_GEN9_BC(dev_priv) || INTEL_GEN(dev_priv) >= 10) { /* Convert GT frequency to 50 HZ units */ min_gpu_freq /= GEN9_FREQ_SCALER; max_gpu_freq /= GEN9_FREQ_SCALER; @@ -1827,7 +1827,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) seq_printf(m, "%d\t\t%d\t\t\t\t%d\n", intel_gpu_freq(dev_priv, (gpu_freq * (IS_GEN9_BC(dev_priv) || - IS_CANNONLAKE(dev_priv) ? + INTEL_GEN(dev_priv) >= 10 ? GEN9_FREQ_SCALER : 1))), ((ia_freq >> 0) & 0xff) * 100, ((ia_freq >> 8) & 0xff) * 100); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a018c9abc2b9..0d25e413ec0b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6572,7 +6572,7 @@ static void gen6_init_rps_frequencies(struct drm_i915_private *dev_priv) rps->efficient_freq = rps->rp1_freq; if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv) || - IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv)) { + IS_GEN9_BC(dev_priv) || INTEL_GEN(dev_priv) >= 10) { u32 ddcc_status = 0; if (sandybridge_pcode_read(dev_priv, @@ -6585,7 +6585,7 @@ static void gen6_init_rps_frequencies(struct drm_i915_private *dev_priv) rps->max_freq); } - if (IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv)) { + if (IS_GEN9_BC(dev_priv) || INTEL_GEN(dev_priv) >= 10) { /* Store the frequency values in 16.66 MHZ units, which is * the natural hardware unit for SKL */ @@ -6923,7 +6923,7 @@ static void gen6_update_ring_freq(struct drm_i915_private *dev_priv) min_gpu_freq = rps->min_freq; max_gpu_freq = rps->max_freq; - if (IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv)) { + if (IS_GEN9_BC(dev_priv) || INTEL_GEN(dev_priv) >= 10) { /* Convert GT frequency to 50 HZ units */ min_gpu_freq /= GEN9_FREQ_SCALER; max_gpu_freq /= GEN9_FREQ_SCALER; @@ -6938,7 +6938,7 @@ static void gen6_update_ring_freq(struct drm_i915_private *dev_priv) const int diff = max_gpu_freq - gpu_freq; unsigned int ia_freq = 0, ring_freq = 0; - if (IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv)) { + if (IS_GEN9_BC(dev_priv) || INTEL_GEN(dev_priv) >= 10) { /* * ring_freq = 2 * GT. ring_freq is in 100MHz units * No floor required for ring frequency on SKL. @@ -8144,8 +8144,6 @@ static void intel_enable_rps(struct drm_i915_private *dev_priv) cherryview_enable_rps(dev_priv); } else if (IS_VALLEYVIEW(dev_priv)) { valleyview_enable_rps(dev_priv); - } else if (WARN_ON_ONCE(INTEL_GEN(dev_priv) >= 11)) { - /* TODO */ } else if (INTEL_GEN(dev_priv) >= 9) { gen9_enable_rps(dev_priv); } else if (IS_BROADWELL(dev_priv)) { -- cgit v1.2.3 From 29991d533f6902757de7ffdb933c196421914b08 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 6 Apr 2018 11:09:50 +0100 Subject: drm/i915/selftests: Rename wait_for_hang() to wait_until_running() Tvrtko mentioned that wait_for_hang() was confusing as it does not actually wait for the aforementioned hang, just until the request is running and we are *ready* to inject a hang. A quick s/wait_for_hang/wait_until_running/ removes that confusion without having to rethink the naming scheme, immediately at least. Suggested-by: Tvrtko Ursulin Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Mika Kuoppala Cc: Michel Thierry Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180406100950.19033-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/intel_hangcheck.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index d03abe7f8a53..8650853c8cb3 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -322,7 +322,7 @@ static void hang_fini(struct hang *h) flush_test(h->i915, I915_WAIT_LOCKED); } -static bool wait_for_hang(struct hang *h, struct i915_request *rq) +static bool wait_until_running(struct hang *h, struct i915_request *rq) { return !(wait_for_us(i915_seqno_passed(hws_seqno(h, rq), rq->fence.seqno), @@ -504,7 +504,7 @@ static int __igt_reset_engine(struct drm_i915_private *i915, bool active) __i915_request_add(rq, true); mutex_unlock(&i915->drm.struct_mutex); - if (!wait_for_hang(&h, rq)) { + if (!wait_until_running(&h, rq)) { struct drm_printer p = drm_info_printer(i915->drm.dev); pr_err("%s: Failed to start request %x, at %x\n", @@ -747,7 +747,7 @@ static int __igt_reset_engines(struct drm_i915_private *i915, __i915_request_add(rq, true); mutex_unlock(&i915->drm.struct_mutex); - if (!wait_for_hang(&h, rq)) { + if (!wait_until_running(&h, rq)) { struct drm_printer p = drm_info_printer(i915->drm.dev); pr_err("%s: Failed to start request %x, at %x\n", @@ -935,7 +935,7 @@ static int igt_wait_reset(void *arg) i915_request_get(rq); __i915_request_add(rq, true); - if (!wait_for_hang(&h, rq)) { + if (!wait_until_running(&h, rq)) { struct drm_printer p = drm_info_printer(i915->drm.dev); pr_err("%s: Failed to start request %x, at %x\n", @@ -1066,7 +1066,7 @@ static int igt_reset_queue(void *arg) goto fini; } - if (!wait_for_hang(&h, prev)) { + if (!wait_until_running(&h, prev)) { struct drm_printer p = drm_info_printer(i915->drm.dev); pr_err("%s(%s): Failed to start request %x, at %x\n", @@ -1177,7 +1177,7 @@ static int igt_handle_error(void *arg) i915_request_get(rq); __i915_request_add(rq, true); - if (!wait_for_hang(&h, rq)) { + if (!wait_until_running(&h, rq)) { struct drm_printer p = drm_info_printer(i915->drm.dev); pr_err("%s: Failed to start request %x, at %x\n", -- cgit v1.2.3 From e4d2006f8f040825fa371e774a5debacdbf20b08 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 6 Apr 2018 16:51:44 +0100 Subject: drm/i915: Split out parking from the idle worker for reuse We will want to park GEM before disengaging the drive^W^W^W unwedging. Since we already do the work for idling, expose the guts as a new function that we can then reuse. v2: Just skip if already parked; makes it more forgiving to use by future callers. v3: Extract mark_busy, rename it to i915_gem_unpark and place it next to i915_gem_park so that we can evaluate it for symmetry more easily. Calling GEM from inside i915_request looks to be a bit of a layering violation, for the moment I am imaging them as being notify_cb. Signed-off-by: Chris Wilson Cc: Michal Wajdeczko Cc: Sagar Arun Kamble Cc: Tvrtko Ursulin Cc: Mika Kuoppala Reviewed-by: Mika Kuoppala #v1 Reviewed-by: Michal Wajdeczko Link: https://patchwork.freedesktop.org/patch/msgid/20180406155144.27791-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 123 ++++++++++++++++++++++++++++-------- drivers/gpu/drm/i915/i915_gem.h | 5 ++ drivers/gpu/drm/i915/i915_request.c | 52 +-------------- 3 files changed, 103 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9650a7b10c5f..a69dc19a0bdb 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -136,6 +136,100 @@ int i915_mutex_lock_interruptible(struct drm_device *dev) return 0; } +static u32 __i915_gem_park(struct drm_i915_private *i915) +{ + lockdep_assert_held(&i915->drm.struct_mutex); + GEM_BUG_ON(i915->gt.active_requests); + + if (!i915->gt.awake) + return I915_EPOCH_INVALID; + + GEM_BUG_ON(i915->gt.epoch == I915_EPOCH_INVALID); + + /* + * Be paranoid and flush a concurrent interrupt to make sure + * we don't reactivate any irq tasklets after parking. + * + * FIXME: Note that even though we have waited for execlists to be idle, + * there may still be an in-flight interrupt even though the CSB + * is now empty. synchronize_irq() makes sure that a residual interrupt + * is completed before we continue, but it doesn't prevent the HW from + * raising a spurious interrupt later. To complete the shield we should + * coordinate disabling the CS irq with flushing the interrupts. + */ + synchronize_irq(i915->drm.irq); + + intel_engines_park(i915); + i915_gem_timelines_park(i915); + + i915_pmu_gt_parked(i915); + + i915->gt.awake = false; + + if (INTEL_GEN(i915) >= 6) + gen6_rps_idle(i915); + + intel_display_power_put(i915, POWER_DOMAIN_GT_IRQ); + + intel_runtime_pm_put(i915); + + return i915->gt.epoch; +} + +void i915_gem_park(struct drm_i915_private *i915) +{ + lockdep_assert_held(&i915->drm.struct_mutex); + GEM_BUG_ON(i915->gt.active_requests); + + if (!i915->gt.awake) + return; + + /* Defer the actual call to __i915_gem_park() to prevent ping-pongs */ + mod_delayed_work(i915->wq, &i915->gt.idle_work, msecs_to_jiffies(100)); +} + +void i915_gem_unpark(struct drm_i915_private *i915) +{ + lockdep_assert_held(&i915->drm.struct_mutex); + GEM_BUG_ON(!i915->gt.active_requests); + + if (i915->gt.awake) + return; + + intel_runtime_pm_get_noresume(i915); + + /* + * It seems that the DMC likes to transition between the DC states a lot + * when there are no connected displays (no active power domains) during + * command submission. + * + * This activity has negative impact on the performance of the chip with + * huge latencies observed in the interrupt handler and elsewhere. + * + * Work around it by grabbing a GT IRQ power domain whilst there is any + * GT activity, preventing any DC state transitions. + */ + 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); + if (INTEL_GEN(i915) >= 6) + gen6_rps_busy(i915); + i915_pmu_gt_unparked(i915); + + intel_engines_unpark(i915); + + i915_queue_hangcheck(i915); + + queue_delayed_work(i915->wq, + &i915->gt.retire_work, + round_jiffies_up_relative(HZ)); +} + int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct drm_file *file) @@ -3496,36 +3590,9 @@ i915_gem_idle_work_handler(struct work_struct *work) if (new_requests_since_last_retire(dev_priv)) goto out_unlock; - /* - * Be paranoid and flush a concurrent interrupt to make sure - * we don't reactivate any irq tasklets after parking. - * - * FIXME: Note that even though we have waited for execlists to be idle, - * there may still be an in-flight interrupt even though the CSB - * is now empty. synchronize_irq() makes sure that a residual interrupt - * is completed before we continue, but it doesn't prevent the HW from - * raising a spurious interrupt later. To complete the shield we should - * coordinate disabling the CS irq with flushing the interrupts. - */ - synchronize_irq(dev_priv->drm.irq); - - intel_engines_park(dev_priv); - i915_gem_timelines_park(dev_priv); - - i915_pmu_gt_parked(dev_priv); + epoch = __i915_gem_park(dev_priv); - 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) - gen6_rps_idle(dev_priv); - - intel_display_power_put(dev_priv, POWER_DOMAIN_GT_IRQ); - - intel_runtime_pm_put(dev_priv); out_unlock: mutex_unlock(&dev_priv->drm.struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_gem.h b/drivers/gpu/drm/i915/i915_gem.h index 8922344fc21b..deaf78d2ae8b 100644 --- a/drivers/gpu/drm/i915/i915_gem.h +++ b/drivers/gpu/drm/i915/i915_gem.h @@ -27,6 +27,8 @@ #include +struct drm_i915_private; + #ifdef CONFIG_DRM_I915_DEBUG_GEM #define GEM_BUG_ON(condition) do { if (unlikely((condition))) { \ pr_err("%s:%d GEM_BUG_ON(%s)\n", \ @@ -61,4 +63,7 @@ #define I915_NUM_ENGINES 8 +void i915_gem_park(struct drm_i915_private *i915); +void i915_gem_unpark(struct drm_i915_private *i915); + #endif /* __I915_GEM_H__ */ diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 585242831974..a9d0bde16443 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -255,47 +255,6 @@ int i915_gem_set_global_seqno(struct drm_device *dev, u32 seqno) return reset_all_global_seqno(i915, seqno - 1); } -static void mark_busy(struct drm_i915_private *i915) -{ - if (i915->gt.awake) - return; - - GEM_BUG_ON(!i915->gt.active_requests); - - intel_runtime_pm_get_noresume(i915); - - /* - * It seems that the DMC likes to transition between the DC states a lot - * when there are no connected displays (no active power domains) during - * command submission. - * - * This activity has negative impact on the performance of the chip with - * huge latencies observed in the interrupt handler and elsewhere. - * - * Work around it by grabbing a GT IRQ power domain whilst there is any - * GT activity, preventing any DC state transitions. - */ - 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); - if (INTEL_GEN(i915) >= 6) - gen6_rps_busy(i915); - i915_pmu_gt_unparked(i915); - - intel_engines_unpark(i915); - - i915_queue_hangcheck(i915); - - queue_delayed_work(i915->wq, - &i915->gt.retire_work, - round_jiffies_up_relative(HZ)); -} - static int reserve_engine(struct intel_engine_cs *engine) { struct drm_i915_private *i915 = engine->i915; @@ -313,7 +272,7 @@ static int reserve_engine(struct intel_engine_cs *engine) } if (!i915->gt.active_requests++) - mark_busy(i915); + i915_gem_unpark(i915); return 0; } @@ -322,13 +281,8 @@ static void unreserve_engine(struct intel_engine_cs *engine) { struct drm_i915_private *i915 = engine->i915; - if (!--i915->gt.active_requests) { - /* Cancel the mark_busy() from our reserve_engine() */ - GEM_BUG_ON(!i915->gt.awake); - mod_delayed_work(i915->wq, - &i915->gt.idle_work, - msecs_to_jiffies(100)); - } + if (!--i915->gt.active_requests) + i915_gem_park(i915); GEM_BUG_ON(!engine->timeline->inflight_seqnos); engine->timeline->inflight_seqnos--; -- cgit v1.2.3 From bba0869b18e44ff2f713c98575ddad8c7c5e9b10 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 6 Apr 2018 23:03:53 +0100 Subject: drm/i915: Treat i915_reset_engine() as guilty until proven innocent If we are resetting just one engine, we know it has stalled. So we can pass the stalled parameter directly to i915_gem_reset_engine(), which alleviates the necessity to poke at the generic engine->hangcheck.stalled magic variable, leaving that under control of hangcheck as its name implies. Other than simplifying by removing the indirect parameter along this path, this allows us to introduce new reset mechanisms that run independently of hangcheck. Signed-off-by: Chris Wilson Cc: Michel Thierry Cc: Jeff McGee Cc: Mika Kuoppala Reviewed-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180406220354.18911-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/i915_gem.c | 36 +++++++++++------------- drivers/gpu/drm/i915/selftests/intel_hangcheck.c | 9 ------ 4 files changed, 20 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 684060ed8db6..7ce229c6f424 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -2050,7 +2050,7 @@ int i915_reset_engine(struct intel_engine_cs *engine, const char *msg) * active request and can drop it, adjust head to skip the offending * request to resume executing remaining requests in the queue. */ - i915_gem_reset_engine(engine, active_request); + i915_gem_reset_engine(engine, active_request, true); /* * The engine and its registers (and workarounds in case of render) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5373b171bb96..6b3f2f651def 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3132,7 +3132,8 @@ void i915_gem_reset_finish(struct drm_i915_private *dev_priv); void i915_gem_set_wedged(struct drm_i915_private *dev_priv); bool i915_gem_unset_wedged(struct drm_i915_private *dev_priv); void i915_gem_reset_engine(struct intel_engine_cs *engine, - struct i915_request *request); + struct i915_request *request, + bool stalled); void i915_gem_init_mmio(struct drm_i915_private *i915); int __must_check i915_gem_init(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a69dc19a0bdb..306d7a805eb7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2990,20 +2990,6 @@ i915_gem_find_active_request(struct intel_engine_cs *engine) return active; } -static bool engine_stalled(struct intel_engine_cs *engine) -{ - if (!engine->hangcheck.stalled) - return false; - - /* Check for possible seqno movement after hang declaration */ - if (engine->hangcheck.seqno != intel_engine_get_seqno(engine)) { - DRM_DEBUG_DRIVER("%s pardoned\n", engine->name); - return false; - } - - return true; -} - /* * Ensure irq handler finishes, and not run again. * Also return the active request so that we only search for it once. @@ -3142,7 +3128,8 @@ static void engine_skip_context(struct i915_request *request) /* Returns the request if it was guilty of the hang */ static struct i915_request * i915_gem_reset_request(struct intel_engine_cs *engine, - struct i915_request *request) + struct i915_request *request, + bool stalled) { /* The guilty request will get skipped on a hung engine. * @@ -3165,7 +3152,15 @@ i915_gem_reset_request(struct intel_engine_cs *engine, * subsequent hangs. */ - if (engine_stalled(engine)) { + if (i915_request_completed(request)) { + GEM_TRACE("%s pardoned global=%d (fence %llx:%d), current %d\n", + engine->name, request->global_seqno, + request->fence.context, request->fence.seqno, + intel_engine_get_seqno(engine)); + stalled = false; + } + + if (stalled) { i915_gem_context_mark_guilty(request->ctx); skip_request(request); @@ -3196,7 +3191,8 @@ i915_gem_reset_request(struct intel_engine_cs *engine, } void i915_gem_reset_engine(struct intel_engine_cs *engine, - struct i915_request *request) + struct i915_request *request, + bool stalled) { /* * Make sure this write is visible before we re-enable the interrupt @@ -3206,7 +3202,7 @@ void i915_gem_reset_engine(struct intel_engine_cs *engine, smp_store_mb(engine->irq_posted, 0); if (request) - request = i915_gem_reset_request(engine, request); + request = i915_gem_reset_request(engine, request, stalled); if (request) { DRM_DEBUG_DRIVER("resetting %s to restart from tail of request 0x%x\n", @@ -3229,7 +3225,9 @@ void i915_gem_reset(struct drm_i915_private *dev_priv) for_each_engine(engine, dev_priv, id) { struct i915_gem_context *ctx; - i915_gem_reset_engine(engine, engine->hangcheck.active_request); + i915_gem_reset_engine(engine, + engine->hangcheck.active_request, + engine->hangcheck.stalled); ctx = fetch_and_zero(&engine->last_retired_context); if (ctx) engine->context_unpin(engine, ctx); diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 8650853c8cb3..acfb4dcc9fb5 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -522,9 +522,6 @@ static int __igt_reset_engine(struct drm_i915_private *i915, bool active) i915_request_put(rq); } - engine->hangcheck.stalled = true; - engine->hangcheck.seqno = seqno; - err = i915_reset_engine(engine, NULL); if (err) { pr_err("i915_reset_engine failed\n"); @@ -545,8 +542,6 @@ static int __igt_reset_engine(struct drm_i915_private *i915, bool active) err = -EINVAL; break; } - - engine->hangcheck.stalled = false; } while (time_before(jiffies, end_time)); clear_bit(I915_RESET_ENGINE + id, &i915->gpu_error.flags); @@ -764,9 +759,6 @@ static int __igt_reset_engines(struct drm_i915_private *i915, seqno = rq->global_seqno - 1; } - engine->hangcheck.stalled = true; - engine->hangcheck.seqno = seqno; - err = i915_reset_engine(engine, NULL); if (err) { pr_err("i915_reset_engine(%s:%s): failed, err=%d\n", @@ -774,7 +766,6 @@ static int __igt_reset_engines(struct drm_i915_private *i915, break; } - engine->hangcheck.stalled = false; count++; if (rq) { -- cgit v1.2.3 From d0667e9ce52eb2d5d32db4f16976226e78f88784 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 6 Apr 2018 23:03:54 +0100 Subject: drm/i915: Pass the set of guilty engines to i915_reset() Currently, we rely on inspecting the hangcheck state from within the i915_reset() routines to determine which engines were guilty of the hang. This is problematic for cases where we want to run i915_handle_error() and call i915_reset() independently of hangcheck. Instead of relying on the indirect parameter passing, turn it into an explicit parameter providing the set of stalled engines which then are treated as guilty until proven innocent. While we are removing the implicit stalled parameter, also make the reason into an explicit parameter to i915_reset(). We still need a back-channel for i915_handle_error() to hand over the task to the locked waiter, but let's keep that its own channel rather than incriminate another. This leaves stalled/seqno as being private to hangcheck, with no more nefarious snooping by reset, be it whole-device or per-engine. \o/ The only real issue now is that this makes it crystal clear that we don't actually do any testing of hangcheck per se in drv_selftest/live_hangcheck, merely of resets! Signed-off-by: Chris Wilson Cc: Michel Thierry Cc: Jeff McGee Cc: Mika Kuoppala Reviewed-by: Michel Thierry Link: https://patchwork.freedesktop.org/patch/msgid/20180406220354.18911-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.c | 13 ++++++---- drivers/gpu/drm/i915/i915_drv.h | 10 +++++--- drivers/gpu/drm/i915/i915_gem.c | 5 ++-- drivers/gpu/drm/i915/i915_gpu_error.h | 3 +++ drivers/gpu/drm/i915/i915_irq.c | 12 ++++++---- drivers/gpu/drm/i915/i915_request.c | 6 +++-- drivers/gpu/drm/i915/selftests/intel_hangcheck.c | 30 +++++++++++------------- 7 files changed, 47 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 7ce229c6f424..f770be18b2d7 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1866,6 +1866,8 @@ static int i915_resume_switcheroo(struct drm_device *dev) /** * i915_reset - reset chip after a hang * @i915: #drm_i915_private to reset + * @stalled_mask: mask of the stalled engines with the guilty requests + * @reason: user error message for why we are resetting * * Reset the chip. Useful if a hang is detected. Marks the device as wedged * on failure. @@ -1880,7 +1882,9 @@ static int i915_resume_switcheroo(struct drm_device *dev) * - re-init interrupt state * - re-init display */ -void i915_reset(struct drm_i915_private *i915) +void i915_reset(struct drm_i915_private *i915, + unsigned int stalled_mask, + const char *reason) { struct i915_gpu_error *error = &i915->gpu_error; int ret; @@ -1899,9 +1903,8 @@ void i915_reset(struct drm_i915_private *i915) if (!i915_gem_unset_wedged(i915)) goto wakeup; - if (error->reason) - dev_notice(i915->drm.dev, - "Resetting chip for %s\n", error->reason); + if (reason) + dev_notice(i915->drm.dev, "Resetting chip for %s\n", reason); error->reset_count++; disable_irq(i915->drm.irq); @@ -1944,7 +1947,7 @@ void i915_reset(struct drm_i915_private *i915) goto error; } - i915_gem_reset(i915); + i915_gem_reset(i915, stalled_mask); intel_overlay_reset(i915); /* diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6b3f2f651def..9bca104c409e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2701,8 +2701,11 @@ extern void i915_driver_unload(struct drm_device *dev); extern int intel_gpu_reset(struct drm_i915_private *dev_priv, u32 engine_mask); extern bool intel_has_gpu_reset(struct drm_i915_private *dev_priv); -extern void i915_reset(struct drm_i915_private *i915); -extern int i915_reset_engine(struct intel_engine_cs *engine, const char *msg); +extern void i915_reset(struct drm_i915_private *i915, + unsigned int stalled_mask, + const char *reason); +extern int i915_reset_engine(struct intel_engine_cs *engine, + const char *reason); extern bool intel_has_reset_engine(struct drm_i915_private *dev_priv); extern int intel_reset_guc(struct drm_i915_private *dev_priv); @@ -3126,7 +3129,8 @@ static inline u32 i915_reset_engine_count(struct i915_gpu_error *error, struct i915_request * i915_gem_reset_prepare_engine(struct intel_engine_cs *engine); int i915_gem_reset_prepare(struct drm_i915_private *dev_priv); -void i915_gem_reset(struct drm_i915_private *dev_priv); +void i915_gem_reset(struct drm_i915_private *dev_priv, + unsigned int stalled_mask); void i915_gem_reset_finish_engine(struct intel_engine_cs *engine); void i915_gem_reset_finish(struct drm_i915_private *dev_priv); void i915_gem_set_wedged(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 306d7a805eb7..28ab0beff86c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3213,7 +3213,8 @@ void i915_gem_reset_engine(struct intel_engine_cs *engine, engine->reset_hw(engine, request); } -void i915_gem_reset(struct drm_i915_private *dev_priv) +void i915_gem_reset(struct drm_i915_private *dev_priv, + unsigned int stalled_mask) { struct intel_engine_cs *engine; enum intel_engine_id id; @@ -3227,7 +3228,7 @@ void i915_gem_reset(struct drm_i915_private *dev_priv) i915_gem_reset_engine(engine, engine->hangcheck.active_request, - engine->hangcheck.stalled); + stalled_mask & ENGINE_MASK(id)); ctx = fetch_and_zero(&engine->last_retired_context); if (ctx) engine->context_unpin(engine, ctx); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index ac5760673cc9..c05b6034d718 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -269,6 +269,9 @@ struct i915_gpu_error { /** Number of times an engine has been reset */ u32 reset_engine_count[I915_NUM_ENGINES]; + /** Set of stalled engines with guilty requests, in the current reset */ + u32 stalled_mask; + /** Reason for the current *global* reset */ const char *reason; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c2f878ace0ea..b03d18561b55 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2961,7 +2961,8 @@ static irqreturn_t gen11_irq_handler(int irq, void *arg) } static void i915_reset_device(struct drm_i915_private *dev_priv, - const char *msg) + u32 engine_mask, + const char *reason) { struct i915_gpu_error *error = &dev_priv->gpu_error; struct kobject *kobj = &dev_priv->drm.primary->kdev->kobj; @@ -2979,9 +2980,11 @@ static void i915_reset_device(struct drm_i915_private *dev_priv, i915_wedge_on_timeout(&w, dev_priv, 5*HZ) { intel_prepare_reset(dev_priv); - error->reason = msg; + error->reason = reason; + error->stalled_mask = engine_mask; /* Signal that locked waiters should reset the GPU */ + smp_mb__before_atomic(); set_bit(I915_RESET_HANDOFF, &error->flags); wake_up_all(&error->wait_queue); @@ -2990,7 +2993,7 @@ static void i915_reset_device(struct drm_i915_private *dev_priv, */ do { if (mutex_trylock(&dev_priv->drm.struct_mutex)) { - i915_reset(dev_priv); + i915_reset(dev_priv, engine_mask, reason); mutex_unlock(&dev_priv->drm.struct_mutex); } } while (wait_on_bit_timeout(&error->flags, @@ -2998,6 +3001,7 @@ static void i915_reset_device(struct drm_i915_private *dev_priv, TASK_UNINTERRUPTIBLE, 1)); + error->stalled_mask = 0; error->reason = NULL; intel_finish_reset(dev_priv); @@ -3122,7 +3126,7 @@ void i915_handle_error(struct drm_i915_private *dev_priv, TASK_UNINTERRUPTIBLE); } - i915_reset_device(dev_priv, msg); + i915_reset_device(dev_priv, engine_mask, msg); for_each_engine(engine, dev_priv, tmp) { clear_bit(I915_RESET_ENGINE + engine->id, diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index a9d0bde16443..629f3e860592 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1185,11 +1185,13 @@ static bool __i915_spin_request(const struct i915_request *rq, static bool __i915_wait_request_check_and_reset(struct i915_request *request) { - if (likely(!i915_reset_handoff(&request->i915->gpu_error))) + struct i915_gpu_error *error = &request->i915->gpu_error; + + if (likely(!i915_reset_handoff(error))) return false; __set_current_state(TASK_RUNNING); - i915_reset(request->i915); + i915_reset(request->i915, error->stalled_mask, error->reason); return true; } diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index acfb4dcc9fb5..24f913f26a7b 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -437,7 +437,7 @@ static int igt_global_reset(void *arg) mutex_lock(&i915->drm.struct_mutex); reset_count = i915_reset_count(&i915->gpu_error); - i915_reset(i915); + i915_reset(i915, ALL_ENGINES, NULL); if (i915_reset_count(&i915->gpu_error) == reset_count) { pr_err("No GPU reset recorded!\n"); @@ -881,17 +881,18 @@ static int igt_reset_engines(void *arg) return 0; } -static u32 fake_hangcheck(struct i915_request *rq) +static u32 fake_hangcheck(struct i915_request *rq, u32 mask) { - u32 reset_count; + struct i915_gpu_error *error = &rq->i915->gpu_error; + u32 reset_count = i915_reset_count(error); - rq->engine->hangcheck.stalled = true; - rq->engine->hangcheck.seqno = intel_engine_get_seqno(rq->engine); + error->stalled_mask = mask; - reset_count = i915_reset_count(&rq->i915->gpu_error); + /* set_bit() must be after we have setup the backchannel (mask) */ + smp_mb__before_atomic(); + set_bit(I915_RESET_HANDOFF, &error->flags); - set_bit(I915_RESET_HANDOFF, &rq->i915->gpu_error.flags); - wake_up_all(&rq->i915->gpu_error.wait_queue); + wake_up_all(&error->wait_queue); return reset_count; } @@ -939,7 +940,7 @@ static int igt_wait_reset(void *arg) goto out_rq; } - reset_count = fake_hangcheck(rq); + reset_count = fake_hangcheck(rq, ALL_ENGINES); timeout = i915_request_wait(rq, I915_WAIT_LOCKED, 10); if (timeout < 0) { @@ -1075,9 +1076,9 @@ static int igt_reset_queue(void *arg) goto fini; } - reset_count = fake_hangcheck(prev); + reset_count = fake_hangcheck(prev, ENGINE_MASK(id)); - i915_reset(i915); + i915_reset(i915, ENGINE_MASK(id), NULL); GEM_BUG_ON(test_bit(I915_RESET_HANDOFF, &i915->gpu_error.flags)); @@ -1150,7 +1151,7 @@ static int igt_handle_error(void *arg) if (!intel_has_reset_engine(i915)) return 0; - if (!intel_engine_can_store_dword(i915->engine[RCS])) + if (!engine || !intel_engine_can_store_dword(engine)) return 0; mutex_lock(&i915->drm.struct_mutex); @@ -1186,10 +1187,7 @@ static int igt_handle_error(void *arg) /* Temporarily disable error capture */ error = xchg(&i915->gpu_error.first_error, (void *)-1); - engine->hangcheck.stalled = true; - engine->hangcheck.seqno = intel_engine_get_seqno(engine); - - i915_handle_error(i915, intel_engine_flag(engine), 0, NULL); + i915_handle_error(i915, ENGINE_MASK(engine->id), 0, NULL); xchg(&i915->gpu_error.first_error, error); -- cgit v1.2.3 From be1c63c8017bb00a4041abace6cc1e9f0bf26aa9 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 6 Apr 2018 21:10:53 -0400 Subject: drm/i915/dp: Send DPCD ON for MST before phy_up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When doing a modeset where the sink is transitioning from D3 to D0 , it would sometimes be possible for the initial power_up_phy() to start timing out. This would only be observed in the last action before the sink went into D3 mode was intel_dp_sink_dpms(DRM_MODE_DPMS_OFF). We originally thought this might be an issue with us accidentally shutting off the aux block when putting the sink into D3, but since the DP spec mandates that sinks must wake up within 1ms while we have 100ms to respond to an ESI irq, this didn't really add up. Turns out that the problem is more subtle then that: It turns out that the timeout is from us not enabling DPMS on the MST hub before actually trying to initiate sideband communications. This would cause the first sideband communication (power_up_phy()), to start timing out because the sink wasn't ready to respond. Afterwards, we would call intel_dp_sink_dpms(DRM_MODE_DPMS_ON) in intel_ddi_pre_enable_dp(), which would actually result in waking up the sink so that sideband requests would work again. Since DPMS is what lets us actually bring the hub up into a state where sideband communications become functional again, we just need to make sure to enable DPMS on the display before attempting to perform sideband communications. Changes since v1: - Remove comment above if (!intel_dp->is_mst) - vsryjala - Move intel_dp_sink_dpms() for MST into intel_dp_post_disable_mst() to keep enable/disable paths symmetrical - Improve commit message - dhnkrn Changes since v2: - Only send DPMS off when we're disabling the last sink, and only send DPMS on when we're enabling the first sink - dhnkrn Changes since v3: - Check against is_mst, not intel_dp->is_mst - dhnkrn/vsyrjala Signed-off-by: Lyude Paul Reviewed-by: Dhinakaran Pandiyan Reviewed-by: Ville Syrjälä Tested-by: Laura Abbott Cc: stable@vger.kernel.org Fixes: ad260ab32a4d9 ("drm/i915/dp: Write to SET_POWER dpcd to enable MST hub.") Link: https://patchwork.freedesktop.org/patch/msgid/20180407011053.22437-1-lyude@redhat.com --- drivers/gpu/drm/i915/intel_ddi.c | 8 ++++++-- drivers/gpu/drm/i915/intel_dp_mst.c | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index a6672a9abd85..92cb26b18a9b 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2324,7 +2324,8 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder, intel_prepare_dp_ddi_buffers(encoder, crtc_state); intel_ddi_init_dp_buf_reg(encoder); - intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + if (!is_mst) + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_start_link_train(intel_dp); if (port != PORT_A || INTEL_GEN(dev_priv) >= 9) intel_dp_stop_link_train(intel_dp); @@ -2422,12 +2423,15 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); struct intel_dp *intel_dp = &dig_port->dp; + bool is_mst = intel_crtc_has_type(old_crtc_state, + INTEL_OUTPUT_DP_MST); /* * Power down sink before disabling the port, otherwise we end * up getting interrupts from the sink on detecting link loss. */ - intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); + if (!is_mst) + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); intel_disable_ddi_buf(encoder); diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index c3de0918ee13..9e6956c08688 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -180,9 +180,11 @@ static void intel_mst_post_disable_dp(struct intel_encoder *encoder, intel_dp->active_mst_links--; intel_mst->connector = NULL; - if (intel_dp->active_mst_links == 0) + if (intel_dp->active_mst_links == 0) { + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); intel_dig_port->base.post_disable(&intel_dig_port->base, old_crtc_state, NULL); + } DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links); } @@ -223,7 +225,11 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder, DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links); + if (intel_dp->active_mst_links == 0) + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, true); + if (intel_dp->active_mst_links == 0) intel_dig_port->base.pre_enable(&intel_dig_port->base, pipe_config, NULL); -- cgit v1.2.3 From 60f8e873307fd15bfb45f1895958cb04a2434e03 Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Mon, 9 Apr 2018 09:11:00 +0530 Subject: drm/i915/skl+: rename skl_wm_values struct to skl_ddb_values skl_wm_values struct contains values of pipe/plane DDB only. so rename it for better readability of code. Similarly skl_copy_wm_for_pipe copies DDB values. s/skl_wm_values/skl_ddb_values s/skl_copy_wm_for_pipe/skl_copy_ddb_for_pipe Changes since V1: - also change name of skl_copy_wm_for_pipe v2: Added reviewed by from Juha-Pekka Heikkila v3: Rebased the series Reviewed-by: Juha-Pekka Heikkila Reviewed-by: Maarten Lankhorst Signed-off-by: Mahesh Kumar Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-2-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_pm.c | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9bca104c409e..c1b89e9899b3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1186,7 +1186,7 @@ struct skl_ddb_allocation { struct skl_ddb_entry y_plane[I915_MAX_PIPES][I915_MAX_PLANES]; }; -struct skl_wm_values { +struct skl_ddb_values { unsigned dirty_pipes; struct skl_ddb_allocation ddb; }; @@ -1885,7 +1885,7 @@ struct drm_i915_private { /* current hardware state */ union { struct ilk_wm_values hw; - struct skl_wm_values skl_hw; + struct skl_ddb_values skl_hw; struct vlv_wm_values vlv; struct g4x_wm_values g4x; }; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 85e483e9a45b..d9a44ccdc837 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -482,7 +482,7 @@ struct intel_atomic_state { bool skip_intermediate_wm; /* Gen9+ only */ - struct skl_wm_values wm_results; + struct skl_ddb_values wm_results; struct i915_sw_fence commit_ready; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0d25e413ec0b..b7f6d8b8ff60 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5042,9 +5042,9 @@ skl_compute_ddb(struct drm_atomic_state *state) } static void -skl_copy_wm_for_pipe(struct skl_wm_values *dst, - struct skl_wm_values *src, - enum pipe pipe) +skl_copy_ddb_for_pipe(struct skl_ddb_values *dst, + struct skl_ddb_values *src, + enum pipe pipe) { memcpy(dst->ddb.y_plane[pipe], src->ddb.y_plane[pipe], sizeof(dst->ddb.y_plane[pipe])); @@ -5095,7 +5095,7 @@ skl_compute_wm(struct drm_atomic_state *state) struct drm_crtc *crtc; struct drm_crtc_state *cstate; struct intel_atomic_state *intel_state = to_intel_atomic_state(state); - struct skl_wm_values *results = &intel_state->wm_results; + struct skl_ddb_values *results = &intel_state->wm_results; struct drm_device *dev = state->dev; struct skl_pipe_wm *pipe_wm; bool changed = false; @@ -5197,8 +5197,8 @@ static void skl_initial_wm(struct intel_atomic_state *state, struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc); struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); - struct skl_wm_values *results = &state->wm_results; - struct skl_wm_values *hw_vals = &dev_priv->wm.skl_hw; + struct skl_ddb_values *results = &state->wm_results; + struct skl_ddb_values *hw_vals = &dev_priv->wm.skl_hw; enum pipe pipe = intel_crtc->pipe; if ((results->dirty_pipes & drm_crtc_mask(&intel_crtc->base)) == 0) @@ -5209,7 +5209,7 @@ static void skl_initial_wm(struct intel_atomic_state *state, if (cstate->base.active_changed) skl_atomic_update_crtc_wm(state, cstate); - skl_copy_wm_for_pipe(hw_vals, results, pipe); + skl_copy_ddb_for_pipe(hw_vals, results, pipe); mutex_unlock(&dev_priv->wm.wm_mutex); } @@ -5341,7 +5341,7 @@ void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc, void skl_wm_get_hw_state(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); - struct skl_wm_values *hw = &dev_priv->wm.skl_hw; + struct skl_ddb_values *hw = &dev_priv->wm.skl_hw; struct skl_ddb_allocation *ddb = &dev_priv->wm.skl_hw.ddb; struct drm_crtc *crtc; struct intel_crtc *intel_crtc; -- cgit v1.2.3 From b879d58ff31baf28c7d7d690c8da7978299fbe02 Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Mon, 9 Apr 2018 09:11:01 +0530 Subject: drm/i915/skl+: refactor WM calculation for NV12 Current code calculates DDB for planar formats in such a way that we store DDB of plane-0 in plane 1 & vice-versa. In order to make this clean this patch refactors WM/DDB calculation for NV12 planar formats. v2: Addressed review comments by Maarten v3: Rebased and addressed review comments by Maarten v4: Fixed a compilation issue of string replacement is_nv12 to is_planar v5: Added reviewed by from Juha-Pekka Heikkila v6: Rebased the series Reviewed-by: Juha-Pekka Heikkila Reviewed-by: Maarten Lankhorst Signed-off-by: Mahesh Kumar Signed-off-by: Vidya Srinivas Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-3-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 5 +- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 121 ++++++++++++++++++++------------------- 3 files changed, 66 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c1b89e9899b3..28fd200eb1fc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1182,8 +1182,9 @@ static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1, } struct skl_ddb_allocation { - struct skl_ddb_entry plane[I915_MAX_PIPES][I915_MAX_PLANES]; /* packed/uv */ - struct skl_ddb_entry y_plane[I915_MAX_PIPES][I915_MAX_PLANES]; + /* packed/y */ + struct skl_ddb_entry plane[I915_MAX_PIPES][I915_MAX_PLANES]; + struct skl_ddb_entry uv_plane[I915_MAX_PIPES][I915_MAX_PLANES]; }; struct skl_ddb_values { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d9a44ccdc837..626a46c11f50 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -603,6 +603,7 @@ struct intel_pipe_wm { struct skl_plane_wm { struct skl_wm_level wm[8]; struct skl_wm_level trans_wm; + bool is_planar; }; struct skl_pipe_wm { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b7f6d8b8ff60..fda22b1ae753 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4009,9 +4009,9 @@ int skl_check_pipe_max_pixel_rate(struct intel_crtc *intel_crtc, static unsigned int skl_plane_relative_data_rate(const struct intel_crtc_state *cstate, const struct drm_plane_state *pstate, - int y) + const int plane) { - struct intel_plane *plane = to_intel_plane(pstate->plane); + struct intel_plane *intel_plane = to_intel_plane(pstate->plane); struct intel_plane_state *intel_pstate = to_intel_plane_state(pstate); uint32_t data_rate; uint32_t width = 0, height = 0; @@ -4025,9 +4025,9 @@ skl_plane_relative_data_rate(const struct intel_crtc_state *cstate, fb = pstate->fb; format = fb->format->format; - if (plane->id == PLANE_CURSOR) + if (intel_plane->id == PLANE_CURSOR) return 0; - if (y && format != DRM_FORMAT_NV12) + if (plane == 1 && format != DRM_FORMAT_NV12) return 0; /* @@ -4038,19 +4038,14 @@ skl_plane_relative_data_rate(const struct intel_crtc_state *cstate, width = drm_rect_width(&intel_pstate->base.src) >> 16; height = drm_rect_height(&intel_pstate->base.src) >> 16; - /* for planar format */ - if (format == DRM_FORMAT_NV12) { - if (y) /* y-plane data rate */ - data_rate = width * height * - fb->format->cpp[0]; - else /* uv-plane data rate */ - data_rate = (width / 2) * (height / 2) * - fb->format->cpp[1]; - } else { - /* for packed formats */ - data_rate = width * height * fb->format->cpp[0]; + /* UV plane does 1/2 pixel sub-sampling */ + if (plane == 1 && format == DRM_FORMAT_NV12) { + width /= 2; + height /= 2; } + data_rate = width * height * fb->format->cpp[plane]; + down_scale_amount = skl_plane_downscale_amount(cstate, intel_pstate); return mul_round_up_u32_fixed16(data_rate, down_scale_amount); @@ -4063,8 +4058,8 @@ skl_plane_relative_data_rate(const struct intel_crtc_state *cstate, */ static unsigned int skl_get_total_relative_data_rate(struct intel_crtc_state *intel_cstate, - unsigned *plane_data_rate, - unsigned *plane_y_data_rate) + unsigned int *plane_data_rate, + unsigned int *uv_plane_data_rate) { struct drm_crtc_state *cstate = &intel_cstate->base; struct drm_atomic_state *state = cstate->state; @@ -4080,17 +4075,17 @@ skl_get_total_relative_data_rate(struct intel_crtc_state *intel_cstate, enum plane_id plane_id = to_intel_plane(plane)->id; unsigned int rate; - /* packed/uv */ + /* packed/y */ rate = skl_plane_relative_data_rate(intel_cstate, pstate, 0); plane_data_rate[plane_id] = rate; total_data_rate += rate; - /* y-plane */ + /* uv-plane */ rate = skl_plane_relative_data_rate(intel_cstate, pstate, 1); - plane_y_data_rate[plane_id] = rate; + uv_plane_data_rate[plane_id] = rate; total_data_rate += rate; } @@ -4099,8 +4094,7 @@ skl_get_total_relative_data_rate(struct intel_crtc_state *intel_cstate, } static uint16_t -skl_ddb_min_alloc(const struct drm_plane_state *pstate, - const int y) +skl_ddb_min_alloc(const struct drm_plane_state *pstate, const int plane) { struct drm_framebuffer *fb = pstate->fb; struct intel_plane_state *intel_pstate = to_intel_plane_state(pstate); @@ -4111,8 +4105,8 @@ skl_ddb_min_alloc(const struct drm_plane_state *pstate, if (WARN_ON(!fb)) return 0; - /* For packed formats, no y-plane, return 0 */ - if (y && fb->format->format != DRM_FORMAT_NV12) + /* For packed formats, and uv-plane, return 0 */ + if (plane == 1 && fb->format->format != DRM_FORMAT_NV12) return 0; /* For Non Y-tile return 8-blocks */ @@ -4131,15 +4125,12 @@ skl_ddb_min_alloc(const struct drm_plane_state *pstate, src_h = drm_rect_height(&intel_pstate->base.src) >> 16; /* Halve UV plane width and height for NV12 */ - if (fb->format->format == DRM_FORMAT_NV12 && !y) { + if (plane == 1) { src_w /= 2; src_h /= 2; } - if (fb->format->format == DRM_FORMAT_NV12 && !y) - plane_bpp = fb->format->cpp[1]; - else - plane_bpp = fb->format->cpp[0]; + plane_bpp = fb->format->cpp[plane]; if (drm_rotation_90_or_270(pstate->rotation)) { switch (plane_bpp) { @@ -4167,7 +4158,7 @@ skl_ddb_min_alloc(const struct drm_plane_state *pstate, static void skl_ddb_calc_min(const struct intel_crtc_state *cstate, int num_active, - uint16_t *minimum, uint16_t *y_minimum) + uint16_t *minimum, uint16_t *uv_minimum) { const struct drm_plane_state *pstate; struct drm_plane *plane; @@ -4182,7 +4173,7 @@ skl_ddb_calc_min(const struct intel_crtc_state *cstate, int num_active, continue; minimum[plane_id] = skl_ddb_min_alloc(pstate, 0); - y_minimum[plane_id] = skl_ddb_min_alloc(pstate, 1); + uv_minimum[plane_id] = skl_ddb_min_alloc(pstate, 1); } minimum[PLANE_CURSOR] = skl_cursor_allocation(num_active); @@ -4200,17 +4191,17 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, struct skl_ddb_entry *alloc = &cstate->wm.skl.ddb; uint16_t alloc_size, start; uint16_t minimum[I915_MAX_PLANES] = {}; - uint16_t y_minimum[I915_MAX_PLANES] = {}; + uint16_t uv_minimum[I915_MAX_PLANES] = {}; unsigned int total_data_rate; enum plane_id plane_id; int num_active; - unsigned plane_data_rate[I915_MAX_PLANES] = {}; - unsigned plane_y_data_rate[I915_MAX_PLANES] = {}; + unsigned int plane_data_rate[I915_MAX_PLANES] = {}; + unsigned int uv_plane_data_rate[I915_MAX_PLANES] = {}; uint16_t total_min_blocks = 0; /* Clear the partitioning for disabled planes. */ memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe])); - memset(ddb->y_plane[pipe], 0, sizeof(ddb->y_plane[pipe])); + memset(ddb->uv_plane[pipe], 0, sizeof(ddb->uv_plane[pipe])); if (WARN_ON(!state)) return 0; @@ -4225,7 +4216,7 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, if (alloc_size == 0) return 0; - skl_ddb_calc_min(cstate, num_active, minimum, y_minimum); + skl_ddb_calc_min(cstate, num_active, minimum, uv_minimum); /* * 1. Allocate the mininum required blocks for each active plane @@ -4235,7 +4226,7 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, for_each_plane_id_on_crtc(intel_crtc, plane_id) { total_min_blocks += minimum[plane_id]; - total_min_blocks += y_minimum[plane_id]; + total_min_blocks += uv_minimum[plane_id]; } if (total_min_blocks > alloc_size) { @@ -4257,14 +4248,14 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, */ total_data_rate = skl_get_total_relative_data_rate(cstate, plane_data_rate, - plane_y_data_rate); + uv_plane_data_rate); if (total_data_rate == 0) return 0; start = alloc->start; for_each_plane_id_on_crtc(intel_crtc, plane_id) { - unsigned int data_rate, y_data_rate; - uint16_t plane_blocks, y_plane_blocks = 0; + unsigned int data_rate, uv_data_rate; + uint16_t plane_blocks, uv_plane_blocks; if (plane_id == PLANE_CURSOR) continue; @@ -4288,21 +4279,20 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, start += plane_blocks; - /* - * allocation for y_plane part of planar format: - */ - y_data_rate = plane_y_data_rate[plane_id]; + /* Allocate DDB for UV plane for planar format/NV12 */ + uv_data_rate = uv_plane_data_rate[plane_id]; - y_plane_blocks = y_minimum[plane_id]; - y_plane_blocks += div_u64((uint64_t)alloc_size * y_data_rate, - total_data_rate); + uv_plane_blocks = uv_minimum[plane_id]; + uv_plane_blocks += div_u64((uint64_t)alloc_size * uv_data_rate, + total_data_rate); - if (y_data_rate) { - ddb->y_plane[pipe][plane_id].start = start; - ddb->y_plane[pipe][plane_id].end = start + y_plane_blocks; + if (uv_data_rate) { + ddb->uv_plane[pipe][plane_id].start = start; + ddb->uv_plane[pipe][plane_id].end = + start + uv_plane_blocks; } - start += y_plane_blocks; + start += uv_plane_blocks; } return 0; @@ -4430,8 +4420,7 @@ skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv, wp->width = drm_rect_width(&intel_pstate->base.src) >> 16; } - wp->cpp = (fb->format->format == DRM_FORMAT_NV12) ? fb->format->cpp[1] : - fb->format->cpp[0]; + wp->cpp = fb->format->cpp[0]; wp->plane_pixel_rate = skl_adjusted_plane_pixel_rate(cstate, intel_pstate); @@ -4660,6 +4649,9 @@ skl_compute_wm_levels(const struct drm_i915_private *dev_priv, return ret; } + if (intel_pstate->base.fb->format->format == DRM_FORMAT_NV12) + wm->is_planar = true; + return 0; } @@ -4833,10 +4825,21 @@ 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]); - if (INTEL_GEN(dev_priv) < 11) + if (INTEL_GEN(dev_priv) >= 11) + return skl_ddb_entry_write(dev_priv, + PLANE_BUF_CFG(pipe, plane_id), + &ddb->plane[pipe][plane_id]); + if (wm->is_planar) { + skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id), + &ddb->uv_plane[pipe][plane_id]); skl_ddb_entry_write(dev_priv, PLANE_NV12_BUF_CFG(pipe, plane_id), - &ddb->y_plane[pipe][plane_id]); + &ddb->plane[pipe][plane_id]); + } else { + skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id), + &ddb->plane[pipe][plane_id]); + I915_WRITE(PLANE_NV12_BUF_CFG(pipe, plane_id), 0x0); + } } static void skl_write_cursor_wm(struct intel_crtc *intel_crtc, @@ -4951,8 +4954,8 @@ skl_ddb_add_affected_planes(struct intel_crtc_state *cstate) if (skl_ddb_entry_equal(&cur_ddb->plane[pipe][plane_id], &new_ddb->plane[pipe][plane_id]) && - skl_ddb_entry_equal(&cur_ddb->y_plane[pipe][plane_id], - &new_ddb->y_plane[pipe][plane_id])) + skl_ddb_entry_equal(&cur_ddb->uv_plane[pipe][plane_id], + &new_ddb->uv_plane[pipe][plane_id])) continue; plane_state = drm_atomic_get_plane_state(state, plane); @@ -5046,8 +5049,8 @@ skl_copy_ddb_for_pipe(struct skl_ddb_values *dst, struct skl_ddb_values *src, enum pipe pipe) { - memcpy(dst->ddb.y_plane[pipe], src->ddb.y_plane[pipe], - sizeof(dst->ddb.y_plane[pipe])); + memcpy(dst->ddb.uv_plane[pipe], src->ddb.uv_plane[pipe], + sizeof(dst->ddb.uv_plane[pipe])); memcpy(dst->ddb.plane[pipe], src->ddb.plane[pipe], sizeof(dst->ddb.plane[pipe])); } -- cgit v1.2.3 From f34a291c0a9f141728b2ad852066322ca38d3cdb Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Mon, 9 Apr 2018 09:11:02 +0530 Subject: drm/i915/skl+: add NV12 in skl_format_to_fourcc Add support of recognizing DRM_FORMAT_NV12 from plane_format register value. v2: Added reviewed by tag from Mika Kahola v3: Added reviewed by from Juha-Pekka Heikkila v4: Rebased the series Reviewed-by: Juha-Pekka Heikkila Reviewed-by: Mika Kahola Reviewed-by: Maarten Lankhorst Signed-off-by: Mahesh Kumar Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-4-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/intel_display.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6de2e1b1a4a7..fa78f2590eea 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2662,6 +2662,8 @@ static int skl_format_to_fourcc(int format, bool rgb_order, bool alpha) switch (format) { case PLANE_CTL_FORMAT_RGB_565: return DRM_FORMAT_RGB565; + case PLANE_CTL_FORMAT_NV12: + return DRM_FORMAT_NV12; default: case PLANE_CTL_FORMAT_XRGB_8888: if (rgb_order) { -- cgit v1.2.3 From ddf343191420e88479027fec9dc8efc0cafb63ef Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Mon, 9 Apr 2018 09:11:03 +0530 Subject: drm/i915/skl+: support verification of DDB HW state for NV12 For YUV 420 Planar formats like NV12, buffer allocation is done for Y and UV surfaces separately. For NV12 plane formats, the UV buffer allocation must be programmed in the Plane Buffer Config register and the Y buffer allocation must be programmed in the Plane NV12 Buffer Config register. Both register values should be verified during verify_wm_state. v2: Addressed review comments by Maarten. v3: Addressed review comments by Shashank Sharma. v4: Adding reviewed by tag from Shashank Sharma v5: Added reviewed by from Juha-Pekka Heikkila v6: Rebased the series Reviewed-by: Juha-Pekka Heikkila Reviewed-by: Shashank Sharma Signed-off-by: Mahesh Kumar Reviewed-by: Maarten Lankhorst Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-5-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 51 +++++++++++++++++++++++++++++------- 3 files changed, 43 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fa78f2590eea..057f3cf95e86 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2657,7 +2657,7 @@ static int i9xx_format_to_fourcc(int format) } } -static int skl_format_to_fourcc(int format, bool rgb_order, bool alpha) +int skl_format_to_fourcc(int format, bool rgb_order, bool alpha) { switch (format) { case PLANE_CTL_FORMAT_RGB_565: diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 626a46c11f50..4eeaca350411 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1613,6 +1613,7 @@ u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane, 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); +int skl_format_to_fourcc(int format, bool rgb_order, bool alpha); /* intel_csr.c */ void intel_csr_ucode_init(struct drm_i915_private *); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index fda22b1ae753..d22d9b2cbc62 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3825,6 +3825,44 @@ static void skl_ddb_entry_init_from_hw(struct skl_ddb_entry *entry, u32 reg) entry->end += 1; } +static void +skl_ddb_get_hw_plane_state(struct drm_i915_private *dev_priv, + const enum pipe pipe, + const enum plane_id plane_id, + struct skl_ddb_allocation *ddb /* out */) +{ + u32 val, val2 = 0; + int fourcc, pixel_format; + + /* Cursor doesn't support NV12/planar, so no extra calculation needed */ + if (plane_id == PLANE_CURSOR) { + val = I915_READ(CUR_BUF_CFG(pipe)); + skl_ddb_entry_init_from_hw(&ddb->plane[pipe][plane_id], val); + return; + } + + val = I915_READ(PLANE_CTL(pipe, plane_id)); + + /* No DDB allocated for disabled planes */ + if (!(val & PLANE_CTL_ENABLE)) + return; + + pixel_format = val & PLANE_CTL_FORMAT_MASK; + fourcc = skl_format_to_fourcc(pixel_format, + val & PLANE_CTL_ORDER_RGBX, + val & PLANE_CTL_ALPHA_MASK); + + val = I915_READ(PLANE_BUF_CFG(pipe, plane_id)); + val2 = I915_READ(PLANE_NV12_BUF_CFG(pipe, plane_id)); + + if (fourcc == DRM_FORMAT_NV12) { + skl_ddb_entry_init_from_hw(&ddb->plane[pipe][plane_id], val2); + skl_ddb_entry_init_from_hw(&ddb->uv_plane[pipe][plane_id], val); + } else { + skl_ddb_entry_init_from_hw(&ddb->plane[pipe][plane_id], val); + } +} + void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, struct skl_ddb_allocation *ddb /* out */) { @@ -3841,16 +3879,9 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) continue; - for_each_plane_id_on_crtc(crtc, plane_id) { - u32 val; - - if (plane_id != PLANE_CURSOR) - val = I915_READ(PLANE_BUF_CFG(pipe, plane_id)); - else - val = I915_READ(CUR_BUF_CFG(pipe)); - - skl_ddb_entry_init_from_hw(&ddb->plane[pipe][plane_id], val); - } + for_each_plane_id_on_crtc(crtc, plane_id) + skl_ddb_get_hw_plane_state(dev_priv, pipe, + plane_id, ddb); intel_display_power_put(dev_priv, power_domain); } -- cgit v1.2.3 From 942aa2d0503d483562795d8f4c0957e13bd4b59d Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Mon, 9 Apr 2018 09:11:04 +0530 Subject: drm/i915/skl+: NV12 related changes for WM NV12 requires WM calculation for UV plane as well. UV plane WM should also fulfill all the WM related restrictions. v2: Addressed review comments from Shashank Sharma. v3: Addressed review comments from Shashank Sharma Changed plane_num to plane_id in skl_compute_plane_wm_params and skl_compute_plane_wm. Adding reviewed by tag from Shashank Sharma v4: Added reviewed by from Juha-Pekka Heikkila v5: Rebased the series Reviewed-by: Juha-Pekka Heikkila Reviewed-by: Shashank Sharma Signed-off-by: Mahesh Kumar Signed-off-by: Vidya Srinivas Reviewed-by: Maarten Lankhorst Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-6-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 50 +++++++++++++++++++++++++++++++++------- 3 files changed, 44 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 28fd200eb1fc..ba4a82193246 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1202,6 +1202,7 @@ struct skl_wm_level { struct skl_wm_params { bool x_tiled, y_tiled; bool rc_surface; + bool is_planar; uint32_t width; uint8_t cpp; uint32_t plane_pixel_rate; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4eeaca350411..2c3c40d12136 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -602,6 +602,7 @@ struct intel_pipe_wm { struct skl_plane_wm { struct skl_wm_level wm[8]; + struct skl_wm_level uv_wm[8]; struct skl_wm_level trans_wm; bool is_planar; }; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d22d9b2cbc62..fb30efa22c24 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4419,7 +4419,7 @@ static int skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv, struct intel_crtc_state *cstate, const struct intel_plane_state *intel_pstate, - struct skl_wm_params *wp) + struct skl_wm_params *wp, int plane_id) { struct intel_plane *plane = to_intel_plane(intel_pstate->base.plane); const struct drm_plane_state *pstate = &intel_pstate->base; @@ -4432,6 +4432,12 @@ skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv, if (!intel_wm_plane_visible(cstate, intel_pstate)) return 0; + /* only NV12 format has two planes */ + if (plane_id == 1 && fb->format->format != DRM_FORMAT_NV12) { + DRM_DEBUG_KMS("Non NV12 format have single plane\n"); + return -EINVAL; + } + wp->y_tiled = fb->modifier == I915_FORMAT_MOD_Y_TILED || fb->modifier == I915_FORMAT_MOD_Yf_TILED || fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS || @@ -4439,6 +4445,7 @@ skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv, wp->x_tiled = fb->modifier == I915_FORMAT_MOD_X_TILED; wp->rc_surface = fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS || fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS; + wp->is_planar = fb->format->format == DRM_FORMAT_NV12; if (plane->id == PLANE_CURSOR) { wp->width = intel_pstate->base.crtc_w; @@ -4451,7 +4458,10 @@ skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv, wp->width = drm_rect_width(&intel_pstate->base.src) >> 16; } - wp->cpp = fb->format->cpp[0]; + if (plane_id == 1 && wp->is_planar) + wp->width /= 2; + + wp->cpp = fb->format->cpp[plane_id]; wp->plane_pixel_rate = skl_adjusted_plane_pixel_rate(cstate, intel_pstate); @@ -4649,7 +4659,8 @@ skl_compute_wm_levels(const struct drm_i915_private *dev_priv, struct intel_crtc_state *cstate, const struct intel_plane_state *intel_pstate, const struct skl_wm_params *wm_params, - struct skl_plane_wm *wm) + struct skl_plane_wm *wm, + int plane_id) { struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc); struct drm_plane *plane = intel_pstate->base.plane; @@ -4657,15 +4668,19 @@ skl_compute_wm_levels(const struct drm_i915_private *dev_priv, uint16_t ddb_blocks; enum pipe pipe = intel_crtc->pipe; int level, max_level = ilk_wm_max_level(dev_priv); + enum plane_id intel_plane_id = intel_plane->id; int ret; if (WARN_ON(!intel_pstate->base.fb)) return -EINVAL; - ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][intel_plane->id]); + ddb_blocks = plane_id ? + skl_ddb_entry_size(&ddb->uv_plane[pipe][intel_plane_id]) : + skl_ddb_entry_size(&ddb->plane[pipe][intel_plane_id]); for (level = 0; level <= max_level; level++) { - struct skl_wm_level *result = &wm->wm[level]; + struct skl_wm_level *result = plane_id ? &wm->uv_wm[level] : + &wm->wm[level]; ret = skl_compute_plane_wm(dev_priv, cstate, @@ -4792,20 +4807,39 @@ static int skl_build_pipe_wm(struct intel_crtc_state *cstate, wm = &pipe_wm->planes[plane_id]; ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][plane_id]); - memset(&wm_params, 0, sizeof(struct skl_wm_params)); ret = skl_compute_plane_wm_params(dev_priv, cstate, - intel_pstate, &wm_params); + intel_pstate, &wm_params, 0); if (ret) return ret; ret = skl_compute_wm_levels(dev_priv, ddb, cstate, - intel_pstate, &wm_params, wm); + intel_pstate, &wm_params, wm, 0); if (ret) return ret; + skl_compute_transition_wm(cstate, &wm_params, &wm->wm[0], ddb_blocks, &wm->trans_wm); + + /* uv plane watermarks must also be validated for NV12/Planar */ + if (wm_params.is_planar) { + memset(&wm_params, 0, sizeof(struct skl_wm_params)); + wm->is_planar = true; + + ret = skl_compute_plane_wm_params(dev_priv, cstate, + intel_pstate, + &wm_params, 1); + if (ret) + return ret; + + ret = skl_compute_wm_levels(dev_priv, ddb, cstate, + intel_pstate, &wm_params, + wm, 1); + if (ret) + return ret; + } } + pipe_wm->linetime = skl_compute_linetime_wm(cstate); return 0; -- cgit v1.2.3 From 62027b7736d038309e93e6d5d25a9a72390821cb Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Mon, 9 Apr 2018 09:11:05 +0530 Subject: drm/i915/skl+: pass skl_wm_level struct to wm compute func This patch passes skl_wm_level structure itself to watermark computation function skl_compute_plane_wm function (instead of its internal parameters). It reduces number of arguments required to be passed. v2: Addressed review comments by Shashank Sharma v3: Adding reviewed by tag from Shashank Sharma v4: Added reviewed by from Juha-Pekka Heikkila v5: Rebased the series Reviewed-by: Juha-Pekka Heikkila Reviewed-by: Shashank Sharma Signed-off-by: Mahesh Kumar Signed-off-by: Vidya Srinivas Reviewed-by: Maarten Lankhorst Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-7-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/intel_pm.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index fb30efa22c24..06352c9e9ef6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4529,9 +4529,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, uint16_t ddb_allocation, int level, const struct skl_wm_params *wp, - uint16_t *out_blocks, /* out */ - uint8_t *out_lines, /* out */ - bool *enabled /* out */) + struct skl_wm_level *result /* out */) { const struct drm_plane_state *pstate = &intel_pstate->base; uint32_t latency = dev_priv->wm.skl_latency[level]; @@ -4545,7 +4543,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, if (latency == 0 || !intel_wm_plane_visible(cstate, intel_pstate)) { - *enabled = false; + result->plane_en = false; return 0; } @@ -4626,7 +4624,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, if ((level > 0 && res_lines > 31) || res_blocks >= ddb_allocation || min_disp_buf_needed >= ddb_allocation) { - *enabled = false; + result->plane_en = false; /* * If there are no valid level 0 watermarks, then we can't @@ -4646,9 +4644,9 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, } /* The number of lines are ignored for the level 0 watermark. */ - *out_lines = level ? res_lines : 0; - *out_blocks = res_blocks; - *enabled = true; + result->plane_res_b = res_blocks; + result->plane_res_l = res_lines; + result->plane_en = true; return 0; } @@ -4688,9 +4686,7 @@ skl_compute_wm_levels(const struct drm_i915_private *dev_priv, ddb_blocks, level, wm_params, - &result->plane_res_b, - &result->plane_res_l, - &result->plane_en); + result); if (ret) return ret; } -- cgit v1.2.3 From 8b2b53ce94e808ef9340add94c4c50b9e5267413 Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Mon, 9 Apr 2018 09:11:06 +0530 Subject: drm/i915/skl+: make sure higher latency level has higher wm value DDB allocation optimization algorithm requires/assumes ddb allocation for any memory C-state level DDB value to be as high as level below the current level. Render decompression requires level WM to be as high as wm level-0. This patch fulfils both the requirements. v2: Changed plane_num to plane_id in skl_compute_wm_levels v3: Addressed review comments from Shashank Sharma Changed the commit message "statement can be more clear, "DDB value to be as high as level below " what is level below ?" v4: Added reviewed by tag from Shashank Sharma v5: Added reviewed by from Juha-Pekka Heikkila v6: Rebased the series Reviewed-by: Juha-Pekka Heikkila Reviewed-by: Shashank Sharma Signed-off-by: Mahesh Kumar Reviewed-by: Maarten Lankhorst Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-8-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/intel_pm.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 06352c9e9ef6..707843012dff 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4529,6 +4529,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, uint16_t ddb_allocation, int level, const struct skl_wm_params *wp, + const struct skl_wm_level *result_prev, struct skl_wm_level *result /* out */) { const struct drm_plane_state *pstate = &intel_pstate->base; @@ -4596,6 +4597,15 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, } else { res_blocks++; } + + /* + * Make sure result blocks for higher latency levels are atleast + * as high as level below the current level. + * Assumption in DDB algorithm optimization for special cases. + * Also covers Display WA #1125 for RC. + */ + if (result_prev->plane_res_b > res_blocks) + res_blocks = result_prev->plane_res_b; } if (INTEL_GEN(dev_priv) >= 11) { @@ -4679,6 +4689,13 @@ skl_compute_wm_levels(const struct drm_i915_private *dev_priv, for (level = 0; level <= max_level; level++) { struct skl_wm_level *result = plane_id ? &wm->uv_wm[level] : &wm->wm[level]; + struct skl_wm_level *result_prev; + + if (level) + result_prev = plane_id ? &wm->uv_wm[level - 1] : + &wm->wm[level - 1]; + else + result_prev = plane_id ? &wm->uv_wm[0] : &wm->wm[0]; ret = skl_compute_plane_wm(dev_priv, cstate, @@ -4686,6 +4703,7 @@ skl_compute_wm_levels(const struct drm_i915_private *dev_priv, ddb_blocks, level, wm_params, + result_prev, result); if (ret) return ret; -- cgit v1.2.3 From 08d0e875aefe72c63076a768a368126ea74a1e3e Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Mon, 9 Apr 2018 09:11:07 +0530 Subject: drm/i915/skl+: nv12 workaround disable WM level 1-7 Display Workaround #0826 (SKL:ALL BXT:ALL) & #1059(CNL:A) Hardware sometimes fails to wake memory from pkg C states fetching the last few lines of planar YUV 420 (NV12) planes. This causes intermittent underflow and corruption. WA: Disable package C states or do not enable latency levels 1 through 7 (WM1 - WM7) on NV12 planes. v2: Addressed review comments by Maarten. v3: Adding reviewed by tag from Shashank Sharma v4: Added reviewed by from Juha-Pekka Heikkila v5: Rebased the series Reviewed-by: Juha-Pekka Heikkila Reviewed-by: Shashank Sharma Reviewed-by: Maarten Lankhorst Signed-off-by: Mahesh Kumar Signed-off-by: Vidya Srinivas Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-9-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/intel_pm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 707843012dff..9d5a7b3e9716 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4653,6 +4653,17 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, } } + /* + * Display WA #826 (SKL:ALL, BXT:ALL) & #1059 (CNL:A) + * disable wm level 1-7 on NV12 planes + */ + if (wp->is_planar && level >= 1 && + (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv) || + IS_CNL_REVID(dev_priv, CNL_REVID_A0, CNL_REVID_A0))) { + result->plane_en = false; + return 0; + } + /* The number of lines are ignored for the level 0 watermark. */ result->plane_res_b = res_blocks; result->plane_res_l = res_lines; -- cgit v1.2.3 From e1f96a66e72569f6277262eef23614236cc6dc15 Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Date: Mon, 9 Apr 2018 09:11:08 +0530 Subject: drm/i915/skl: split skl_compute_ddb function This patch splits skl_compute_wm/ddb functions into two parts. One adds all affected pipes after the commit to atomic_state structure and second part does compute the DDB. v2: Added reviewed by tag from Shashank Sharma v3: Added reviewed by from Juha-Pekka Heikkila v4: Rebased the series v5: Fixed checkpatch error. Changed *changed = true to (*changed) = true; Reviewed-by: Juha-Pekka Heikkila Reviewed-by: Shashank Sharma Signed-off-by: Mahesh Kumar Signed-off-by: Vidya Srinivas Reviewed-by: Maarten Lankhorst Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-10-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/intel_pm.c | 157 ++++++++++++++++++++++------------------ 1 file changed, 88 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9d5a7b3e9716..007a12ebe725 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5059,69 +5059,16 @@ skl_ddb_add_affected_planes(struct intel_crtc_state *cstate) static int skl_compute_ddb(struct drm_atomic_state *state) { - struct drm_device *dev = state->dev; - struct drm_i915_private *dev_priv = to_i915(dev); + const struct drm_i915_private *dev_priv = to_i915(state->dev); struct intel_atomic_state *intel_state = to_intel_atomic_state(state); - struct intel_crtc *intel_crtc; struct skl_ddb_allocation *ddb = &intel_state->wm_results.ddb; - uint32_t realloc_pipes = pipes_modified(state); - int ret; - - /* - * If this is our first atomic update following hardware readout, - * we can't trust the DDB that the BIOS programmed for us. Let's - * pretend that all pipes switched active status so that we'll - * ensure a full DDB recompute. - */ - if (dev_priv->wm.distrust_bios_wm) { - ret = drm_modeset_lock(&dev->mode_config.connection_mutex, - state->acquire_ctx); - if (ret) - return ret; - - intel_state->active_pipe_changes = ~0; - - /* - * We usually only initialize intel_state->active_crtcs if we - * we're doing a modeset; make sure this field is always - * initialized during the sanitization process that happens - * on the first commit too. - */ - if (!intel_state->modeset) - intel_state->active_crtcs = dev_priv->active_crtcs; - } - - /* - * If the modeset changes which CRTC's are active, we need to - * recompute the DDB allocation for *all* active pipes, even - * those that weren't otherwise being modified in any way by this - * atomic commit. Due to the shrinking of the per-pipe allocations - * when new active CRTC's are added, it's possible for a pipe that - * we were already using and aren't changing at all here to suddenly - * become invalid if its DDB needs exceeds its new allocation. - * - * Note that if we wind up doing a full DDB recompute, we can't let - * any other display updates race with this transaction, so we need - * to grab the lock on *all* CRTC's. - */ - if (intel_state->active_pipe_changes) { - realloc_pipes = ~0; - intel_state->wm_results.dirty_pipes = ~0; - } + struct intel_crtc *crtc; + struct intel_crtc_state *cstate; + int ret, i; - /* - * We're not recomputing for the pipes not included in the commit, so - * make sure we start with the current state. - */ memcpy(ddb, &dev_priv->wm.skl_hw.ddb, sizeof(*ddb)); - for_each_intel_crtc_mask(dev, intel_crtc, realloc_pipes) { - struct intel_crtc_state *cstate; - - cstate = intel_atomic_get_crtc_state(state, intel_crtc); - if (IS_ERR(cstate)) - return PTR_ERR(cstate); - + for_each_new_intel_crtc_in_state(intel_state, crtc, cstate, i) { ret = skl_allocate_pipe_ddb(cstate, ddb); if (ret) return ret; @@ -5183,23 +5130,23 @@ skl_print_wm_changes(const struct drm_atomic_state *state) } static int -skl_compute_wm(struct drm_atomic_state *state) +skl_ddb_add_affected_pipes(struct drm_atomic_state *state, bool *changed) { - struct drm_crtc *crtc; - struct drm_crtc_state *cstate; - struct intel_atomic_state *intel_state = to_intel_atomic_state(state); - struct skl_ddb_values *results = &intel_state->wm_results; struct drm_device *dev = state->dev; - struct skl_pipe_wm *pipe_wm; - bool changed = false; + const struct drm_i915_private *dev_priv = to_i915(dev); + const struct drm_crtc *crtc; + const struct drm_crtc_state *cstate; + struct intel_crtc *intel_crtc; + struct intel_atomic_state *intel_state = to_intel_atomic_state(state); + uint32_t realloc_pipes = pipes_modified(state); int ret, i; /* * When we distrust bios wm we always need to recompute to set the * expected DDB allocations for each CRTC. */ - if (to_i915(dev)->wm.distrust_bios_wm) - changed = true; + if (dev_priv->wm.distrust_bios_wm) + (*changed) = true; /* * If this transaction isn't actually touching any CRTC's, don't @@ -5210,14 +5157,86 @@ skl_compute_wm(struct drm_atomic_state *state) * hold _all_ CRTC state mutexes. */ for_each_new_crtc_in_state(state, crtc, cstate, i) - changed = true; + (*changed) = true; - if (!changed) + if (!*changed) return 0; + /* + * If this is our first atomic update following hardware readout, + * we can't trust the DDB that the BIOS programmed for us. Let's + * pretend that all pipes switched active status so that we'll + * ensure a full DDB recompute. + */ + if (dev_priv->wm.distrust_bios_wm) { + ret = drm_modeset_lock(&dev->mode_config.connection_mutex, + state->acquire_ctx); + if (ret) + return ret; + + intel_state->active_pipe_changes = ~0; + + /* + * We usually only initialize intel_state->active_crtcs if we + * we're doing a modeset; make sure this field is always + * initialized during the sanitization process that happens + * on the first commit too. + */ + if (!intel_state->modeset) + intel_state->active_crtcs = dev_priv->active_crtcs; + } + + /* + * If the modeset changes which CRTC's are active, we need to + * recompute the DDB allocation for *all* active pipes, even + * those that weren't otherwise being modified in any way by this + * atomic commit. Due to the shrinking of the per-pipe allocations + * when new active CRTC's are added, it's possible for a pipe that + * we were already using and aren't changing at all here to suddenly + * become invalid if its DDB needs exceeds its new allocation. + * + * Note that if we wind up doing a full DDB recompute, we can't let + * any other display updates race with this transaction, so we need + * to grab the lock on *all* CRTC's. + */ + if (intel_state->active_pipe_changes) { + realloc_pipes = ~0; + intel_state->wm_results.dirty_pipes = ~0; + } + + /* + * We're not recomputing for the pipes not included in the commit, so + * make sure we start with the current state. + */ + for_each_intel_crtc_mask(dev, intel_crtc, realloc_pipes) { + struct intel_crtc_state *cstate; + + cstate = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(cstate)) + return PTR_ERR(cstate); + } + + return 0; +} + +static int +skl_compute_wm(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *cstate; + struct intel_atomic_state *intel_state = to_intel_atomic_state(state); + struct skl_ddb_values *results = &intel_state->wm_results; + struct skl_pipe_wm *pipe_wm; + bool changed = false; + int ret, i; + /* Clear all dirty flags */ results->dirty_pipes = 0; + ret = skl_ddb_add_affected_pipes(state, &changed); + if (ret || !changed) + return ret; + ret = skl_compute_ddb(state); if (ret) return ret; -- cgit v1.2.3 From c4a4efa91737e61b3334642a61659fd64d7e31d6 Mon Sep 17 00:00:00 2001 From: Vidya Srinivas Date: Mon, 9 Apr 2018 09:11:09 +0530 Subject: drm/i915: Display WA 827 Display WA 827 applies to GEN9 (excluede GLK) and CNL. Switching the plane format from NV12 to RGB and leaving system idle results in display underrun and corruption. WA: Set the bit 15 & bit 19 to 1b in the CLKGATE_DIS_PSL register for the pipe in which NV12 plane is enabled. v2: Addressed review comments from Maarten and Juha-Pekka Heikkila. Added reviewed by from Juha-Pekka Heikkila. v3: Rebased the series Reviewed-by: Juha-Pekka Heikkila Signed-off-by: Chandra Konduru Signed-off-by: Nabendu Maiti Signed-off-by: Vidya Srinivas Reviewed-by: Maarten Lankhorst Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-11-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_display.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b3a6428aa71d..1f858e2c85f0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3824,6 +3824,9 @@ enum { #define _CLKGATE_DIS_PSL_A 0x46520 #define _CLKGATE_DIS_PSL_B 0x46524 #define _CLKGATE_DIS_PSL_C 0x46528 +#define DUPS1_GATING_DIS (1 << 15) +#define DUPS2_GATING_DIS (1 << 19) +#define DUPS3_GATING_DIS (1 << 23) #define DPF_GATING_DIS (1 << 10) #define DPF_RAM_GATING_DIS (1 << 9) #define DPFR_GATING_DIS (1 << 8) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 057f3cf95e86..466d2479a8fb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -488,6 +488,21 @@ static const struct intel_limit intel_limits_bxt = { .p2 = { .p2_slow = 1, .p2_fast = 20 }, }; +static void +skl_wa_clkgate(struct drm_i915_private *dev_priv, int pipe, bool enable) +{ + if (IS_SKYLAKE(dev_priv)) + return; + + if (enable) + I915_WRITE(CLKGATE_DIS_PSL(pipe), + DUPS1_GATING_DIS | DUPS2_GATING_DIS); + else + I915_WRITE(CLKGATE_DIS_PSL(pipe), + I915_READ(CLKGATE_DIS_PSL(pipe)) & + ~(DUPS1_GATING_DIS | DUPS2_GATING_DIS)); +} + static bool needs_modeset(const struct drm_crtc_state *state) { @@ -5103,6 +5118,8 @@ static bool hsw_post_update_enable_ips(const struct intel_crtc_state *old_crtc_s static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state) { struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc); + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); struct drm_atomic_state *old_state = old_crtc_state->base.state; struct intel_crtc_state *pipe_config = intel_atomic_get_new_crtc_state(to_intel_atomic_state(old_state), @@ -5125,6 +5142,7 @@ static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state) to_intel_plane(primary)); struct intel_plane_state *old_primary_state = to_intel_plane_state(old_pri_state); + struct drm_framebuffer *fb = primary_state->base.fb; intel_fbc_post_update(crtc); @@ -5132,6 +5150,14 @@ static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state) (needs_modeset(&pipe_config->base) || !old_primary_state->base.visible)) intel_post_enable_primary(&crtc->base, pipe_config); + + /* Display WA 827 */ + if ((INTEL_GEN(dev_priv) == 9 && !IS_GEMINILAKE(dev_priv)) || + IS_CANNONLAKE(dev_priv)) { + if (fb && fb->format->format == DRM_FORMAT_NV12) + skl_wa_clkgate(dev_priv, crtc->pipe, false); + } + } } @@ -5158,6 +5184,14 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state, to_intel_plane(primary)); struct intel_plane_state *old_primary_state = to_intel_plane_state(old_pri_state); + struct drm_framebuffer *fb = primary_state->base.fb; + + /* Display WA 827 */ + if ((INTEL_GEN(dev_priv) == 9 && !IS_GEMINILAKE(dev_priv)) || + IS_CANNONLAKE(dev_priv)) { + if (fb && fb->format->format == DRM_FORMAT_NV12) + skl_wa_clkgate(dev_priv, crtc->pipe, true); + } intel_fbc_pre_update(crtc, pipe_config, primary_state); /* -- cgit v1.2.3 From 8ed30ab6acede16996ac140c45271f6b61a753a8 Mon Sep 17 00:00:00 2001 From: Vidya Srinivas Date: Mon, 9 Apr 2018 09:11:10 +0530 Subject: drm/i915: Enable YUV to RGB for Gen10 in Plane Ctrl Reg If the fb format is YUV, enable the plane CSC mode bits for the conversion. v2: Addressed review comments from Shashank Sharma Alignment issue fixed in i915_reg.h v3: Adding Reviewed By from Shashank Sharma v4: Rebased the patch. As part of rebasing, re-using the color series defines which are already merged. plane_state->base.color_encoding might not be set for NV12. For now, just using PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709 in glk_plane_color_ctl if format is NV12. v5: Added reviewed by from Juha-Pekka Heikkila v6: Rebased the series Reviewed-by: Shashank Sharma Reviewed-by: Juha-Pekka Heikkila Signed-off-by: Vidya Srinivas Reviewed-by: Maarten Lankhorst Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-12-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/intel_display.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 466d2479a8fb..eb9d4e7f9160 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3630,6 +3630,11 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, plane_color_ctl |= glk_plane_color_ctl_alpha(fb->format->format); if (intel_format_is_yuv(fb->format->format)) { + if (fb->format->format == DRM_FORMAT_NV12) { + plane_color_ctl |= + PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; + goto out; + } if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; else @@ -3638,7 +3643,7 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE) plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE; } - +out: return plane_color_ctl; } -- cgit v1.2.3 From e6e1948c9fabe1a83c0c033ea6e5d83dfce8f38b Mon Sep 17 00:00:00 2001 From: Chandra Konduru Date: Mon, 9 Apr 2018 09:11:11 +0530 Subject: drm/i915: Set scaler mode for NV12 This patch sets appropriate scaler mode for NV12 format. In this mode, skylake scaler does either chroma-upsampling or chroma-upsampling and resolution scaling v2: Review comments from Ville addressed NV12 case to be checked first for setting the scaler v3: Rebased (me) v4: Rebased (me) v5: Missed the Tested-by/Reviewed-by in the previous series Adding the same to commit message in this version. v6: Rebased (me) v7: Rebased (me) v8: Rebased (me) Restricting the NV12 change for scaler to BXT and KBL in this series. v9: Rebased (me) v10: As of now, NV12 has been tested on Gen9 and Gen10. However, code is applicable to all GEN >= 9. Hence making that change to keep it generic. Comments under v8 is not valid anymore. v11: Addressed review comments by Shashank Sharma. For Gen10+, the scaler mode to be set it planar or normal (single bit). Changed the code to be applicable to all Gen. v12: Addressed review comments from Shashank Sharma For Gen9 (apart from GLK) bits 28:29 to be programmed in PS_CTRL for NV12. For GLK and Gen10+, bit 29 to be set for all Planar. v13: Addressed review comments from Juha-Pekka Heikkila "NV12 not to be supported by SKL" Adding Reviewed by tag from Shashank Shamr v14: Added reviewed by from Juha-Pekka Heikkila v15: Rebased the series Tested-by: Clinton Taylor Reviewed-by: Juha-Pekka Heikkila Reviewed-by: Shashank Sharma Reviewed-by: Clinton Taylor Signed-off-by: Chandra Konduru Signed-off-by: Nabendu Maiti Signed-off-by: Vidya Srinivas Reviewed-by: Maarten Lankhorst Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-13-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_atomic.c | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1f858e2c85f0..fb106026a1f4 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6664,6 +6664,8 @@ enum { #define PS_SCALER_MODE_MASK (3 << 28) #define PS_SCALER_MODE_DYN (0 << 28) #define PS_SCALER_MODE_HQ (1 << 28) +#define SKL_PS_SCALER_MODE_NV12 (2 << 28) +#define PS_SCALER_MODE_PLANAR (1 << 29) #define PS_PLANE_SEL_MASK (7 << 25) #define PS_PLANE_SEL(plane) (((plane) + 1) << 25) #define PS_FILTER_MASK (3 << 23) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index e9fb692076d7..bb8c1687823e 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -328,8 +328,18 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv, } /* set scaler mode */ - if (IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) { - scaler_state->scalers[*scaler_id].mode = 0; + if ((INTEL_GEN(dev_priv) >= 9) && + plane_state && plane_state->base.fb && + plane_state->base.fb->format->format == + DRM_FORMAT_NV12) { + if (INTEL_GEN(dev_priv) == 9 && + !IS_GEMINILAKE(dev_priv) && + !IS_SKYLAKE(dev_priv)) + scaler_state->scalers[*scaler_id].mode = + SKL_PS_SCALER_MODE_NV12; + else + scaler_state->scalers[*scaler_id].mode = + PS_SCALER_MODE_PLANAR; } else if (num_scalers_need == 1 && intel_crtc->pipe != PIPE_C) { /* * when only 1 scaler is in use on either pipe A or B, -- cgit v1.2.3 From a589b1384593c6a9df8b808e5a0aa4280de5edc2 Mon Sep 17 00:00:00 2001 From: Chandra Konduru Date: Mon, 9 Apr 2018 09:11:12 +0530 Subject: drm/i915: Update format_is_yuv() to include NV12 This patch adds NV12 to format_is_yuv() function for sprite planes. v2: -Use intel_ prefix for format_is_yuv (Ville) v3: Rebased (me) v4: Rebased and addressed review comments from Clinton A Taylor. "static function in intel_sprite.c is not available to the primary plane functions". Changed commit message - function modified for sprite planes. v5: Missed the Tested-by/Reviewed-by in the previous series Adding the same to commit message in this version. v6: Rebased (me) v7: Rebased (me) v8: Rebased (me) v9: Rebased (me) v10: Changed intel_format_is_yuv function from static to non-static. We need to use it later from other files for check. v11: Rebased the patch. format_is_yuv has already been renamed to intel_format_is_yuv in the color patch series which is already merged. This function which was previously static has already been made non-static. So this patch after rebase just adds NV12 to intel_format_is_yuv function. v12: Added reviewed by from Juha-Pekka Heikkila v13/v14/v15: Rebased the series Tested-by: Clinton Taylor Reviewed-by: Juha-Pekka Heikkila Reviewed-by: Clinton Taylor Reviewed-by: Shashank Sharma Signed-off-by: Chandra Konduru Signed-off-by: Nabendu Maiti Signed-off-by: Vidya Srinivas Reviewed-by: Maarten Lankhorst Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-14-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_sprite.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2c3c40d12136..a6d7d856ea62 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -2055,6 +2055,7 @@ 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); +bool intel_format_is_yuv(uint32_t format); /* 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 dbdcf85032df..0652e583b03d 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -48,6 +48,7 @@ bool intel_format_is_yuv(u32 format) case DRM_FORMAT_UYVY: case DRM_FORMAT_VYUY: case DRM_FORMAT_YVYU: + case DRM_FORMAT_NV12: return true; default: return false; -- cgit v1.2.3 From 77224cd59eae67acfc1259f0756957b10ec7c3b5 Mon Sep 17 00:00:00 2001 From: Chandra Konduru Date: Mon, 9 Apr 2018 09:11:13 +0530 Subject: drm/i915: Upscale scaler max scale for NV12 This patch updates scaler max limit support for NV12 v2: Rebased (me) v3: Rebased (me) v4: Missed the Tested-by/Reviewed-by in the previous series Adding the same to commit message in this version. v5: Addressed review comments from Ville and rebased - calculation of max_scale to be made less convoluted by splitting it up a bit - Indentation errors to be fixed in the series v6: Rebased (me) Fixed review comments from Paauwe, Bob J Previous version, where a split of calculation was done, was wrong. Fixed that issue here. v7: Rebased (me) v8: Rebased (me) v9: Rebased (me) v10: Rebased (me) v11: Addressed review comments from Shashank Sharma Alignment issues fixed. When call to skl_update_scaler is made, 0 was being sent instead of pixel_format. When crtc update scaler is called, we dont have the fb to derive the pixel format. Added the function parameter bool plane_scaler_check to account for this. v12: Fixed failure in IGT debugfs_test. fb is NULL in skl_update_scaler_plane Due to this, accessing fb->format caused failure. Patch checks fb before using. v13: In the previous version there was a flaw. In skl_update_scaler during plane_scaler_check if the format was non-NV12, it would set need_scaling to false. This could reset the previously set need_scaling from a previous condition check. Patch fixes this. Patch also adds minimum src height for YUV 420 formats to 16 (as defined in BSpec) and adds for checking this range. v14: Addressed review comments from Maarten Just add a check for NV12 min src height in skl_update_scaler and retain the remaining checks as is. Added Reviewed By from Juha-Pekka Heikkila. v15: Rebased the series. v16: Changed fb height restriction to be >= 16 as per Bspec. Earlier it was > 16. v17: Adding src width and height to be mult of 4 restriction to avoid pipe fifo underruns for NV12. Credits-to: Maarten Lankhorst Tested-by: Clinton Taylor Reviewed-by: Clinton Taylor Reviewed-by: Juha-Pekka Heikkila Signed-off-by: Chandra Konduru Signed-off-by: Nabendu Maiti Signed-off-by: Vidya Srinivas Reviewed-by: Maarten Lankhorst Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/1523245273-30264-15-git-send-email-vidya.srinivas@intel.com --- drivers/gpu/drm/i915/intel_display.c | 48 +++++++++++++++++++++++++++--------- drivers/gpu/drm/i915/intel_drv.h | 5 +++- drivers/gpu/drm/i915/intel_sprite.c | 6 ++++- 3 files changed, 46 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index eb9d4e7f9160..fec3d6dd5c60 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3483,6 +3483,8 @@ static u32 skl_plane_ctl_format(uint32_t pixel_format) return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY; case DRM_FORMAT_VYUY: return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_VYUY; + case DRM_FORMAT_NV12: + return PLANE_CTL_FORMAT_NV12; default: MISSING_CASE(pixel_format); } @@ -4724,7 +4726,9 @@ static void cpt_verify_modeset(struct drm_device *dev, int pipe) static int skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, unsigned int scaler_user, int *scaler_id, - int src_w, int src_h, int dst_w, int dst_h) + int src_w, int src_h, int dst_w, int dst_h, + bool plane_scaler_check, + uint32_t pixel_format) { struct intel_crtc_scaler_state *scaler_state = &crtc_state->scaler_state; @@ -4742,6 +4746,10 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, */ need_scaling = src_w != dst_w || src_h != dst_h; + if (plane_scaler_check) + if (pixel_format == DRM_FORMAT_NV12) + need_scaling = true; + if (crtc_state->ycbcr420 && scaler_user == SKL_CRTC_INDEX) need_scaling = true; @@ -4781,6 +4789,13 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, return 0; } + if (plane_scaler_check && pixel_format == DRM_FORMAT_NV12 && + (src_h < SKL_MIN_YUV_420_SRC_H || (src_w % 4) != 0 || + (src_h % 4) != 0)) { + DRM_DEBUG_KMS("NV12: src dimensions not met\n"); + return -EINVAL; + } + /* range checks */ if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H || dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H || @@ -4820,9 +4835,10 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state) const struct drm_display_mode *adjusted_mode = &state->base.adjusted_mode; return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX, - &state->scaler_state.scaler_id, - state->pipe_src_w, state->pipe_src_h, - adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_vdisplay); + &state->scaler_state.scaler_id, + state->pipe_src_w, state->pipe_src_h, + adjusted_mode->crtc_hdisplay, + adjusted_mode->crtc_vdisplay, false, 0); } /** @@ -4851,7 +4867,8 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, drm_rect_width(&plane_state->base.src) >> 16, drm_rect_height(&plane_state->base.src) >> 16, drm_rect_width(&plane_state->base.dst), - drm_rect_height(&plane_state->base.dst)); + drm_rect_height(&plane_state->base.dst), + fb ? true : false, fb ? fb->format->format : 0); if (ret || plane_state->scaler_id < 0) return ret; @@ -4877,6 +4894,7 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, case DRM_FORMAT_YVYU: case DRM_FORMAT_UYVY: case DRM_FORMAT_VYUY: + case DRM_FORMAT_NV12: break; default: DRM_DEBUG_KMS("[PLANE:%d:%s] FB:%d unsupported scaling format 0x%x\n", @@ -12877,11 +12895,13 @@ intel_cleanup_plane_fb(struct drm_plane *plane, } int -skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state) +skl_max_scale(struct intel_crtc *intel_crtc, + struct intel_crtc_state *crtc_state, + uint32_t pixel_format) { struct drm_i915_private *dev_priv; - int max_scale; - int crtc_clock, max_dotclk; + int max_scale, mult; + int crtc_clock, max_dotclk, tmpclk1, tmpclk2; if (!intel_crtc || !crtc_state->base.enable) return DRM_PLANE_HELPER_NO_SCALING; @@ -12903,8 +12923,10 @@ skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state * or * cdclk/crtc_clock */ - max_scale = min((1 << 16) * 3 - 1, - (1 << 8) * ((max_dotclk << 8) / crtc_clock)); + mult = pixel_format == DRM_FORMAT_NV12 ? 2 : 3; + tmpclk1 = (1 << 16) * mult - 1; + tmpclk2 = (1 << 8) * ((max_dotclk << 8) / crtc_clock); + max_scale = min(tmpclk1, tmpclk2); return max_scale; } @@ -12920,12 +12942,16 @@ intel_check_primary_plane(struct intel_plane *plane, int max_scale = DRM_PLANE_HELPER_NO_SCALING; bool can_position = false; int ret; + uint32_t pixel_format = 0; if (INTEL_GEN(dev_priv) >= 9) { /* use scaler when colorkey is not required */ if (!state->ckey.flags) { min_scale = 1; - max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state); + if (state->base.fb) + pixel_format = state->base.fb->format->format; + max_scale = skl_max_scale(to_intel_crtc(crtc), + crtc_state, pixel_format); } can_position = true; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a6d7d856ea62..b2e0fa04ef5b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -552,6 +552,8 @@ struct intel_initial_plane_config { #define ICL_MAX_SRC_H 4096 #define ICL_MAX_DST_W 5120 #define ICL_MAX_DST_H 4096 +#define SKL_MIN_YUV_420_SRC_W 16 +#define SKL_MIN_YUV_420_SRC_H 16 struct intel_scaler { int in_use; @@ -1597,7 +1599,8 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, struct intel_crtc_state *pipe_config); int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state); -int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); +int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, + uint32_t pixel_format); static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state) { diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 0652e583b03d..aa1dfaa692b9 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -947,6 +947,7 @@ intel_check_sprite_plane(struct intel_plane *plane, int max_scale, min_scale; bool can_scale; int ret; + uint32_t pixel_format = 0; *src = drm_plane_state_src(&state->base); *dst = drm_plane_state_dest(&state->base); @@ -970,11 +971,14 @@ intel_check_sprite_plane(struct intel_plane *plane, /* setup can_scale, min_scale, max_scale */ if (INTEL_GEN(dev_priv) >= 9) { + if (state->base.fb) + pixel_format = state->base.fb->format->format; /* use scaler when colorkey is not required */ if (!state->ckey.flags) { can_scale = 1; min_scale = 1; - max_scale = skl_max_scale(crtc, crtc_state); + max_scale = + skl_max_scale(crtc, crtc_state, pixel_format); } else { can_scale = 0; min_scale = DRM_PLANE_HELPER_NO_SCALING; -- cgit v1.2.3 From 19d3cf00cda6a3543c6fe2c75b674efab4a20eb6 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 6 Apr 2018 12:44:07 +0100 Subject: drm/i915: Enclose for_each_engine_masked macro arguments in parentheses Enclose for_each_engine_masked macro arguments in parentheses. v2: * Fixup whitespace to satisfy checkpatch. * Likewise reformat to 80 chars. Signed-off-by: Tvrtko Ursulin Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180406114407.25360-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_drv.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ba4a82193246..649c0f2f3bae 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2151,8 +2151,10 @@ static inline struct drm_i915_private *huc_to_i915(struct intel_huc *huc) /* Iterator over subset of engines selected by mask */ #define for_each_engine_masked(engine__, dev_priv__, mask__, tmp__) \ - for (tmp__ = mask__ & INTEL_INFO(dev_priv__)->ring_mask; \ - tmp__ ? (engine__ = (dev_priv__)->engine[__mask_next_bit(tmp__)]), 1 : 0; ) + for ((tmp__) = (mask__) & INTEL_INFO(dev_priv__)->ring_mask; \ + (tmp__) ? \ + ((engine__) = (dev_priv__)->engine[__mask_next_bit(tmp__)]), 1 : \ + 0;) enum hdmi_force_audio { HDMI_AUDIO_OFF_DVI = -2, /* no aux data for HDMI-DVI converter */ -- cgit v1.2.3 From 0c5c7df360dbcfefac61ebd118c8551acf714d79 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 6 Apr 2018 13:35:14 +0100 Subject: drm/i915/execlists: Log fence context & seqno throughout GEM_TRACE Include fence context and seqno in low level tracing so it is easier to follow flows of individual requests when things go bad. Also added tracing on the reset side of things. v2: Chris Wilson: * Standardize global_seqno and seqno as global. * Include current hws seqno in execlists_cancel_port_requests. v3: * Fix port printk format for all builds. Signed-off-by: Tvrtko Ursulin Reviewed-by: Chris Wilson # v2 Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180406123514.5809-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_request.c | 6 +++--- drivers/gpu/drm/i915/intel_lrc.c | 22 +++++++++++++++++----- 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 629f3e860592..9ca9c24b4421 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -343,7 +343,7 @@ static void i915_request_retire(struct i915_request *request) struct intel_engine_cs *engine = request->engine; struct i915_gem_active *active, *next; - GEM_TRACE("%s fence %llx:%d, global_seqno %d, current %d\n", + GEM_TRACE("%s fence %llx:%d, global=%d, current %d\n", engine->name, request->fence.context, request->fence.seqno, request->global_seqno, @@ -466,7 +466,7 @@ void __i915_request_submit(struct i915_request *request) struct intel_engine_cs *engine = request->engine; u32 seqno; - GEM_TRACE("%s fence %llx:%d -> global_seqno %d, current %d\n", + GEM_TRACE("%s fence %llx:%d -> global=%d, current %d\n", engine->name, request->fence.context, request->fence.seqno, engine->timeline->seqno + 1, @@ -516,7 +516,7 @@ void __i915_request_unsubmit(struct i915_request *request) { struct intel_engine_cs *engine = request->engine; - GEM_TRACE("%s fence %llx:%d <- global_seqno %d, current %d\n", + GEM_TRACE("%s fence %llx:%d <- global=%d, current %d\n", engine->name, request->fence.context, request->fence.seqno, request->global_seqno, diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 3592288e4696..02b25bf2378a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -468,10 +468,11 @@ static void execlists_submit_ports(struct intel_engine_cs *engine) desc = execlists_update_context(rq); GEM_DEBUG_EXEC(port[n].context_id = upper_32_bits(desc)); - GEM_TRACE("%s in[%d]: ctx=%d.%d, seqno=%d (current %d), prio=%d\n", + GEM_TRACE("%s in[%d]: ctx=%d.%d, global=%d (fence %llx:%d) (current %d), prio=%d\n", engine->name, n, port[n].context_id, count, rq->global_seqno, + rq->fence.context, rq->fence.seqno, intel_engine_get_seqno(engine), rq_prio(rq)); } else { @@ -742,6 +743,13 @@ execlists_cancel_port_requests(struct intel_engine_execlists * const execlists) while (num_ports-- && port_isset(port)) { struct i915_request *rq = port_request(port); + GEM_TRACE("%s:port%u global=%d (fence %llx:%d), (current %d)\n", + rq->engine->name, + (unsigned int)(port - execlists->port), + rq->global_seqno, + rq->fence.context, rq->fence.seqno, + intel_engine_get_seqno(rq->engine)); + GEM_BUG_ON(!execlists->active); intel_engine_context_out(rq->engine); @@ -817,7 +825,8 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) struct rb_node *rb; unsigned long flags; - GEM_TRACE("%s\n", engine->name); + GEM_TRACE("%s current %d\n", + engine->name, intel_engine_get_seqno(engine)); /* * Before we call engine->cancel_requests(), we should have exclusive @@ -1014,10 +1023,12 @@ static void execlists_submission_tasklet(unsigned long data) EXECLISTS_ACTIVE_USER)); rq = port_unpack(port, &count); - GEM_TRACE("%s out[0]: ctx=%d.%d, seqno=%d (current %d), prio=%d\n", + GEM_TRACE("%s out[0]: ctx=%d.%d, global=%d (fence %llx:%d) (current %d), prio=%d\n", engine->name, port->context_id, count, rq ? rq->global_seqno : 0, + rq ? rq->fence.context : 0, + rq ? rq->fence.seqno : 0, intel_engine_get_seqno(engine), rq ? rq_prio(rq) : 0); @@ -1744,8 +1755,9 @@ static void reset_common_ring(struct intel_engine_cs *engine, struct intel_context *ce; unsigned long flags; - GEM_TRACE("%s seqno=%x\n", - engine->name, request ? request->global_seqno : 0); + GEM_TRACE("%s request global=%x, current=%d\n", + engine->name, request ? request->global_seqno : 0, + intel_engine_get_seqno(engine)); /* See execlists_cancel_requests() for the irq/spinlock split. */ local_irq_save(flags); -- cgit v1.2.3 From cd27d88fba98660da870c00eda5ac0ea7969fc8e Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 9 Apr 2018 14:46:53 +0200 Subject: drm/i915: Change use get_new_plane_state instead of existing plane state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The get_existing macros are deprecated and should be replaced by get_old/new_state for clarity. Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20180409124656.39886-1-maarten.lankhorst@linux.intel.com [mlankhorst: Remove useless warn. (Ville)] Reviewed-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_atomic.c | 5 +++-- drivers/gpu/drm/i915/intel_drv.h | 11 ----------- drivers/gpu/drm/i915/intel_pm.c | 2 -- 3 files changed, 3 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index bb8c1687823e..40285d1b91b7 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -227,6 +227,7 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv, struct intel_crtc_scaler_state *scaler_state = &crtc_state->scaler_state; struct drm_atomic_state *drm_state = crtc_state->base.state; + struct intel_atomic_state *intel_state = to_intel_atomic_state(drm_state); int num_scalers_need; int i, j; @@ -304,8 +305,8 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv, continue; } - plane_state = intel_atomic_get_existing_plane_state(drm_state, - intel_plane); + plane_state = intel_atomic_get_new_plane_state(intel_state, + intel_plane); scaler_id = &plane_state->scaler_id; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b2e0fa04ef5b..e545aa673bd9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -2109,17 +2109,6 @@ intel_atomic_get_existing_crtc_state(struct drm_atomic_state *state, return NULL; } -static inline struct intel_plane_state * -intel_atomic_get_existing_plane_state(struct drm_atomic_state *state, - struct intel_plane *plane) -{ - struct drm_plane_state *plane_state; - - plane_state = drm_atomic_get_existing_plane_state(state, &plane->base); - - return to_intel_plane_state(plane_state); -} - int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv, struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 007a12ebe725..4baab858e442 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5037,8 +5037,6 @@ skl_ddb_add_affected_planes(struct intel_crtc_state *cstate) struct drm_plane *plane; enum pipe pipe = intel_crtc->pipe; - WARN_ON(!drm_atomic_get_existing_crtc_state(state, crtc)); - drm_for_each_plane_mask(plane, dev, cstate->base.plane_mask) { enum plane_id plane_id = to_intel_plane(plane)->id; -- cgit v1.2.3 From 70c7183fbe96a42292df598288d32c2a172ff12f Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 9 Apr 2018 14:46:54 +0200 Subject: drm/i915: Remove get_existing_crtc_state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_existing_crtc_state is currently unused, get rid of it. Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20180409124656.39886-2-maarten.lankhorst@linux.intel.com Reviewed-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_drv.h | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e545aa673bd9..9969309132d0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -2095,20 +2095,6 @@ intel_atomic_get_crtc_state(struct drm_atomic_state *state, return to_intel_crtc_state(crtc_state); } -static inline struct intel_crtc_state * -intel_atomic_get_existing_crtc_state(struct drm_atomic_state *state, - struct intel_crtc *crtc) -{ - struct drm_crtc_state *crtc_state; - - crtc_state = drm_atomic_get_existing_crtc_state(state, &crtc->base); - - if (crtc_state) - return to_intel_crtc_state(crtc_state); - else - return NULL; -} - int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv, struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state); -- cgit v1.2.3 From 8b69449d26637551c4145731e684cf1bb2478393 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 9 Apr 2018 14:46:55 +0200 Subject: drm/i915: Remove last references to drm_atomic_get_existing* macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the references to get_existing_state can be converted to get_new_state or get_old_state, which means that i915 is now get_existing_state free. Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20180409124656.39886-3-maarten.lankhorst@linux.intel.com [mlankhorst: Fix alignment in prepare_plane_fb. (Ville)] Reviewed-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c | 53 ++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fec3d6dd5c60..8fe805983be8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5148,8 +5148,8 @@ static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state) intel_atomic_get_new_crtc_state(to_intel_atomic_state(old_state), crtc); struct drm_plane *primary = crtc->base.primary; - struct drm_plane_state *old_pri_state = - drm_atomic_get_existing_plane_state(old_state, primary); + struct drm_plane_state *old_primary_state = + drm_atomic_get_old_plane_state(old_state, primary); intel_frontbuffer_flip(to_i915(crtc->base.dev), pipe_config->fb_bits); @@ -5159,19 +5159,16 @@ static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state) if (hsw_post_update_enable_ips(old_crtc_state, pipe_config)) hsw_enable_ips(pipe_config); - if (old_pri_state) { - struct intel_plane_state *primary_state = - intel_atomic_get_new_plane_state(to_intel_atomic_state(old_state), - to_intel_plane(primary)); - struct intel_plane_state *old_primary_state = - to_intel_plane_state(old_pri_state); - struct drm_framebuffer *fb = primary_state->base.fb; + if (old_primary_state) { + struct drm_plane_state *new_primary_state = + drm_atomic_get_new_plane_state(old_state, primary); + struct drm_framebuffer *fb = new_primary_state->fb; intel_fbc_post_update(crtc); - if (primary_state->base.visible && + if (new_primary_state->visible && (needs_modeset(&pipe_config->base) || - !old_primary_state->base.visible)) + !old_primary_state->visible)) intel_post_enable_primary(&crtc->base, pipe_config); /* Display WA 827 */ @@ -5192,8 +5189,8 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state, struct drm_i915_private *dev_priv = to_i915(dev); struct drm_atomic_state *old_state = old_crtc_state->base.state; struct drm_plane *primary = crtc->base.primary; - struct drm_plane_state *old_pri_state = - drm_atomic_get_existing_plane_state(old_state, primary); + struct drm_plane_state *old_primary_state = + drm_atomic_get_old_plane_state(old_state, primary); bool modeset = needs_modeset(&pipe_config->base); struct intel_atomic_state *old_intel_state = to_intel_atomic_state(old_state); @@ -5201,13 +5198,11 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state, if (hsw_pre_update_disable_ips(old_crtc_state, pipe_config)) hsw_disable_ips(old_crtc_state); - if (old_pri_state) { - struct intel_plane_state *primary_state = + if (old_primary_state) { + struct intel_plane_state *new_primary_state = intel_atomic_get_new_plane_state(old_intel_state, to_intel_plane(primary)); - struct intel_plane_state *old_primary_state = - to_intel_plane_state(old_pri_state); - struct drm_framebuffer *fb = primary_state->base.fb; + struct drm_framebuffer *fb = new_primary_state->base.fb; /* Display WA 827 */ if ((INTEL_GEN(dev_priv) == 9 && !IS_GEMINILAKE(dev_priv)) || @@ -5216,13 +5211,13 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state, skl_wa_clkgate(dev_priv, crtc->pipe, true); } - intel_fbc_pre_update(crtc, pipe_config, primary_state); + intel_fbc_pre_update(crtc, pipe_config, new_primary_state); /* * Gen2 reports pipe underruns whenever all planes are disabled. * So disable underrun reporting before all the planes get disabled. */ - if (IS_GEN2(dev_priv) && old_primary_state->base.visible && - (modeset || !primary_state->base.visible)) + if (IS_GEN2(dev_priv) && old_primary_state->visible && + (modeset || !new_primary_state->base.visible)) intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false); } @@ -10834,7 +10829,7 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state) struct drm_connector_state *connector_state; struct intel_encoder *encoder; - connector_state = drm_atomic_get_existing_connector_state(state, connector); + connector_state = drm_atomic_get_new_connector_state(state, connector); if (!connector_state) connector_state = connector->state; @@ -12197,6 +12192,9 @@ static void intel_update_crtc(struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc_state *pipe_config = to_intel_crtc_state(new_crtc_state); bool modeset = needs_modeset(new_crtc_state); + struct intel_plane_state *new_plane_state = + intel_atomic_get_new_plane_state(to_intel_atomic_state(state), + to_intel_plane(crtc->primary)); if (modeset) { update_scanline_offset(intel_crtc); @@ -12209,11 +12207,8 @@ static void intel_update_crtc(struct drm_crtc *crtc, pipe_config); } - if (drm_atomic_get_existing_plane_state(state, crtc->primary)) { - intel_fbc_enable( - intel_crtc, pipe_config, - to_intel_plane_state(crtc->primary->state)); - } + if (new_plane_state) + intel_fbc_enable(intel_crtc, pipe_config, new_plane_state); drm_atomic_helper_commit_planes_on_crtc(old_crtc_state); } @@ -12794,8 +12789,8 @@ intel_prepare_plane_fb(struct drm_plane *plane, if (old_obj) { struct drm_crtc_state *crtc_state = - drm_atomic_get_existing_crtc_state(new_state->state, - plane->state->crtc); + drm_atomic_get_new_crtc_state(new_state->state, + plane->state->crtc); /* Big Hammer, we also need to ensure that any pending * MI_WAIT_FOR_EVENT inside a user batch buffer on the -- cgit v1.2.3 From 1b85147b4b8fb90da51b6e94a3e6c30469bf1de1 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 9 Apr 2018 15:27:16 +0300 Subject: drm/i915/gen9_lp: Increase DDI PHY0 power well enabling timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On GLK sporadic timeouts occur during PHY0 enabling. Based on logs it looks like they happen sometime after a system suspend/resume cycle, with the same power well enabling succeeding both before and after the failed one and no other problems observed. The current timeout in the code is not actually specified by BSpec, so let's try to increase that until a BSpec update. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105771 Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20180409122716.4055-1-imre.deak@intel.com Reviewed-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_dpio_phy.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dpio_phy.c b/drivers/gpu/drm/i915/intel_dpio_phy.c index c8e9e44e5981..00b3ab656b06 100644 --- a/drivers/gpu/drm/i915/intel_dpio_phy.c +++ b/drivers/gpu/drm/i915/intel_dpio_phy.c @@ -380,13 +380,14 @@ static void _bxt_ddi_phy_init(struct drm_i915_private *dev_priv, * all 1s. Eventually they become accessible as they power up, then * the reserved bit will give the default 0. Poll on the reserved bit * becoming 0 to find when the PHY is accessible. - * HW team confirmed that the time to reach phypowergood status is - * anywhere between 50 us and 100us. + * The flag should get set in 100us according to the HW team, but + * use 1ms due to occasional timeouts observed with that. */ - if (wait_for_us(((I915_READ(BXT_PORT_CL1CM_DW0(phy)) & - (PHY_RESERVED | PHY_POWER_GOOD)) == PHY_POWER_GOOD), 100)) { + if (intel_wait_for_register_fw(dev_priv, BXT_PORT_CL1CM_DW0(phy), + PHY_RESERVED | PHY_POWER_GOOD, + PHY_POWER_GOOD, + 1)) DRM_ERROR("timeout during PHY%d power on\n", phy); - } /* Program PLL Rcomp code offset */ val = I915_READ(BXT_PORT_CL1CM_DW9(phy)); -- cgit v1.2.3 From daeb725e919c0d2d4b628aeaa1fa053125f888b2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 5 Apr 2018 12:49:15 +0100 Subject: drm/i915/psr: Chase psr.enabled only under the psr.lock Inside the psr work function, we want to wait for PSR to idle first and wish to do so without blocking the normal modeset path, so we do so without holding the PSR lock. However, we first have to find which pipe PSR was enabled on, which requires chasing into the PSR struct and requires locking to prevent intel_psr_disable() from concurrently setting our pointer to NULL. Fixes: 995d30477496 ("drm/i915: VLV/CHV PSR Software timer mode") Signed-off-by: Chris Wilson Cc: Durgadoss R Cc: Rodrigo Vivi Cc: # v4.0+ Reviewed-by: Jose Roberto de Souza Acked-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180405114915.29609-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_psr.c | 82 +++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 2d53f7398a6d..69a5b276f4d8 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -775,53 +775,59 @@ void intel_psr_disable(struct intel_dp *intel_dp, cancel_delayed_work_sync(&dev_priv->psr.work); } -static void intel_psr_work(struct work_struct *work) +static bool psr_wait_for_idle(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = - container_of(work, typeof(*dev_priv), psr.work.work); - struct intel_dp *intel_dp = dev_priv->psr.enabled; - struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc; - enum pipe pipe = to_intel_crtc(crtc)->pipe; + struct intel_dp *intel_dp; + i915_reg_t reg; + u32 mask; + int err; + + intel_dp = dev_priv->psr.enabled; + if (!intel_dp) + return false; - /* We have to make sure PSR is ready for re-enable - * otherwise it keeps disabled until next full enable/disable cycle. - * PSR might take some time to get fully disabled - * and be ready for re-enable. - */ if (HAS_DDI(dev_priv)) { if (dev_priv->psr.psr2_enabled) { - if (intel_wait_for_register(dev_priv, - EDP_PSR2_STATUS, - EDP_PSR2_STATUS_STATE_MASK, - 0, - 50)) { - DRM_ERROR("Timed out waiting for PSR2 Idle for re-enable\n"); - return; - } + reg = EDP_PSR2_STATUS; + mask = EDP_PSR2_STATUS_STATE_MASK; } else { - if (intel_wait_for_register(dev_priv, - EDP_PSR_STATUS, - EDP_PSR_STATUS_STATE_MASK, - 0, - 50)) { - DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n"); - return; - } + reg = EDP_PSR_STATUS; + mask = EDP_PSR_STATUS_STATE_MASK; } } else { - if (intel_wait_for_register(dev_priv, - VLV_PSRSTAT(pipe), - VLV_EDP_PSR_IN_TRANS, - 0, - 1)) { - DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n"); - return; - } + struct drm_crtc *crtc = + dp_to_dig_port(intel_dp)->base.base.crtc; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + + reg = VLV_PSRSTAT(pipe); + mask = VLV_EDP_PSR_IN_TRANS; } + + mutex_unlock(&dev_priv->psr.lock); + + err = intel_wait_for_register(dev_priv, reg, mask, 0, 50); + if (err) + DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n"); + + /* After the unlocked wait, verify that PSR is still wanted! */ mutex_lock(&dev_priv->psr.lock); - intel_dp = dev_priv->psr.enabled; + return err == 0 && dev_priv->psr.enabled; +} - if (!intel_dp) +static void intel_psr_work(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, typeof(*dev_priv), psr.work.work); + + mutex_lock(&dev_priv->psr.lock); + + /* + * We have to make sure PSR is ready for re-enable + * otherwise it keeps disabled until next full enable/disable cycle. + * PSR might take some time to get fully disabled + * and be ready for re-enable. + */ + if (!psr_wait_for_idle(dev_priv)) goto unlock; /* @@ -832,7 +838,7 @@ static void intel_psr_work(struct work_struct *work) if (dev_priv->psr.busy_frontbuffer_bits) goto unlock; - intel_psr_activate(intel_dp); + intel_psr_activate(dev_priv->psr.enabled); unlock: mutex_unlock(&dev_priv->psr.lock); } -- cgit v1.2.3 From d52ad9cb9d6d3b696d6b7ad20a381a8f5520ea03 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 28 Mar 2018 12:05:26 +0200 Subject: drm/i915: Add debugfs file to clear FIFO underruns. Adding a i915_fifo_underrun_reset debugfs file will make it possible for IGT tests to clear FIFO underrun fallout at the start of each subtest, and make re-enable FBC so tests always have maximum exposure to features used by IGT. FIFO underruns and FBC bugs will no longer hide when an earlier subtests disables both. Signed-off-by: Maarten Lankhorst References: https://bugs.freedesktop.org/show_bug.cgi?id=105685 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105681 Link: https://patchwork.freedesktop.org/patch/msgid/20180328100526.36467-1-maarten.lankhorst@linux.intel.com Acked-by: Jani Nikula [mlankhorst: Reset FBC reason if underrun had occurred. (vivijim)] Reviewed-by: Rodrigo Vivi --- drivers/gpu/drm/i915/i915_debugfs.c | 62 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 30 ++++++++++------- drivers/gpu/drm/i915/intel_drv.h | 3 ++ drivers/gpu/drm/i915/intel_fbc.c | 28 ++++++++++++++++ 4 files changed, 111 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 785b710e4ee4..2e6652a9bb9e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4732,6 +4732,67 @@ static int i915_drrs_ctl_set(void *data, u64 val) DEFINE_SIMPLE_ATTRIBUTE(i915_drrs_ctl_fops, NULL, i915_drrs_ctl_set, "%llu\n"); +static ssize_t +i915_fifo_underrun_reset_write(struct file *filp, + const char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + struct drm_i915_private *dev_priv = filp->private_data; + struct intel_crtc *intel_crtc; + struct drm_device *dev = &dev_priv->drm; + int ret; + bool reset; + + ret = kstrtobool_from_user(ubuf, cnt, &reset); + if (ret) + return ret; + + if (!reset) + return cnt; + + for_each_intel_crtc(dev, intel_crtc) { + struct drm_crtc_commit *commit; + struct intel_crtc_state *crtc_state; + + ret = drm_modeset_lock_single_interruptible(&intel_crtc->base.mutex); + if (ret) + return ret; + + crtc_state = to_intel_crtc_state(intel_crtc->base.state); + commit = crtc_state->base.commit; + if (commit) { + ret = wait_for_completion_interruptible(&commit->hw_done); + if (!ret) + ret = wait_for_completion_interruptible(&commit->flip_done); + } + + if (!ret && crtc_state->base.active) { + DRM_DEBUG_KMS("Re-arming FIFO underruns on pipe %c\n", + pipe_name(intel_crtc->pipe)); + + intel_crtc_arm_fifo_underrun(intel_crtc, crtc_state); + } + + drm_modeset_unlock(&intel_crtc->base.mutex); + + if (ret) + return ret; + } + + ret = intel_fbc_reset_underrun(dev_priv); + if (ret) + return ret; + + return cnt; +} + +static const struct file_operations i915_fifo_underrun_reset_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = i915_fifo_underrun_reset_write, + .llseek = default_llseek, +}; + static const struct drm_info_list i915_debugfs_list[] = { {"i915_capabilities", i915_capabilities, 0}, {"i915_gem_objects", i915_gem_object_info, 0}, @@ -4799,6 +4860,7 @@ static const struct i915_debugfs_files { {"i915_error_state", &i915_error_state_fops}, {"i915_gpu_info", &i915_gpu_info_fops}, #endif + {"i915_fifo_underrun_reset", &i915_fifo_underrun_reset_ops}, {"i915_next_seqno", &i915_next_seqno_fops}, {"i915_display_crc_ctl", &i915_display_crc_ctl_fops}, {"i915_pri_wm_latency", &i915_pri_wm_latency_fops}, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8fe805983be8..e04050ea3e28 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13019,10 +13019,25 @@ out: intel_cstate); } +void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc, + struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + + if (!IS_GEN2(dev_priv)) + intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, true); + + if (crtc_state->has_pch_encoder) { + enum pipe pch_transcoder = + intel_crtc_pch_transcoder(crtc); + + intel_set_pch_fifo_underrun_reporting(dev_priv, pch_transcoder, true); + } +} + static void intel_finish_crtc_commit(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc->dev); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_atomic_state *old_intel_state = to_intel_atomic_state(old_crtc_state->state); @@ -13033,17 +13048,8 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc, if (new_crtc_state->update_pipe && !needs_modeset(&new_crtc_state->base) && - old_crtc_state->mode.private_flags & I915_MODE_FLAG_INHERITED) { - if (!IS_GEN2(dev_priv)) - intel_set_cpu_fifo_underrun_reporting(dev_priv, intel_crtc->pipe, true); - - if (new_crtc_state->has_pch_encoder) { - enum pipe pch_transcoder = - intel_crtc_pch_transcoder(intel_crtc); - - intel_set_pch_fifo_underrun_reporting(dev_priv, pch_transcoder, true); - } - } + old_crtc_state->mode.private_flags & I915_MODE_FLAG_INHERITED) + intel_crtc_arm_fifo_underrun(intel_crtc, new_crtc_state); } /** diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9969309132d0..5bd2263407b2 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1597,6 +1597,8 @@ void hsw_disable_ips(const struct intel_crtc_state *crtc_state); enum intel_display_power_domain intel_port_to_power_domain(enum port port); void intel_mode_from_pipe_config(struct drm_display_mode *mode, struct intel_crtc_state *pipe_config); +void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc, + struct intel_crtc_state *crtc_state); int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state); int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, @@ -1784,6 +1786,7 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin); void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv); void intel_fbc_handle_fifo_underrun_irq(struct drm_i915_private *dev_priv); +int intel_fbc_reset_underrun(struct drm_i915_private *dev_priv); /* intel_hdmi.c */ void intel_hdmi_init(struct drm_i915_private *dev_priv, i915_reg_t hdmi_reg, diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 707d49c12638..b431b6733cc1 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -1272,6 +1272,34 @@ out: mutex_unlock(&fbc->lock); } +/* + * intel_fbc_reset_underrun - reset FBC fifo underrun status. + * @dev_priv: i915 device instance + * + * See intel_fbc_handle_fifo_underrun_irq(). For automated testing we + * want to re-enable FBC after an underrun to increase test coverage. + */ +int intel_fbc_reset_underrun(struct drm_i915_private *dev_priv) +{ + int ret; + + cancel_work_sync(&dev_priv->fbc.underrun_work); + + ret = mutex_lock_interruptible(&dev_priv->fbc.lock); + if (ret) + return ret; + + if (dev_priv->fbc.underrun_detected) { + DRM_DEBUG_KMS("Re-allowing FBC after fifo underrun\n"); + dev_priv->fbc.no_fbc_reason = "FIFO underrun cleared"; + } + + dev_priv->fbc.underrun_detected = false; + mutex_unlock(&dev_priv->fbc.lock); + + return 0; +} + /** * intel_fbc_handle_fifo_underrun_irq - disable FBC when we get a FIFO underrun * @dev_priv: i915 device instance -- cgit v1.2.3 From 3834dc1f0e57891a398b2cabd40c60fa9595cd7c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 10 Apr 2018 14:33:54 +0100 Subject: drm/i915: Don't fiddle with rps/rc6 across GPU reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resetting the GPU doesn't affect the RPS/RC6 state, so we can stop forcibly reloading the registers. Ville suggested this many moons ago, I said at that time that sanitizing was no harm and meant that our bookkeeping was kept consistent with the HW. However, in a forthcoming series, we want to split rps/rc6 GT powermanagement and one of the key simplifications is the control of when we enable it. Performing a crude sanitize in the middle of i915_gem_reset() is then a huge wart. Suggested-by: Ville Syrjälä Signed-off-by: Chris Wilson Cc: Ville Syrjälä Reviewed-by: Sagar Arun Kamble Link: https://patchwork.freedesktop.org/patch/msgid/20180410133354.13425-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 28ab0beff86c..60cf7cfc24ee 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3254,13 +3254,6 @@ void i915_gem_reset(struct drm_i915_private *dev_priv, } i915_gem_restore_fences(dev_priv); - - if (dev_priv->gt.awake) { - intel_sanitize_gt_powersave(dev_priv); - intel_enable_gt_powersave(dev_priv); - if (INTEL_GEN(dev_priv) >= 6) - gen6_rps_busy(dev_priv); - } } void i915_gem_reset_finish_engine(struct intel_engine_cs *engine) -- cgit v1.2.3 From 2184b3d69b961b5beb2781acf200b5b93643e32a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 10 Apr 2018 12:14:17 +0100 Subject: drm/i915/guc: Replace %phn with %ph %phn is not a valid specifier, and the trailing 'n' is being eaten by the format-specifier and defaulting to the ' ' separator. Avoid angering smatch by using the unknown specifier, and use the default we expect. drivers/gpu/drm/i915/intel_guc_ct.c:616 ctb_read() warn: '%ph' cannot be followed by 'n' drivers/gpu/drm/i915/intel_guc_ct.c:616 ctb_read() warn: '%ph' cannot be followed by 'n' drivers/gpu/drm/i915/intel_guc_ct.c:616 ctb_read() warn: '%ph' cannot be followed by 'n' drivers/gpu/drm/i915/intel_guc_ct.c:669 ct_handle_response() warn: '%ph' cannot be followed by 'n' drivers/gpu/drm/i915/intel_guc_ct.c:679 ct_handle_response() warn: '%ph' cannot be followed by 'n' drivers/gpu/drm/i915/intel_guc_ct.c:693 ct_handle_response() warn: '%ph' cannot be followed by 'n' drivers/gpu/drm/i915/intel_guc_ct.c:707 ct_handle_response() warn: '%ph' cannot be followed by 'n' drivers/gpu/drm/i915/intel_guc_ct.c:727 ct_process_request() warn: '%ph' cannot be followed by 'n' drivers/gpu/drm/i915/intel_guc_ct.c:803 ct_handle_request() warn: '%ph' cannot be followed by 'n' Signed-off-by: Chris Wilson Cc: Michal Wajdeczko Cc: Daniele Ceraolo Spurio Reviewed-by: Michal Wajdeczko Link: https://patchwork.freedesktop.org/patch/msgid/20180410111417.27563-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_guc_ct.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index 990141d5f195..371b6005954a 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -361,7 +361,7 @@ static int ctb_write(struct intel_guc_ct_buffer *ctb, (want_response ? GUC_CT_MSG_SEND_STATUS : 0) | (action[0] << GUC_CT_MSG_ACTION_SHIFT); - CT_DEBUG_DRIVER("CT: writing %*phn %*phn %*phn\n", + CT_DEBUG_DRIVER("CT: writing %*ph %*ph %*ph\n", 4, &header, 4, &fence, 4 * (len - 1), &action[1]); @@ -613,7 +613,7 @@ static int ctb_read(struct intel_guc_ct_buffer *ctb, u32 *data) /* message len with header */ len = ct_header_get_len(data[0]) + 1; if (unlikely(len > (u32)available)) { - DRM_ERROR("CT: incomplete message %*phn %*phn %*phn\n", + DRM_ERROR("CT: incomplete message %*ph %*ph %*ph\n", 4, data, 4 * (head + available - 1 > size ? size - head : available - 1), &cmds[head], @@ -626,7 +626,7 @@ static int ctb_read(struct intel_guc_ct_buffer *ctb, u32 *data) data[i] = cmds[head]; head = (head + 1) % size; } - CT_DEBUG_DRIVER("CT: received %*phn\n", 4 * len, data); + CT_DEBUG_DRIVER("CT: received %*ph\n", 4 * len, data); desc->head = head * 4; return 0; @@ -666,7 +666,7 @@ static int ct_handle_response(struct intel_guc_ct *ct, const u32 *msg) /* Response payload shall at least include fence and status */ if (unlikely(len < 2)) { - DRM_ERROR("CT: corrupted response %*phn\n", 4 * msglen, msg); + DRM_ERROR("CT: corrupted response %*ph\n", 4 * msglen, msg); return -EPROTO; } @@ -676,7 +676,7 @@ static int ct_handle_response(struct intel_guc_ct *ct, const u32 *msg) /* Format of the status follows RESPONSE message */ if (unlikely(!INTEL_GUC_MSG_IS_RESPONSE(status))) { - DRM_ERROR("CT: corrupted response %*phn\n", 4 * msglen, msg); + DRM_ERROR("CT: corrupted response %*ph\n", 4 * msglen, msg); return -EPROTO; } @@ -690,7 +690,7 @@ static int ct_handle_response(struct intel_guc_ct *ct, const u32 *msg) continue; } if (unlikely(datalen > req->response_len)) { - DRM_ERROR("CT: response %u too long %*phn\n", + DRM_ERROR("CT: response %u too long %*ph\n", req->fence, 4 * msglen, msg); datalen = 0; } @@ -704,7 +704,7 @@ static int ct_handle_response(struct intel_guc_ct *ct, const u32 *msg) spin_unlock(&ct->lock); if (!found) - DRM_ERROR("CT: unsolicited response %*phn\n", 4 * msglen, msg); + DRM_ERROR("CT: unsolicited response %*ph\n", 4 * msglen, msg); return 0; } @@ -713,7 +713,7 @@ static void ct_process_request(struct intel_guc_ct *ct, { struct intel_guc *guc = ct_to_guc(ct); - CT_DEBUG_DRIVER("CT: request %x %*phn\n", action, 4 * len, payload); + CT_DEBUG_DRIVER("CT: request %x %*ph\n", action, 4 * len, payload); switch (action) { case INTEL_GUC_ACTION_DEFAULT: @@ -724,7 +724,7 @@ static void ct_process_request(struct intel_guc_ct *ct, default: fail_unexpected: - DRM_ERROR("CT: unexpected request %x %*phn\n", + DRM_ERROR("CT: unexpected request %x %*ph\n", action, 4 * len, payload); break; } @@ -800,7 +800,7 @@ static int ct_handle_request(struct intel_guc_ct *ct, const u32 *msg) request = kmalloc(sizeof(*request) + 4 * msglen, GFP_ATOMIC); if (unlikely(!request)) { - DRM_ERROR("CT: dropping request %*phn\n", 4 * msglen, msg); + DRM_ERROR("CT: dropping request %*ph\n", 4 * msglen, msg); return 0; /* XXX: -ENOMEM ? */ } memcpy(request->msg, msg, 4 * msglen); -- cgit v1.2.3 From 2924bdee21edd6785a4df1b4d17fd3cb265fddd9 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 10 Apr 2018 12:27:04 +0100 Subject: drm/i915/pmu: Inspect runtime PM state more carefully while estimating RC6 While thinking about sporadic failures of perf_pmu/rc6-runtime-pm* tests on some CI machines I have concluded that: a) the PMU readout of RC6 can race against runtime PM transitions, and b) there are other reasons than being runtime suspended which can cause intel_runtime_pm_get_if_in_use to fail. Therefore when estimating RC6 the code needs to assert we are indeed in suspended state, and if not, the best we can do is return the last known RC6 value. Without this check we can calculate the estimated value based on un- initialized or inappropriate internal state, which can result in over- estimation, or in any case incorrect value being returned. v2: * Re-arrange the code a bit to avoid second unlock and return branch. (Chris Wilson) v3: * Insert some strategic blank lines and improve commit msg. (Chris Wilson) Signed-off-by: Tvrtko Ursulin Fixes: 1fe699e30113 ("drm/i915/pmu: Fix sleep under atomic in RC6 readout") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105010 Cc: Tvrtko Ursulin Cc: Chris Wilson Cc: Imre Deak Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180410112704.24462-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 11fb76bd3860..dc87797db500 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -452,20 +452,37 @@ static u64 get_rc6(struct drm_i915_private *i915) spin_lock_irqsave(&i915->pmu.lock, flags); spin_lock(&kdev->power.lock); - if (!i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur) - i915->pmu.suspended_jiffies_last = - kdev->power.suspended_jiffies; + /* + * After the above branch intel_runtime_pm_get_if_in_use failed + * to get the runtime PM reference we cannot assume we are in + * runtime suspend since we can either: a) race with coming out + * of it before we took the power.lock, or b) there are other + * states than suspended which can bring us here. + * + * We need to double-check that we are indeed currently runtime + * suspended and if not we cannot do better than report the last + * known RC6 value. + */ + if (kdev->power.runtime_status == RPM_SUSPENDED) { + if (!i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur) + i915->pmu.suspended_jiffies_last = + kdev->power.suspended_jiffies; - val = kdev->power.suspended_jiffies - - i915->pmu.suspended_jiffies_last; - val += jiffies - kdev->power.accounting_timestamp; + val = kdev->power.suspended_jiffies - + i915->pmu.suspended_jiffies_last; + val += jiffies - kdev->power.accounting_timestamp; - spin_unlock(&kdev->power.lock); + val = jiffies_to_nsecs(val); + val += i915->pmu.sample[__I915_SAMPLE_RC6].cur; - val = jiffies_to_nsecs(val); - val += i915->pmu.sample[__I915_SAMPLE_RC6].cur; - i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur = val; + i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur = val; + } else if (i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur) { + val = i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur; + } else { + val = i915->pmu.sample[__I915_SAMPLE_RC6].cur; + } + spin_unlock(&kdev->power.lock); spin_unlock_irqrestore(&i915->pmu.lock, flags); } -- cgit v1.2.3 From f3aa929c59c945e50386fde65d37c24e8a898e48 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 10 Apr 2018 12:12:48 +0300 Subject: drm/i915/bios: remove duplicated code Apparently caused by a merge fail at some point. Due to the nature of the duplicated block, the second one will have no effect, and there's no need to backport. Reviewed-by: Paulo Zanoni Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180410091248.1454-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_bios.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index c5c7530ba157..6aae88c4df52 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1271,13 +1271,6 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, is_hdmi = false; } - if (port == PORT_A && is_dvi) { - DRM_DEBUG_KMS("VBT claims port A supports DVI%s, ignoring\n", - is_hdmi ? "/HDMI" : ""); - is_dvi = false; - is_hdmi = false; - } - info->supports_dvi = is_dvi; info->supports_hdmi = is_hdmi; info->supports_dp = is_dp; -- cgit v1.2.3 From 15c83c436424adf3fe0365e9085a82da1190c95e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 11 Apr 2018 11:39:29 +0100 Subject: drm/i915/execlists: Set queue priority from secondary port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can refine our current execlists->queue_priority if we inspect ELSP[1] rather than the head of the unsubmitted queue. Currently, we use the unsubmitted queue and say that if a subsequent request is more important than the current queue, we will rerun the submission tasklet to evaluate the need for preemption. However, we only want to preempt if we need to jump ahead of a currently executing request in ELSP. The second reason for running the submission tasklet is amalgamate requests into the active context on ELSP[0] to avoid a stall when ELSP[0] drains. (Though repeatedly amalgamating requests into the active context and triggering many lite-restore is off question gain, the goal really is to put a context into ELSP[1] to cover the interrupt.) So if instead of looking at the head of the queue, we look at the context in ELSP[1] we can answer both of the questions more accurately -- we don't need to rerun the submission tasklet unless our new request is important enough to feed into, at least, ELSP[1]. v2: Add some comments from the discussion with Tvrtko. v3: More commentary to cross-reference queue_request() References: f6322eddaff7 ("drm/i915/preemption: Allow preemption between submission ports") Signed-off-by: Chris Wilson Cc: Michał Winiarski Cc: Michel Thierry Cc: Mika Kuoppala Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20180411103929.27374-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 3 +++ drivers/gpu/drm/i915/intel_lrc.c | 21 ++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 12486d8f534b..a217b3fe5f0b 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1687,6 +1687,9 @@ void intel_engines_park(struct drm_i915_private *i915) intel_engine_dump(engine, &p, NULL); } + /* Must be reset upon idling, or we may miss the busy wakeup. */ + GEM_BUG_ON(engine->execlists.queue_priority != INT_MIN); + if (engine->park) engine->park(engine); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 02b25bf2378a..665d9e82e954 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -713,8 +713,27 @@ static void execlists_dequeue(struct intel_engine_cs *engine) if (p->priority != I915_PRIORITY_NORMAL) kmem_cache_free(engine->i915->priorities, p); } + done: - execlists->queue_priority = rb ? to_priolist(rb)->priority : INT_MIN; + /* + * Here be a bit of magic! Or sleight-of-hand, whichever you prefer. + * + * We choose queue_priority such that if we add a request of greater + * priority than this, we kick the submission tasklet to decide on + * the right order of submitting the requests to hardware. We must + * also be prepared to reorder requests as they are in-flight on the + * HW. We derive the queue_priority then as the first "hole" in + * the HW submission ports and if there are no available slots, + * the priority of the lowest executing request, i.e. last. + * + * When we do receive a higher priority request ready to run from the + * user, see queue_request(), the queue_priority is bumped to that + * request triggering preemption on the next dequeue (or subsequent + * interrupt for secondary ports). + */ + execlists->queue_priority = + port != execlists->port ? rq_prio(last) : INT_MIN; + execlists->first = rb; if (submit) port_assign(port, last); -- cgit v1.2.3 From 7d3c425fefb91da7e984a43ba27dff6cdd53758a Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Tue, 10 Apr 2018 09:12:46 -0700 Subject: drm/i915: Move a bunch of workaround-related code to its own file This has grown to be a sizable amount of code, so move it to its own file before we try to refactor anything. For the moment, we are leaving behind the WA BB code and the WAs that get applied (incorrectly) in init_clock_gating, but we will deal with it later. v2: Use intel_ prefix for code that deals with the hardware (Chris) v3: Rebased v4: - Rebased - New license header v5: - Rebased - Added some organisational notes to the file (Chris) v6: Include DOC section in the documentation build (Jani) Signed-off-by: Oscar Mateo Cc: Mika Kuoppala Cc: Jani Nikula Reviewed-by: Chris Wilson [ickle: appease checkpatch, mostly] Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/1523376767-18480-1-git-send-email-oscar.mateo@intel.com --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/intel_engine_cs.c | 634 ---------------------------- drivers/gpu/drm/i915/intel_lrc.c | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 1 + drivers/gpu/drm/i915/intel_ringbuffer.h | 3 - drivers/gpu/drm/i915/intel_workarounds.c | 686 +++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_workarounds.h | 13 + 7 files changed, 703 insertions(+), 638 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_workarounds.c create mode 100644 drivers/gpu/drm/i915/intel_workarounds.h (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 0c79c19223af..9bee52a949a9 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -43,7 +43,8 @@ i915-y := i915_drv.o \ intel_csr.o \ intel_device_info.o \ intel_pm.o \ - intel_runtime_pm.o + intel_runtime_pm.o \ + intel_workarounds.o i915-$(CONFIG_COMPAT) += i915_ioc32.o i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o intel_pipe_crc.o diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index a217b3fe5f0b..68898d58dd1e 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -903,640 +903,6 @@ void intel_engine_get_instdone(struct intel_engine_cs *engine, } } -static int wa_add(struct drm_i915_private *dev_priv, - i915_reg_t addr, - const u32 mask, const u32 val) -{ - const u32 idx = dev_priv->workarounds.count; - - if (WARN_ON(idx >= I915_MAX_WA_REGS)) - return -ENOSPC; - - dev_priv->workarounds.reg[idx].addr = addr; - dev_priv->workarounds.reg[idx].value = val; - dev_priv->workarounds.reg[idx].mask = mask; - - dev_priv->workarounds.count++; - - return 0; -} - -#define WA_REG(addr, mask, val) do { \ - const int r = wa_add(dev_priv, (addr), (mask), (val)); \ - if (r) \ - return r; \ - } while (0) - -#define WA_SET_BIT_MASKED(addr, mask) \ - WA_REG(addr, (mask), _MASKED_BIT_ENABLE(mask)) - -#define WA_CLR_BIT_MASKED(addr, mask) \ - WA_REG(addr, (mask), _MASKED_BIT_DISABLE(mask)) - -#define WA_SET_FIELD_MASKED(addr, mask, value) \ - WA_REG(addr, mask, _MASKED_FIELD(mask, value)) - -static int wa_ring_whitelist_reg(struct intel_engine_cs *engine, - i915_reg_t reg) -{ - struct drm_i915_private *dev_priv = engine->i915; - struct i915_workarounds *wa = &dev_priv->workarounds; - const uint32_t index = wa->hw_whitelist_count[engine->id]; - - if (WARN_ON(index >= RING_MAX_NONPRIV_SLOTS)) - return -EINVAL; - - I915_WRITE(RING_FORCE_TO_NONPRIV(engine->mmio_base, index), - i915_mmio_reg_offset(reg)); - wa->hw_whitelist_count[engine->id]++; - - return 0; -} - -static int gen8_init_workarounds(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - - WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); - - /* WaDisableAsyncFlipPerfMode:bdw,chv */ - WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE); - - /* WaDisablePartialInstShootdown:bdw,chv */ - WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, - PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); - - /* Use Force Non-Coherent whenever executing a 3D context. This is a - * workaround for for a possible hang in the unlikely event a TLB - * invalidation occurs during a PSD flush. - */ - /* WaForceEnableNonCoherent:bdw,chv */ - /* WaHdcDisableFetchWhenMasked:bdw,chv */ - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_DONOT_FETCH_MEM_WHEN_MASKED | - HDC_FORCE_NON_COHERENT); - - /* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0: - * "The Hierarchical Z RAW Stall Optimization allows non-overlapping - * polygons in the same 8x4 pixel/sample area to be processed without - * stalling waiting for the earlier ones to write to Hierarchical Z - * buffer." - * - * This optimization is off by default for BDW and CHV; turn it on. - */ - WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE); - - /* Wa4x4STCOptimizationDisable:bdw,chv */ - WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE); - - /* - * BSpec recommends 8x4 when MSAA is used, - * however in practice 16x4 seems fastest. - * - * Note that PS/WM thread counts depend on the WIZ hashing - * disable bit, which we don't touch here, but it's good - * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM). - */ - WA_SET_FIELD_MASKED(GEN7_GT_MODE, - GEN6_WIZ_HASHING_MASK, - GEN6_WIZ_HASHING_16x4); - - return 0; -} - -static int bdw_init_workarounds(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - int ret; - - ret = gen8_init_workarounds(engine); - if (ret) - return ret; - - /* WaDisableThreadStallDopClockGating:bdw (pre-production) */ - WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE); - - /* WaDisableDopClockGating:bdw - * - * Also see the related UCGTCL1 write in broadwell_init_clock_gating() - * to disable EUTC clock gating. - */ - WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2, - DOP_CLOCK_GATING_DISABLE); - - WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, - GEN8_SAMPLER_POWER_BYPASS_DIS); - - WA_SET_BIT_MASKED(HDC_CHICKEN0, - /* WaForceContextSaveRestoreNonCoherent:bdw */ - HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT | - /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */ - (IS_BDW_GT3(dev_priv) ? HDC_FENCE_DEST_SLM_DISABLE : 0)); - - return 0; -} - -static int chv_init_workarounds(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - int ret; - - ret = gen8_init_workarounds(engine); - if (ret) - return ret; - - /* WaDisableThreadStallDopClockGating:chv */ - WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE); - - /* Improve HiZ throughput on CHV. */ - WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X); - - return 0; -} - -static int gen9_init_workarounds(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - int ret; - - /* WaConextSwitchWithConcurrentTLBInvalidate:skl,bxt,kbl,glk,cfl */ - I915_WRITE(GEN9_CSFE_CHICKEN1_RCS, _MASKED_BIT_ENABLE(GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE)); - - /* WaEnableLbsSlaRetryTimerDecrement:skl,bxt,kbl,glk,cfl */ - I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) | - GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE); - - /* WaDisableKillLogic:bxt,skl,kbl */ - if (!IS_COFFEELAKE(dev_priv)) - I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | - ECOCHK_DIS_TLB); - - if (HAS_LLC(dev_priv)) { - /* WaCompressedResourceSamplerPbeMediaNewHashMode:skl,kbl - * - * Must match Display Engine. See - * WaCompressedResourceDisplayNewHashMode. - */ - WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, - GEN9_PBE_COMPRESSED_HASH_SELECTION); - WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7, - GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR); - - I915_WRITE(MMCD_MISC_CTRL, - I915_READ(MMCD_MISC_CTRL) | - MMCD_PCLA | - MMCD_HOTSPOT_EN); - } - - /* WaClearFlowControlGpgpuContextSave:skl,bxt,kbl,glk,cfl */ - /* WaDisablePartialInstShootdown:skl,bxt,kbl,glk,cfl */ - WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, - FLOW_CONTROL_ENABLE | - PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); - - /* Syncing dependencies between camera and graphics:skl,bxt,kbl */ - if (!IS_COFFEELAKE(dev_priv)) - WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, - GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC); - - /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt,kbl,glk,cfl */ - /* WaEnableSamplerGPGPUPreemptionSupport:skl,bxt,kbl,cfl */ - WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7, - GEN9_ENABLE_YV12_BUGFIX | - GEN9_ENABLE_GPGPU_PREEMPTION); - - /* Wa4x4STCOptimizationDisable:skl,bxt,kbl,glk,cfl */ - /* WaDisablePartialResolveInVc:skl,bxt,kbl,cfl */ - WA_SET_BIT_MASKED(CACHE_MODE_1, (GEN8_4x4_STC_OPTIMIZATION_DISABLE | - GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE)); - - /* WaCcsTlbPrefetchDisable:skl,bxt,kbl,glk,cfl */ - WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5, - GEN9_CCS_TLB_PREFETCH_ENABLE); - - /* WaForceContextSaveRestoreNonCoherent:skl,bxt,kbl,cfl */ - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT | - HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE); - - /* WaForceEnableNonCoherent and WaDisableHDCInvalidation are - * both tied to WaForceContextSaveRestoreNonCoherent - * in some hsds for skl. We keep the tie for all gen9. The - * documentation is a bit hazy and so we want to get common behaviour, - * even though there is no clear evidence we would need both on kbl/bxt. - * This area has been source of system hangs so we play it safe - * and mimic the skl regardless of what bspec says. - * - * Use Force Non-Coherent whenever executing a 3D context. This - * is a workaround for a possible hang in the unlikely event - * a TLB invalidation occurs during a PSD flush. - */ - - /* WaForceEnableNonCoherent:skl,bxt,kbl,cfl */ - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_FORCE_NON_COHERENT); - - /* WaDisableHDCInvalidation:skl,bxt,kbl,cfl */ - I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | - BDW_DISABLE_HDC_INVALIDATION); - - /* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt,kbl,cfl */ - if (IS_SKYLAKE(dev_priv) || - IS_KABYLAKE(dev_priv) || - IS_COFFEELAKE(dev_priv)) - WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, - GEN8_SAMPLER_POWER_BYPASS_DIS); - - /* WaDisableSTUnitPowerOptimization:skl,bxt,kbl,glk,cfl */ - WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE); - - /* WaProgramL3SqcReg1DefaultForPerf:bxt,glk */ - if (IS_GEN9_LP(dev_priv)) { - u32 val = I915_READ(GEN8_L3SQCREG1); - - val &= ~L3_PRIO_CREDITS_MASK; - val |= L3_GENERAL_PRIO_CREDITS(62) | L3_HIGH_PRIO_CREDITS(2); - I915_WRITE(GEN8_L3SQCREG1, val); - } - - /* WaOCLCoherentLineFlush:skl,bxt,kbl,cfl */ - I915_WRITE(GEN8_L3SQCREG4, (I915_READ(GEN8_L3SQCREG4) | - GEN8_LQSC_FLUSH_COHERENT_LINES)); - - /* - * Supporting preemption with fine-granularity requires changes in the - * batch buffer programming. Since we can't break old userspace, we - * need to set our default preemption level to safe value. Userspace is - * still able to use more fine-grained preemption levels, since in - * WaEnablePreemptionGranularityControlByUMD we're whitelisting the - * per-ctx register. As such, WaDisable{3D,GPGPU}MidCmdPreemption are - * not real HW workarounds, but merely a way to start using preemption - * while maintaining old contract with userspace. - */ - - /* WaDisable3DMidCmdPreemption:skl,bxt,glk,cfl,[cnl] */ - WA_CLR_BIT_MASKED(GEN8_CS_CHICKEN1, GEN9_PREEMPT_3D_OBJECT_LEVEL); - - /* WaDisableGPGPUMidCmdPreemption:skl,bxt,blk,cfl,[cnl] */ - WA_SET_FIELD_MASKED(GEN8_CS_CHICKEN1, GEN9_PREEMPT_GPGPU_LEVEL_MASK, - GEN9_PREEMPT_GPGPU_COMMAND_LEVEL); - - /* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt,glk,cfl */ - ret = wa_ring_whitelist_reg(engine, GEN9_CTX_PREEMPT_REG); - if (ret) - return ret; - - /* WaEnablePreemptionGranularityControlByUMD:skl,bxt,kbl,cfl,[cnl] */ - I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, - _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); - ret = wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1); - if (ret) - return ret; - - /* WaAllowUMDToModifyHDCChicken1:skl,bxt,kbl,glk,cfl */ - ret = wa_ring_whitelist_reg(engine, GEN8_HDC_CHICKEN1); - if (ret) - return ret; - - return 0; -} - -static int skl_tune_iz_hashing(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - u8 vals[3] = { 0, 0, 0 }; - unsigned int i; - - for (i = 0; i < 3; i++) { - u8 ss; - - /* - * Only consider slices where one, and only one, subslice has 7 - * EUs - */ - if (!is_power_of_2(INTEL_INFO(dev_priv)->sseu.subslice_7eu[i])) - continue; - - /* - * subslice_7eu[i] != 0 (because of the check above) and - * ss_max == 4 (maximum number of subslices possible per slice) - * - * -> 0 <= ss <= 3; - */ - ss = ffs(INTEL_INFO(dev_priv)->sseu.subslice_7eu[i]) - 1; - vals[i] = 3 - ss; - } - - if (vals[0] == 0 && vals[1] == 0 && vals[2] == 0) - return 0; - - /* Tune IZ hashing. See intel_device_info_runtime_init() */ - WA_SET_FIELD_MASKED(GEN7_GT_MODE, - GEN9_IZ_HASHING_MASK(2) | - GEN9_IZ_HASHING_MASK(1) | - GEN9_IZ_HASHING_MASK(0), - GEN9_IZ_HASHING(2, vals[2]) | - GEN9_IZ_HASHING(1, vals[1]) | - GEN9_IZ_HASHING(0, vals[0])); - - return 0; -} - -static int skl_init_workarounds(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - int ret; - - ret = gen9_init_workarounds(engine); - if (ret) - return ret; - - /* WaEnableGapsTsvCreditFix:skl */ - I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | - GEN9_GAPS_TSV_CREDIT_DISABLE)); - - /* WaDisableGafsUnitClkGating:skl */ - I915_WRITE(GEN7_UCGCTL4, (I915_READ(GEN7_UCGCTL4) | - GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE)); - - /* WaInPlaceDecompressionHang:skl */ - if (IS_SKL_REVID(dev_priv, SKL_REVID_H0, REVID_FOREVER)) - I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, - (I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | - GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS)); - - /* WaDisableLSQCROPERFforOCL:skl */ - ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4); - if (ret) - return ret; - - return skl_tune_iz_hashing(engine); -} - -static int bxt_init_workarounds(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - int ret; - - ret = gen9_init_workarounds(engine); - if (ret) - return ret; - - /* WaDisableThreadStallDopClockGating:bxt */ - WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, - STALL_DOP_GATING_DISABLE); - - /* WaDisablePooledEuLoadBalancingFix:bxt */ - I915_WRITE(FF_SLICE_CS_CHICKEN2, - _MASKED_BIT_ENABLE(GEN9_POOLED_EU_LOAD_BALANCING_FIX_DISABLE)); - - /* WaToEnableHwFixForPushConstHWBug:bxt */ - WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, - GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); - - /* WaInPlaceDecompressionHang:bxt */ - I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, - (I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | - GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS)); - - return 0; -} - -static int cnl_init_workarounds(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - int ret; - - /* WaDisableI2mCycleOnWRPort:cnl (pre-prod) */ - if (IS_CNL_REVID(dev_priv, CNL_REVID_B0, CNL_REVID_B0)) - I915_WRITE(GAMT_CHKN_BIT_REG, - (I915_READ(GAMT_CHKN_BIT_REG) | - GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT)); - - /* WaForceContextSaveRestoreNonCoherent:cnl */ - WA_SET_BIT_MASKED(CNL_HDC_CHICKEN0, - HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT); - - /* WaThrottleEUPerfToAvoidTDBackPressure:cnl(pre-prod) */ - if (IS_CNL_REVID(dev_priv, CNL_REVID_B0, CNL_REVID_B0)) - WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, THROTTLE_12_5); - - /* WaDisableReplayBufferBankArbitrationOptimization:cnl */ - WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, - GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); - - /* WaDisableEnhancedSBEVertexCaching:cnl (pre-prod) */ - if (IS_CNL_REVID(dev_priv, 0, CNL_REVID_B0)) - WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, - GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE); - - /* WaInPlaceDecompressionHang:cnl */ - I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, - (I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | - GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS)); - - /* WaPushConstantDereferenceHoldDisable:cnl */ - WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2, PUSH_CONSTANT_DEREF_DISABLE); - - /* FtrEnableFastAnisoL1BankingFix: cnl */ - WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, CNL_FAST_ANISO_L1_BANKING_FIX); - - /* WaDisable3DMidCmdPreemption:cnl */ - WA_CLR_BIT_MASKED(GEN8_CS_CHICKEN1, GEN9_PREEMPT_3D_OBJECT_LEVEL); - - /* WaDisableGPGPUMidCmdPreemption:cnl */ - WA_SET_FIELD_MASKED(GEN8_CS_CHICKEN1, GEN9_PREEMPT_GPGPU_LEVEL_MASK, - GEN9_PREEMPT_GPGPU_COMMAND_LEVEL); - - /* WaEnablePreemptionGranularityControlByUMD:cnl */ - I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, - _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); - ret= wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1); - if (ret) - return ret; - - /* WaDisableEarlyEOT:cnl */ - WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, DISABLE_EARLY_EOT); - - return 0; -} - -static int kbl_init_workarounds(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - int ret; - - ret = gen9_init_workarounds(engine); - if (ret) - return ret; - - /* WaEnableGapsTsvCreditFix:kbl */ - I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | - GEN9_GAPS_TSV_CREDIT_DISABLE)); - - /* WaDisableDynamicCreditSharing:kbl */ - if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0)) - I915_WRITE(GAMT_CHKN_BIT_REG, - (I915_READ(GAMT_CHKN_BIT_REG) | - GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING)); - - /* WaDisableFenceDestinationToSLM:kbl (pre-prod) */ - if (IS_KBL_REVID(dev_priv, KBL_REVID_A0, KBL_REVID_A0)) - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_FENCE_DEST_SLM_DISABLE); - - /* WaToEnableHwFixForPushConstHWBug:kbl */ - if (IS_KBL_REVID(dev_priv, KBL_REVID_C0, REVID_FOREVER)) - WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, - GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); - - /* WaDisableGafsUnitClkGating:kbl */ - I915_WRITE(GEN7_UCGCTL4, (I915_READ(GEN7_UCGCTL4) | - GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE)); - - /* WaDisableSbeCacheDispatchPortSharing:kbl */ - WA_SET_BIT_MASKED( - GEN7_HALF_SLICE_CHICKEN1, - GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); - - /* WaInPlaceDecompressionHang:kbl */ - I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, - (I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | - GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS)); - - /* WaDisableLSQCROPERFforOCL:kbl */ - ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4); - if (ret) - return ret; - - return 0; -} - -static int glk_init_workarounds(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - int ret; - - ret = gen9_init_workarounds(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); - - return 0; -} - -static int cfl_init_workarounds(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - int ret; - - ret = gen9_init_workarounds(engine); - if (ret) - return ret; - - /* WaEnableGapsTsvCreditFix:cfl */ - I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | - GEN9_GAPS_TSV_CREDIT_DISABLE)); - - /* WaToEnableHwFixForPushConstHWBug:cfl */ - WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, - GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); - - /* WaDisableGafsUnitClkGating:cfl */ - I915_WRITE(GEN7_UCGCTL4, (I915_READ(GEN7_UCGCTL4) | - GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE)); - - /* WaDisableSbeCacheDispatchPortSharing:cfl */ - WA_SET_BIT_MASKED( - GEN7_HALF_SLICE_CHICKEN1, - GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); - - /* WaInPlaceDecompressionHang:cfl */ - I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, - (I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | - GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS)); - - return 0; -} - -int init_workarounds_ring(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - int err; - - if (GEM_WARN_ON(engine->id != RCS)) - return -EINVAL; - - dev_priv->workarounds.count = 0; - dev_priv->workarounds.hw_whitelist_count[engine->id] = 0; - - if (IS_BROADWELL(dev_priv)) - err = bdw_init_workarounds(engine); - else if (IS_CHERRYVIEW(dev_priv)) - err = chv_init_workarounds(engine); - else if (IS_SKYLAKE(dev_priv)) - err = skl_init_workarounds(engine); - else if (IS_BROXTON(dev_priv)) - err = bxt_init_workarounds(engine); - else if (IS_KABYLAKE(dev_priv)) - err = kbl_init_workarounds(engine); - else if (IS_GEMINILAKE(dev_priv)) - err = glk_init_workarounds(engine); - else if (IS_COFFEELAKE(dev_priv)) - err = cfl_init_workarounds(engine); - else if (IS_CANNONLAKE(dev_priv)) - err = cnl_init_workarounds(engine); - else - err = 0; - if (err) - return err; - - DRM_DEBUG_DRIVER("%s: Number of context specific w/a: %d\n", - engine->name, dev_priv->workarounds.count); - return 0; -} - -int intel_ring_workarounds_emit(struct i915_request *rq) -{ - struct i915_workarounds *w = &rq->i915->workarounds; - u32 *cs; - int ret, i; - - if (w->count == 0) - return 0; - - ret = rq->engine->emit_flush(rq, EMIT_BARRIER); - if (ret) - return ret; - - cs = intel_ring_begin(rq, w->count * 2 + 2); - if (IS_ERR(cs)) - return PTR_ERR(cs); - - *cs++ = MI_LOAD_REGISTER_IMM(w->count); - for (i = 0; i < w->count; i++) { - *cs++ = i915_mmio_reg_offset(w->reg[i].addr); - *cs++ = w->reg[i].value; - } - *cs++ = MI_NOOP; - - intel_ring_advance(rq, cs); - - ret = rq->engine->emit_flush(rq, EMIT_BARRIER); - if (ret) - return ret; - - return 0; -} - static bool ring_is_idle(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 665d9e82e954..03b9d5ae883a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -139,6 +139,7 @@ #include "i915_gem_render_state.h" #include "intel_lrc_reg.h" #include "intel_mocs.h" +#include "intel_workarounds.h" #define RING_EXECLIST_QFULL (1 << 0x2) #define RING_EXECLIST1_VALID (1 << 0x3) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 04d9d9a946a7..36acc32374e4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -36,6 +36,7 @@ #include "i915_gem_render_state.h" #include "i915_trace.h" #include "intel_drv.h" +#include "intel_workarounds.h" /* Rough estimate of the typical request size, performing a flush, * set-context and then emitting the batch. diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 256d58487559..717041640135 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -885,9 +885,6 @@ static inline u32 intel_engine_last_submit(struct intel_engine_cs *engine) return READ_ONCE(engine->timeline->seqno); } -int init_workarounds_ring(struct intel_engine_cs *engine); -int intel_ring_workarounds_emit(struct i915_request *rq); - void intel_engine_get_instdone(struct intel_engine_cs *engine, struct intel_instdone *instdone); diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c new file mode 100644 index 000000000000..d60a37700f84 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -0,0 +1,686 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright © 2014-2018 Intel Corporation + */ + +#include "i915_drv.h" +#include "intel_workarounds.h" + +/** + * DOC: Hardware workarounds + * + * This file is intended as a central place to implement most [1]_ of the + * required workarounds for hardware to work as originally intended. They fall + * in five basic categories depending on how/when they are applied: + * + * - Workarounds that touch registers that are saved/restored to/from the HW + * context image. The list is emitted (via Load Register Immediate commands) + * everytime a new context is created. + * - GT workarounds. The list of these WAs is applied whenever these registers + * revert to default values (on GPU reset, suspend/resume [2]_, etc..). + * - Display workarounds. The list is applied during display clock-gating + * initialization. + * - Workarounds that whitelist a privileged register, so that UMDs can manage + * them directly. This is just a special case of a MMMIO workaround (as we + * write the list of these to/be-whitelisted registers to some special HW + * registers). + * - Workaround batchbuffers, that get executed automatically by the hardware + * on every HW context restore. + * + * .. [1] Please notice that there are other WAs that, due to their nature, + * cannot be applied from a central place. Those are peppered around the rest + * of the code, as needed. + * + * .. [2] Technically, some registers are powercontext saved & restored, so they + * survive a suspend/resume. In practice, writing them again is not too + * costly and simplifies things. We can revisit this in the future. + * + * Layout + * '''''' + * + * Keep things in this file ordered by WA type, as per the above (context, GT, + * display, register whitelist, batchbuffer). Then, inside each type, keep the + * following order: + * + * - Infrastructure functions and macros + * - WAs per platform in standard gen/chrono order + * - Public functions to init or apply the given workaround type. + */ + +static int wa_add(struct drm_i915_private *dev_priv, + i915_reg_t addr, + const u32 mask, const u32 val) +{ + const unsigned int idx = dev_priv->workarounds.count; + + if (WARN_ON(idx >= I915_MAX_WA_REGS)) + return -ENOSPC; + + dev_priv->workarounds.reg[idx].addr = addr; + dev_priv->workarounds.reg[idx].value = val; + dev_priv->workarounds.reg[idx].mask = mask; + + dev_priv->workarounds.count++; + + return 0; +} + +#define WA_REG(addr, mask, val) do { \ + const int r = wa_add(dev_priv, (addr), (mask), (val)); \ + if (r) \ + return r; \ + } while (0) + +#define WA_SET_BIT_MASKED(addr, mask) \ + WA_REG(addr, (mask), _MASKED_BIT_ENABLE(mask)) + +#define WA_CLR_BIT_MASKED(addr, mask) \ + WA_REG(addr, (mask), _MASKED_BIT_DISABLE(mask)) + +#define WA_SET_FIELD_MASKED(addr, mask, value) \ + WA_REG(addr, (mask), _MASKED_FIELD(mask, value)) + +static int wa_ring_whitelist_reg(struct intel_engine_cs *engine, + i915_reg_t reg) +{ + struct drm_i915_private *dev_priv = engine->i915; + struct i915_workarounds *wa = &dev_priv->workarounds; + const unsigned int index = wa->hw_whitelist_count[engine->id]; + + if (WARN_ON(index >= RING_MAX_NONPRIV_SLOTS)) + return -EINVAL; + + I915_WRITE(RING_FORCE_TO_NONPRIV(engine->mmio_base, index), + i915_mmio_reg_offset(reg)); + wa->hw_whitelist_count[engine->id]++; + + return 0; +} + +static int gen8_init_workarounds(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + + WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); + + /* WaDisableAsyncFlipPerfMode:bdw,chv */ + WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE); + + /* WaDisablePartialInstShootdown:bdw,chv */ + WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, + PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); + + /* Use Force Non-Coherent whenever executing a 3D context. This is a + * workaround for for a possible hang in the unlikely event a TLB + * invalidation occurs during a PSD flush. + */ + /* WaForceEnableNonCoherent:bdw,chv */ + /* WaHdcDisableFetchWhenMasked:bdw,chv */ + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_DONOT_FETCH_MEM_WHEN_MASKED | + HDC_FORCE_NON_COHERENT); + + /* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0: + * "The Hierarchical Z RAW Stall Optimization allows non-overlapping + * polygons in the same 8x4 pixel/sample area to be processed without + * stalling waiting for the earlier ones to write to Hierarchical Z + * buffer." + * + * This optimization is off by default for BDW and CHV; turn it on. + */ + WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE); + + /* Wa4x4STCOptimizationDisable:bdw,chv */ + WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE); + + /* + * BSpec recommends 8x4 when MSAA is used, + * however in practice 16x4 seems fastest. + * + * Note that PS/WM thread counts depend on the WIZ hashing + * disable bit, which we don't touch here, but it's good + * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM). + */ + WA_SET_FIELD_MASKED(GEN7_GT_MODE, + GEN6_WIZ_HASHING_MASK, + GEN6_WIZ_HASHING_16x4); + + return 0; +} + +static int bdw_init_workarounds(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + int ret; + + ret = gen8_init_workarounds(engine); + if (ret) + return ret; + + /* WaDisableThreadStallDopClockGating:bdw (pre-production) */ + WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE); + + /* WaDisableDopClockGating:bdw + * + * Also see the related UCGTCL1 write in broadwell_init_clock_gating() + * to disable EUTC clock gating. + */ + WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2, + DOP_CLOCK_GATING_DISABLE); + + WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, + GEN8_SAMPLER_POWER_BYPASS_DIS); + + WA_SET_BIT_MASKED(HDC_CHICKEN0, + /* WaForceContextSaveRestoreNonCoherent:bdw */ + HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT | + /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */ + (IS_BDW_GT3(dev_priv) ? HDC_FENCE_DEST_SLM_DISABLE : 0)); + + return 0; +} + +static int chv_init_workarounds(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + int ret; + + ret = gen8_init_workarounds(engine); + if (ret) + return ret; + + /* WaDisableThreadStallDopClockGating:chv */ + WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE); + + /* Improve HiZ throughput on CHV. */ + WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X); + + return 0; +} + +static int gen9_init_workarounds(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + int ret; + + /* WaConextSwitchWithConcurrentTLBInvalidate:skl,bxt,kbl,glk,cfl */ + I915_WRITE(GEN9_CSFE_CHICKEN1_RCS, + _MASKED_BIT_ENABLE(GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE)); + + /* WaEnableLbsSlaRetryTimerDecrement:skl,bxt,kbl,glk,cfl */ + I915_WRITE(BDW_SCRATCH1, + I915_READ(BDW_SCRATCH1) | + GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE); + + /* WaDisableKillLogic:bxt,skl,kbl */ + if (!IS_COFFEELAKE(dev_priv)) + I915_WRITE(GAM_ECOCHK, + I915_READ(GAM_ECOCHK) | ECOCHK_DIS_TLB); + + if (HAS_LLC(dev_priv)) { + /* WaCompressedResourceSamplerPbeMediaNewHashMode:skl,kbl + * + * Must match Display Engine. See + * WaCompressedResourceDisplayNewHashMode. + */ + WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, + GEN9_PBE_COMPRESSED_HASH_SELECTION); + WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7, + GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR); + + I915_WRITE(MMCD_MISC_CTRL, + I915_READ(MMCD_MISC_CTRL) | + MMCD_PCLA | + MMCD_HOTSPOT_EN); + } + + /* WaClearFlowControlGpgpuContextSave:skl,bxt,kbl,glk,cfl */ + /* WaDisablePartialInstShootdown:skl,bxt,kbl,glk,cfl */ + WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, + FLOW_CONTROL_ENABLE | + PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); + + /* Syncing dependencies between camera and graphics:skl,bxt,kbl */ + if (!IS_COFFEELAKE(dev_priv)) + WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, + GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC); + + /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt,kbl,glk,cfl */ + /* WaEnableSamplerGPGPUPreemptionSupport:skl,bxt,kbl,cfl */ + WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7, + GEN9_ENABLE_YV12_BUGFIX | + GEN9_ENABLE_GPGPU_PREEMPTION); + + /* Wa4x4STCOptimizationDisable:skl,bxt,kbl,glk,cfl */ + /* WaDisablePartialResolveInVc:skl,bxt,kbl,cfl */ + WA_SET_BIT_MASKED(CACHE_MODE_1, + GEN8_4x4_STC_OPTIMIZATION_DISABLE | + GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE); + + /* WaCcsTlbPrefetchDisable:skl,bxt,kbl,glk,cfl */ + WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5, + GEN9_CCS_TLB_PREFETCH_ENABLE); + + /* WaForceContextSaveRestoreNonCoherent:skl,bxt,kbl,cfl */ + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT | + HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE); + + /* WaForceEnableNonCoherent and WaDisableHDCInvalidation are + * both tied to WaForceContextSaveRestoreNonCoherent + * in some hsds for skl. We keep the tie for all gen9. The + * documentation is a bit hazy and so we want to get common behaviour, + * even though there is no clear evidence we would need both on kbl/bxt. + * This area has been source of system hangs so we play it safe + * and mimic the skl regardless of what bspec says. + * + * Use Force Non-Coherent whenever executing a 3D context. This + * is a workaround for a possible hang in the unlikely event + * a TLB invalidation occurs during a PSD flush. + */ + + /* WaForceEnableNonCoherent:skl,bxt,kbl,cfl */ + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_FORCE_NON_COHERENT); + + /* WaDisableHDCInvalidation:skl,bxt,kbl,cfl */ + I915_WRITE(GAM_ECOCHK, + I915_READ(GAM_ECOCHK) | BDW_DISABLE_HDC_INVALIDATION); + + /* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt,kbl,cfl */ + if (IS_SKYLAKE(dev_priv) || + IS_KABYLAKE(dev_priv) || + IS_COFFEELAKE(dev_priv)) + WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, + GEN8_SAMPLER_POWER_BYPASS_DIS); + + /* WaDisableSTUnitPowerOptimization:skl,bxt,kbl,glk,cfl */ + WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE); + + /* WaProgramL3SqcReg1DefaultForPerf:bxt,glk */ + if (IS_GEN9_LP(dev_priv)) { + u32 val = I915_READ(GEN8_L3SQCREG1); + + val &= ~L3_PRIO_CREDITS_MASK; + val |= L3_GENERAL_PRIO_CREDITS(62) | L3_HIGH_PRIO_CREDITS(2); + I915_WRITE(GEN8_L3SQCREG1, val); + } + + /* WaOCLCoherentLineFlush:skl,bxt,kbl,cfl */ + I915_WRITE(GEN8_L3SQCREG4, + I915_READ(GEN8_L3SQCREG4) | GEN8_LQSC_FLUSH_COHERENT_LINES); + + /* + * Supporting preemption with fine-granularity requires changes in the + * batch buffer programming. Since we can't break old userspace, we + * need to set our default preemption level to safe value. Userspace is + * still able to use more fine-grained preemption levels, since in + * WaEnablePreemptionGranularityControlByUMD we're whitelisting the + * per-ctx register. As such, WaDisable{3D,GPGPU}MidCmdPreemption are + * not real HW workarounds, but merely a way to start using preemption + * while maintaining old contract with userspace. + */ + + /* WaDisable3DMidCmdPreemption:skl,bxt,glk,cfl,[cnl] */ + WA_CLR_BIT_MASKED(GEN8_CS_CHICKEN1, GEN9_PREEMPT_3D_OBJECT_LEVEL); + + /* WaDisableGPGPUMidCmdPreemption:skl,bxt,blk,cfl,[cnl] */ + WA_SET_FIELD_MASKED(GEN8_CS_CHICKEN1, + GEN9_PREEMPT_GPGPU_LEVEL_MASK, + GEN9_PREEMPT_GPGPU_COMMAND_LEVEL); + + /* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt,glk,cfl */ + ret = wa_ring_whitelist_reg(engine, GEN9_CTX_PREEMPT_REG); + if (ret) + return ret; + + /* WaEnablePreemptionGranularityControlByUMD:skl,bxt,kbl,cfl,[cnl] */ + I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, + _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); + ret = wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1); + if (ret) + return ret; + + /* WaAllowUMDToModifyHDCChicken1:skl,bxt,kbl,glk,cfl */ + ret = wa_ring_whitelist_reg(engine, GEN8_HDC_CHICKEN1); + if (ret) + return ret; + + return 0; +} + +static int skl_tune_iz_hashing(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + u8 vals[3] = { 0, 0, 0 }; + unsigned int i; + + for (i = 0; i < 3; i++) { + u8 ss; + + /* + * Only consider slices where one, and only one, subslice has 7 + * EUs + */ + if (!is_power_of_2(INTEL_INFO(dev_priv)->sseu.subslice_7eu[i])) + continue; + + /* + * subslice_7eu[i] != 0 (because of the check above) and + * ss_max == 4 (maximum number of subslices possible per slice) + * + * -> 0 <= ss <= 3; + */ + ss = ffs(INTEL_INFO(dev_priv)->sseu.subslice_7eu[i]) - 1; + vals[i] = 3 - ss; + } + + if (vals[0] == 0 && vals[1] == 0 && vals[2] == 0) + return 0; + + /* Tune IZ hashing. See intel_device_info_runtime_init() */ + WA_SET_FIELD_MASKED(GEN7_GT_MODE, + GEN9_IZ_HASHING_MASK(2) | + GEN9_IZ_HASHING_MASK(1) | + GEN9_IZ_HASHING_MASK(0), + GEN9_IZ_HASHING(2, vals[2]) | + GEN9_IZ_HASHING(1, vals[1]) | + GEN9_IZ_HASHING(0, vals[0])); + + return 0; +} + +static int skl_init_workarounds(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + int ret; + + ret = gen9_init_workarounds(engine); + if (ret) + return ret; + + /* WaEnableGapsTsvCreditFix:skl */ + I915_WRITE(GEN8_GARBCNTL, + I915_READ(GEN8_GARBCNTL) | GEN9_GAPS_TSV_CREDIT_DISABLE); + + /* WaDisableGafsUnitClkGating:skl */ + I915_WRITE(GEN7_UCGCTL4, + I915_READ(GEN7_UCGCTL4) | GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE); + + /* WaInPlaceDecompressionHang:skl */ + if (IS_SKL_REVID(dev_priv, SKL_REVID_H0, REVID_FOREVER)) + I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, + I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | + GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); + + /* WaDisableLSQCROPERFforOCL:skl */ + ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4); + if (ret) + return ret; + + return skl_tune_iz_hashing(engine); +} + +static int bxt_init_workarounds(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + int ret; + + ret = gen9_init_workarounds(engine); + if (ret) + return ret; + + /* WaDisableThreadStallDopClockGating:bxt */ + WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, + STALL_DOP_GATING_DISABLE); + + /* WaDisablePooledEuLoadBalancingFix:bxt */ + I915_WRITE(FF_SLICE_CS_CHICKEN2, + _MASKED_BIT_ENABLE(GEN9_POOLED_EU_LOAD_BALANCING_FIX_DISABLE)); + + /* WaToEnableHwFixForPushConstHWBug:bxt */ + WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, + GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); + + /* WaInPlaceDecompressionHang:bxt */ + I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, + I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | + GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); + + return 0; +} + +static int cnl_init_workarounds(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + int ret; + + /* WaDisableI2mCycleOnWRPort:cnl (pre-prod) */ + if (IS_CNL_REVID(dev_priv, CNL_REVID_B0, CNL_REVID_B0)) + I915_WRITE(GAMT_CHKN_BIT_REG, + I915_READ(GAMT_CHKN_BIT_REG) | + GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT); + + /* WaForceContextSaveRestoreNonCoherent:cnl */ + WA_SET_BIT_MASKED(CNL_HDC_CHICKEN0, + HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT); + + /* WaThrottleEUPerfToAvoidTDBackPressure:cnl(pre-prod) */ + if (IS_CNL_REVID(dev_priv, CNL_REVID_B0, CNL_REVID_B0)) + WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, THROTTLE_12_5); + + /* WaDisableReplayBufferBankArbitrationOptimization:cnl */ + WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, + GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); + + /* WaDisableEnhancedSBEVertexCaching:cnl (pre-prod) */ + if (IS_CNL_REVID(dev_priv, 0, CNL_REVID_B0)) + WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, + GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE); + + /* WaInPlaceDecompressionHang:cnl */ + I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, + I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | + GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); + + /* WaPushConstantDereferenceHoldDisable:cnl */ + WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2, PUSH_CONSTANT_DEREF_DISABLE); + + /* FtrEnableFastAnisoL1BankingFix: cnl */ + WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, CNL_FAST_ANISO_L1_BANKING_FIX); + + /* WaDisable3DMidCmdPreemption:cnl */ + WA_CLR_BIT_MASKED(GEN8_CS_CHICKEN1, GEN9_PREEMPT_3D_OBJECT_LEVEL); + + /* WaDisableGPGPUMidCmdPreemption:cnl */ + WA_SET_FIELD_MASKED(GEN8_CS_CHICKEN1, + GEN9_PREEMPT_GPGPU_LEVEL_MASK, + GEN9_PREEMPT_GPGPU_COMMAND_LEVEL); + + /* WaEnablePreemptionGranularityControlByUMD:cnl */ + I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, + _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); + ret = wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1); + if (ret) + return ret; + + /* WaDisableEarlyEOT:cnl */ + WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, DISABLE_EARLY_EOT); + + return 0; +} + +static int kbl_init_workarounds(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + int ret; + + ret = gen9_init_workarounds(engine); + if (ret) + return ret; + + /* WaEnableGapsTsvCreditFix:kbl */ + I915_WRITE(GEN8_GARBCNTL, + I915_READ(GEN8_GARBCNTL) | GEN9_GAPS_TSV_CREDIT_DISABLE); + + /* WaDisableDynamicCreditSharing:kbl */ + if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0)) + I915_WRITE(GAMT_CHKN_BIT_REG, + I915_READ(GAMT_CHKN_BIT_REG) | + GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING); + + /* WaDisableFenceDestinationToSLM:kbl (pre-prod) */ + if (IS_KBL_REVID(dev_priv, KBL_REVID_A0, KBL_REVID_A0)) + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_FENCE_DEST_SLM_DISABLE); + + /* WaToEnableHwFixForPushConstHWBug:kbl */ + if (IS_KBL_REVID(dev_priv, KBL_REVID_C0, REVID_FOREVER)) + WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, + GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); + + /* WaDisableGafsUnitClkGating:kbl */ + I915_WRITE(GEN7_UCGCTL4, + I915_READ(GEN7_UCGCTL4) | GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE); + + /* WaDisableSbeCacheDispatchPortSharing:kbl */ + WA_SET_BIT_MASKED(GEN7_HALF_SLICE_CHICKEN1, + GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); + + /* WaInPlaceDecompressionHang:kbl */ + I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, + I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | + GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); + + /* WaDisableLSQCROPERFforOCL:kbl */ + ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4); + if (ret) + return ret; + + return 0; +} + +static int glk_init_workarounds(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + int ret; + + ret = gen9_init_workarounds(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); + + return 0; +} + +static int cfl_init_workarounds(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + int ret; + + ret = gen9_init_workarounds(engine); + if (ret) + return ret; + + /* WaEnableGapsTsvCreditFix:cfl */ + I915_WRITE(GEN8_GARBCNTL, + I915_READ(GEN8_GARBCNTL) | GEN9_GAPS_TSV_CREDIT_DISABLE); + + /* WaToEnableHwFixForPushConstHWBug:cfl */ + WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, + GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); + + /* WaDisableGafsUnitClkGating:cfl */ + I915_WRITE(GEN7_UCGCTL4, + I915_READ(GEN7_UCGCTL4) | GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE); + + /* WaDisableSbeCacheDispatchPortSharing:cfl */ + WA_SET_BIT_MASKED(GEN7_HALF_SLICE_CHICKEN1, + GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); + + /* WaInPlaceDecompressionHang:cfl */ + I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, + I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | + GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); + + return 0; +} + +int init_workarounds_ring(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + int err; + + if (GEM_WARN_ON(engine->id != RCS)) + return -EINVAL; + + dev_priv->workarounds.count = 0; + dev_priv->workarounds.hw_whitelist_count[engine->id] = 0; + + if (IS_BROADWELL(dev_priv)) + err = bdw_init_workarounds(engine); + else if (IS_CHERRYVIEW(dev_priv)) + err = chv_init_workarounds(engine); + else if (IS_SKYLAKE(dev_priv)) + err = skl_init_workarounds(engine); + else if (IS_BROXTON(dev_priv)) + err = bxt_init_workarounds(engine); + else if (IS_KABYLAKE(dev_priv)) + err = kbl_init_workarounds(engine); + else if (IS_GEMINILAKE(dev_priv)) + err = glk_init_workarounds(engine); + else if (IS_COFFEELAKE(dev_priv)) + err = cfl_init_workarounds(engine); + else if (IS_CANNONLAKE(dev_priv)) + err = cnl_init_workarounds(engine); + else + err = 0; + if (err) + return err; + + DRM_DEBUG_DRIVER("%s: Number of context specific w/a: %d\n", + engine->name, dev_priv->workarounds.count); + return 0; +} + +int intel_ring_workarounds_emit(struct i915_request *rq) +{ + struct i915_workarounds *w = &rq->i915->workarounds; + u32 *cs; + int ret, i; + + if (w->count == 0) + return 0; + + ret = rq->engine->emit_flush(rq, EMIT_BARRIER); + if (ret) + return ret; + + cs = intel_ring_begin(rq, w->count * 2 + 2); + if (IS_ERR(cs)) + return PTR_ERR(cs); + + *cs++ = MI_LOAD_REGISTER_IMM(w->count); + for (i = 0; i < w->count; i++) { + *cs++ = i915_mmio_reg_offset(w->reg[i].addr); + *cs++ = w->reg[i].value; + } + *cs++ = MI_NOOP; + + intel_ring_advance(rq, cs); + + ret = rq->engine->emit_flush(rq, EMIT_BARRIER); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/gpu/drm/i915/intel_workarounds.h b/drivers/gpu/drm/i915/intel_workarounds.h new file mode 100644 index 000000000000..2afea73aeeae --- /dev/null +++ b/drivers/gpu/drm/i915/intel_workarounds.h @@ -0,0 +1,13 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright © 2014-2018 Intel Corporation + */ + +#ifndef _I915_WORKAROUNDS_H_ +#define _I915_WORKAROUNDS_H_ + +int init_workarounds_ring(struct intel_engine_cs *engine); +int intel_ring_workarounds_emit(struct i915_request *rq); + +#endif -- cgit v1.2.3 From 59b449d5c82af03acdfc3f9a343c9d085ab5568f Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Tue, 10 Apr 2018 09:12:47 -0700 Subject: drm/i915: Split out functions for different kinds of workarounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are different kind of workarounds (those that modify registers that live in the context image, those that modify global registers, those that whitelist registers, etc...) and they have different requirements in terms of where they are applied and how. Also, by splitting them apart, it should be easier to decide where a new workaround should go. v2: - Add multiple MISSING_CASE - Rebased v3: - Rename mmio_workarounds to gt_workarounds (Chris, Mika) - Create empty placeholders for BDW and CHV GT WAs - Rebased v4: Rebased v5: - Rebased - FORCE_TO_NONPRIV register exists since BDW, so make a path for it to achieve universality, even if empty (Chris) Signed-off-by: Oscar Mateo Cc: Mika Kuoppala Cc: Ville Syrjälä Reviewed-by: Chris Wilson [ickle: appease checkpatch] Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/1523376767-18480-2-git-send-email-oscar.mateo@intel.com --- drivers/gpu/drm/i915/i915_gem.c | 3 + drivers/gpu/drm/i915/i915_gem_context.c | 6 + drivers/gpu/drm/i915/intel_lrc.c | 14 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 8 +- drivers/gpu/drm/i915/intel_workarounds.c | 638 +++++++++++++++++++------------ drivers/gpu/drm/i915/intel_workarounds.h | 8 +- 6 files changed, 436 insertions(+), 241 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 60cf7cfc24ee..4c9d2a6f7d28 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -35,6 +35,7 @@ #include "intel_drv.h" #include "intel_frontbuffer.h" #include "intel_mocs.h" +#include "intel_workarounds.h" #include "i915_gemfs.h" #include #include @@ -5191,6 +5192,8 @@ int i915_gem_init_hw(struct drm_i915_private *dev_priv) } } + intel_gt_workarounds_apply(dev_priv); + i915_gem_init_swizzling(dev_priv); /* diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 5cfac0255758..9b3834a846e8 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -90,6 +90,7 @@ #include #include "i915_drv.h" #include "i915_trace.h" +#include "intel_workarounds.h" #define ALL_L3_SLICES(dev) (1 << NUM_L3_SLICES(dev)) - 1 @@ -459,11 +460,16 @@ static bool needs_preempt_context(struct drm_i915_private *i915) int i915_gem_contexts_init(struct drm_i915_private *dev_priv) { struct i915_gem_context *ctx; + int ret; /* Reassure ourselves we are only called once */ GEM_BUG_ON(dev_priv->kernel_context); GEM_BUG_ON(dev_priv->preempt_context); + ret = intel_ctx_workarounds_init(dev_priv); + if (ret) + return ret; + INIT_LIST_HEAD(&dev_priv->contexts.list); INIT_WORK(&dev_priv->contexts.free_work, contexts_free_worker); init_llist_head(&dev_priv->contexts.free_list); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 03b9d5ae883a..c7c85134a84a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1744,6 +1744,10 @@ static int gen8_init_render_ring(struct intel_engine_cs *engine) if (ret) return ret; + ret = intel_whitelist_workarounds_apply(engine); + if (ret) + return ret; + /* We need to disable the AsyncFlip performance optimisations in order * to use MI_WAIT_FOR_EVENT within the CS. It should already be * programmed to '1' on all products. @@ -1754,7 +1758,7 @@ static int gen8_init_render_ring(struct intel_engine_cs *engine) I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING)); - return init_workarounds_ring(engine); + return 0; } static int gen9_init_render_ring(struct intel_engine_cs *engine) @@ -1765,7 +1769,11 @@ static int gen9_init_render_ring(struct intel_engine_cs *engine) if (ret) return ret; - return init_workarounds_ring(engine); + ret = intel_whitelist_workarounds_apply(engine); + if (ret) + return ret; + + return 0; } static void reset_common_ring(struct intel_engine_cs *engine, @@ -2090,7 +2098,7 @@ static int gen8_init_rcs_context(struct i915_request *rq) { int ret; - ret = intel_ring_workarounds_emit(rq); + ret = intel_ctx_workarounds_emit(rq); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 36acc32374e4..757bb0990c07 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -600,7 +600,7 @@ static int intel_rcs_ctx_init(struct i915_request *rq) { int ret; - ret = intel_ring_workarounds_emit(rq); + ret = intel_ctx_workarounds_emit(rq); if (ret != 0) return ret; @@ -618,6 +618,10 @@ static int init_render_ring(struct intel_engine_cs *engine) if (ret) return ret; + ret = intel_whitelist_workarounds_apply(engine); + if (ret) + return ret; + /* WaTimedSingleVertexDispatch:cl,bw,ctg,elk,ilk,snb */ if (IS_GEN(dev_priv, 4, 6)) I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH)); @@ -659,7 +663,7 @@ static int init_render_ring(struct intel_engine_cs *engine) if (INTEL_GEN(dev_priv) >= 6) I915_WRITE_IMR(engine, ~engine->irq_keep_mask); - return init_workarounds_ring(engine); + return 0; } static u32 *gen6_signal(struct i915_request *rq, u32 *cs) diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c index d60a37700f84..bbbf4ed4aa97 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.c +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -81,27 +81,8 @@ static int wa_add(struct drm_i915_private *dev_priv, #define WA_SET_FIELD_MASKED(addr, mask, value) \ WA_REG(addr, (mask), _MASKED_FIELD(mask, value)) -static int wa_ring_whitelist_reg(struct intel_engine_cs *engine, - i915_reg_t reg) +static int gen8_ctx_workarounds_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = engine->i915; - struct i915_workarounds *wa = &dev_priv->workarounds; - const unsigned int index = wa->hw_whitelist_count[engine->id]; - - if (WARN_ON(index >= RING_MAX_NONPRIV_SLOTS)) - return -EINVAL; - - I915_WRITE(RING_FORCE_TO_NONPRIV(engine->mmio_base, index), - i915_mmio_reg_offset(reg)); - wa->hw_whitelist_count[engine->id]++; - - return 0; -} - -static int gen8_init_workarounds(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); /* WaDisableAsyncFlipPerfMode:bdw,chv */ @@ -149,12 +130,11 @@ static int gen8_init_workarounds(struct intel_engine_cs *engine) return 0; } -static int bdw_init_workarounds(struct intel_engine_cs *engine) +static int bdw_ctx_workarounds_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = engine->i915; int ret; - ret = gen8_init_workarounds(engine); + ret = gen8_ctx_workarounds_init(dev_priv); if (ret) return ret; @@ -181,12 +161,11 @@ static int bdw_init_workarounds(struct intel_engine_cs *engine) return 0; } -static int chv_init_workarounds(struct intel_engine_cs *engine) +static int chv_ctx_workarounds_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = engine->i915; int ret; - ret = gen8_init_workarounds(engine); + ret = gen8_ctx_workarounds_init(dev_priv); if (ret) return ret; @@ -199,25 +178,8 @@ static int chv_init_workarounds(struct intel_engine_cs *engine) return 0; } -static int gen9_init_workarounds(struct intel_engine_cs *engine) +static int gen9_ctx_workarounds_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = engine->i915; - int ret; - - /* WaConextSwitchWithConcurrentTLBInvalidate:skl,bxt,kbl,glk,cfl */ - I915_WRITE(GEN9_CSFE_CHICKEN1_RCS, - _MASKED_BIT_ENABLE(GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE)); - - /* WaEnableLbsSlaRetryTimerDecrement:skl,bxt,kbl,glk,cfl */ - I915_WRITE(BDW_SCRATCH1, - I915_READ(BDW_SCRATCH1) | - GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE); - - /* WaDisableKillLogic:bxt,skl,kbl */ - if (!IS_COFFEELAKE(dev_priv)) - I915_WRITE(GAM_ECOCHK, - I915_READ(GAM_ECOCHK) | ECOCHK_DIS_TLB); - if (HAS_LLC(dev_priv)) { /* WaCompressedResourceSamplerPbeMediaNewHashMode:skl,kbl * @@ -228,11 +190,6 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) GEN9_PBE_COMPRESSED_HASH_SELECTION); WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7, GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR); - - I915_WRITE(MMCD_MISC_CTRL, - I915_READ(MMCD_MISC_CTRL) | - MMCD_PCLA | - MMCD_HOTSPOT_EN); } /* WaClearFlowControlGpgpuContextSave:skl,bxt,kbl,glk,cfl */ @@ -284,10 +241,6 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) WA_SET_BIT_MASKED(HDC_CHICKEN0, HDC_FORCE_NON_COHERENT); - /* WaDisableHDCInvalidation:skl,bxt,kbl,cfl */ - I915_WRITE(GAM_ECOCHK, - I915_READ(GAM_ECOCHK) | BDW_DISABLE_HDC_INVALIDATION); - /* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt,kbl,cfl */ if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv) || @@ -298,19 +251,6 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) /* WaDisableSTUnitPowerOptimization:skl,bxt,kbl,glk,cfl */ WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE); - /* WaProgramL3SqcReg1DefaultForPerf:bxt,glk */ - if (IS_GEN9_LP(dev_priv)) { - u32 val = I915_READ(GEN8_L3SQCREG1); - - val &= ~L3_PRIO_CREDITS_MASK; - val |= L3_GENERAL_PRIO_CREDITS(62) | L3_HIGH_PRIO_CREDITS(2); - I915_WRITE(GEN8_L3SQCREG1, val); - } - - /* WaOCLCoherentLineFlush:skl,bxt,kbl,cfl */ - I915_WRITE(GEN8_L3SQCREG4, - I915_READ(GEN8_L3SQCREG4) | GEN8_LQSC_FLUSH_COHERENT_LINES); - /* * Supporting preemption with fine-granularity requires changes in the * batch buffer programming. Since we can't break old userspace, we @@ -330,29 +270,11 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) GEN9_PREEMPT_GPGPU_LEVEL_MASK, GEN9_PREEMPT_GPGPU_COMMAND_LEVEL); - /* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt,glk,cfl */ - ret = wa_ring_whitelist_reg(engine, GEN9_CTX_PREEMPT_REG); - if (ret) - return ret; - - /* WaEnablePreemptionGranularityControlByUMD:skl,bxt,kbl,cfl,[cnl] */ - I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, - _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); - ret = wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1); - if (ret) - return ret; - - /* WaAllowUMDToModifyHDCChicken1:skl,bxt,kbl,glk,cfl */ - ret = wa_ring_whitelist_reg(engine, GEN8_HDC_CHICKEN1); - if (ret) - return ret; - return 0; } -static int skl_tune_iz_hashing(struct intel_engine_cs *engine) +static int skl_tune_iz_hashing(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = engine->i915; u8 vals[3] = { 0, 0, 0 }; unsigned int i; @@ -391,77 +313,97 @@ static int skl_tune_iz_hashing(struct intel_engine_cs *engine) return 0; } -static int skl_init_workarounds(struct intel_engine_cs *engine) +static int skl_ctx_workarounds_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = engine->i915; int ret; - ret = gen9_init_workarounds(engine); + ret = gen9_ctx_workarounds_init(dev_priv); if (ret) return ret; - /* WaEnableGapsTsvCreditFix:skl */ - I915_WRITE(GEN8_GARBCNTL, - I915_READ(GEN8_GARBCNTL) | GEN9_GAPS_TSV_CREDIT_DISABLE); - - /* WaDisableGafsUnitClkGating:skl */ - I915_WRITE(GEN7_UCGCTL4, - I915_READ(GEN7_UCGCTL4) | GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE); + return skl_tune_iz_hashing(dev_priv); +} - /* WaInPlaceDecompressionHang:skl */ - if (IS_SKL_REVID(dev_priv, SKL_REVID_H0, REVID_FOREVER)) - I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, - I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | - GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); +static int bxt_ctx_workarounds_init(struct drm_i915_private *dev_priv) +{ + int ret; - /* WaDisableLSQCROPERFforOCL:skl */ - ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4); + ret = gen9_ctx_workarounds_init(dev_priv); if (ret) return ret; - return skl_tune_iz_hashing(engine); + /* WaDisableThreadStallDopClockGating:bxt */ + WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, + STALL_DOP_GATING_DISABLE); + + /* WaToEnableHwFixForPushConstHWBug:bxt */ + WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, + GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); + + return 0; } -static int bxt_init_workarounds(struct intel_engine_cs *engine) +static int kbl_ctx_workarounds_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = engine->i915; int ret; - ret = gen9_init_workarounds(engine); + ret = gen9_ctx_workarounds_init(dev_priv); if (ret) return ret; - /* WaDisableThreadStallDopClockGating:bxt */ - WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, - STALL_DOP_GATING_DISABLE); + /* WaDisableFenceDestinationToSLM:kbl (pre-prod) */ + if (IS_KBL_REVID(dev_priv, KBL_REVID_A0, KBL_REVID_A0)) + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_FENCE_DEST_SLM_DISABLE); - /* WaDisablePooledEuLoadBalancingFix:bxt */ - I915_WRITE(FF_SLICE_CS_CHICKEN2, - _MASKED_BIT_ENABLE(GEN9_POOLED_EU_LOAD_BALANCING_FIX_DISABLE)); + /* WaToEnableHwFixForPushConstHWBug:kbl */ + if (IS_KBL_REVID(dev_priv, KBL_REVID_C0, REVID_FOREVER)) + WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, + GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); - /* WaToEnableHwFixForPushConstHWBug:bxt */ + /* WaDisableSbeCacheDispatchPortSharing:kbl */ + WA_SET_BIT_MASKED(GEN7_HALF_SLICE_CHICKEN1, + GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); + + return 0; +} + +static int glk_ctx_workarounds_init(struct drm_i915_private *dev_priv) +{ + int ret; + + ret = gen9_ctx_workarounds_init(dev_priv); + if (ret) + return ret; + + /* WaToEnableHwFixForPushConstHWBug:glk */ WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); - /* WaInPlaceDecompressionHang:bxt */ - I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, - I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | - GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); - return 0; } -static int cnl_init_workarounds(struct intel_engine_cs *engine) +static int cfl_ctx_workarounds_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = engine->i915; int ret; - /* WaDisableI2mCycleOnWRPort:cnl (pre-prod) */ - if (IS_CNL_REVID(dev_priv, CNL_REVID_B0, CNL_REVID_B0)) - I915_WRITE(GAMT_CHKN_BIT_REG, - I915_READ(GAMT_CHKN_BIT_REG) | - GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT); + ret = gen9_ctx_workarounds_init(dev_priv); + if (ret) + return ret; + + /* WaToEnableHwFixForPushConstHWBug:cfl */ + WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, + GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); + /* WaDisableSbeCacheDispatchPortSharing:cfl */ + WA_SET_BIT_MASKED(GEN7_HALF_SLICE_CHICKEN1, + GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); + + return 0; +} + +static int cnl_ctx_workarounds_init(struct drm_i915_private *dev_priv) +{ /* WaForceContextSaveRestoreNonCoherent:cnl */ WA_SET_BIT_MASKED(CNL_HDC_CHICKEN0, HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT); @@ -479,15 +421,10 @@ static int cnl_init_workarounds(struct intel_engine_cs *engine) WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE); - /* WaInPlaceDecompressionHang:cnl */ - I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, - I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | - GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); - /* WaPushConstantDereferenceHoldDisable:cnl */ WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2, PUSH_CONSTANT_DEREF_DISABLE); - /* FtrEnableFastAnisoL1BankingFix: cnl */ + /* FtrEnableFastAnisoL1BankingFix:cnl */ WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, CNL_FAST_ANISO_L1_BANKING_FIX); /* WaDisable3DMidCmdPreemption:cnl */ @@ -498,28 +435,173 @@ static int cnl_init_workarounds(struct intel_engine_cs *engine) GEN9_PREEMPT_GPGPU_LEVEL_MASK, GEN9_PREEMPT_GPGPU_COMMAND_LEVEL); - /* WaEnablePreemptionGranularityControlByUMD:cnl */ - I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, - _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); - ret = wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1); - if (ret) - return ret; - /* WaDisableEarlyEOT:cnl */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, DISABLE_EARLY_EOT); return 0; } -static int kbl_init_workarounds(struct intel_engine_cs *engine) +int intel_ctx_workarounds_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = engine->i915; - int ret; + int err = 0; - ret = gen9_init_workarounds(engine); + dev_priv->workarounds.count = 0; + + if (INTEL_GEN(dev_priv) < 8) + err = 0; + else if (IS_BROADWELL(dev_priv)) + err = bdw_ctx_workarounds_init(dev_priv); + else if (IS_CHERRYVIEW(dev_priv)) + err = chv_ctx_workarounds_init(dev_priv); + else if (IS_SKYLAKE(dev_priv)) + err = skl_ctx_workarounds_init(dev_priv); + else if (IS_BROXTON(dev_priv)) + err = bxt_ctx_workarounds_init(dev_priv); + else if (IS_KABYLAKE(dev_priv)) + err = kbl_ctx_workarounds_init(dev_priv); + else if (IS_GEMINILAKE(dev_priv)) + err = glk_ctx_workarounds_init(dev_priv); + else if (IS_COFFEELAKE(dev_priv)) + err = cfl_ctx_workarounds_init(dev_priv); + else if (IS_CANNONLAKE(dev_priv)) + err = cnl_ctx_workarounds_init(dev_priv); + else + MISSING_CASE(INTEL_GEN(dev_priv)); + if (err) + return err; + + DRM_DEBUG_DRIVER("Number of context specific w/a: %d\n", + dev_priv->workarounds.count); + return 0; +} + +int intel_ctx_workarounds_emit(struct i915_request *rq) +{ + struct i915_workarounds *w = &rq->i915->workarounds; + u32 *cs; + int ret, i; + + if (w->count == 0) + return 0; + + ret = rq->engine->emit_flush(rq, EMIT_BARRIER); if (ret) return ret; + cs = intel_ring_begin(rq, (w->count * 2 + 2)); + if (IS_ERR(cs)) + return PTR_ERR(cs); + + *cs++ = MI_LOAD_REGISTER_IMM(w->count); + for (i = 0; i < w->count; i++) { + *cs++ = i915_mmio_reg_offset(w->reg[i].addr); + *cs++ = w->reg[i].value; + } + *cs++ = MI_NOOP; + + intel_ring_advance(rq, cs); + + ret = rq->engine->emit_flush(rq, EMIT_BARRIER); + if (ret) + return ret; + + return 0; +} + +static void bdw_gt_workarounds_apply(struct drm_i915_private *dev_priv) +{ +} + +static void chv_gt_workarounds_apply(struct drm_i915_private *dev_priv) +{ +} + +static void gen9_gt_workarounds_apply(struct drm_i915_private *dev_priv) +{ + /* WaContextSwitchWithConcurrentTLBInvalidate:skl,bxt,kbl,glk,cfl */ + I915_WRITE(GEN9_CSFE_CHICKEN1_RCS, + _MASKED_BIT_ENABLE(GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE)); + + /* WaEnableLbsSlaRetryTimerDecrement:skl,bxt,kbl,glk,cfl */ + I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) | + GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE); + + /* WaDisableKillLogic:bxt,skl,kbl */ + if (!IS_COFFEELAKE(dev_priv)) + I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | + ECOCHK_DIS_TLB); + + if (HAS_LLC(dev_priv)) { + /* WaCompressedResourceSamplerPbeMediaNewHashMode:skl,kbl + * + * Must match Display Engine. See + * WaCompressedResourceDisplayNewHashMode. + */ + I915_WRITE(MMCD_MISC_CTRL, + I915_READ(MMCD_MISC_CTRL) | + MMCD_PCLA | + MMCD_HOTSPOT_EN); + } + + /* WaDisableHDCInvalidation:skl,bxt,kbl,cfl */ + I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | + BDW_DISABLE_HDC_INVALIDATION); + + /* WaProgramL3SqcReg1DefaultForPerf:bxt,glk */ + if (IS_GEN9_LP(dev_priv)) { + u32 val = I915_READ(GEN8_L3SQCREG1); + + val &= ~L3_PRIO_CREDITS_MASK; + val |= L3_GENERAL_PRIO_CREDITS(62) | L3_HIGH_PRIO_CREDITS(2); + I915_WRITE(GEN8_L3SQCREG1, val); + } + + /* WaOCLCoherentLineFlush:skl,bxt,kbl,cfl */ + I915_WRITE(GEN8_L3SQCREG4, + I915_READ(GEN8_L3SQCREG4) | GEN8_LQSC_FLUSH_COHERENT_LINES); + + /* WaEnablePreemptionGranularityControlByUMD:skl,bxt,kbl,cfl,[cnl] */ + I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, + _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); +} + +static void skl_gt_workarounds_apply(struct drm_i915_private *dev_priv) +{ + gen9_gt_workarounds_apply(dev_priv); + + /* WaEnableGapsTsvCreditFix:skl */ + I915_WRITE(GEN8_GARBCNTL, + I915_READ(GEN8_GARBCNTL) | GEN9_GAPS_TSV_CREDIT_DISABLE); + + /* WaDisableGafsUnitClkGating:skl */ + I915_WRITE(GEN7_UCGCTL4, + I915_READ(GEN7_UCGCTL4) | GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE); + + /* WaInPlaceDecompressionHang:skl */ + if (IS_SKL_REVID(dev_priv, SKL_REVID_H0, REVID_FOREVER)) + I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, + I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | + GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); +} + +static void bxt_gt_workarounds_apply(struct drm_i915_private *dev_priv) +{ + gen9_gt_workarounds_apply(dev_priv); + + /* WaDisablePooledEuLoadBalancingFix:bxt */ + I915_WRITE(FF_SLICE_CS_CHICKEN2, + _MASKED_BIT_ENABLE(GEN9_POOLED_EU_LOAD_BALANCING_FIX_DISABLE)); + + /* WaInPlaceDecompressionHang:bxt */ + I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, + I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | + GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); +} + +static void kbl_gt_workarounds_apply(struct drm_i915_private *dev_priv) +{ + gen9_gt_workarounds_apply(dev_priv); + /* WaEnableGapsTsvCreditFix:kbl */ I915_WRITE(GEN8_GARBCNTL, I915_READ(GEN8_GARBCNTL) | GEN9_GAPS_TSV_CREDIT_DISABLE); @@ -530,30 +612,139 @@ static int kbl_init_workarounds(struct intel_engine_cs *engine) I915_READ(GAMT_CHKN_BIT_REG) | GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING); - /* WaDisableFenceDestinationToSLM:kbl (pre-prod) */ - if (IS_KBL_REVID(dev_priv, KBL_REVID_A0, KBL_REVID_A0)) - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_FENCE_DEST_SLM_DISABLE); + /* WaDisableGafsUnitClkGating:kbl */ + I915_WRITE(GEN7_UCGCTL4, + I915_READ(GEN7_UCGCTL4) | GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE); - /* WaToEnableHwFixForPushConstHWBug:kbl */ - if (IS_KBL_REVID(dev_priv, KBL_REVID_C0, REVID_FOREVER)) - WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, - GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); + /* WaInPlaceDecompressionHang:kbl */ + I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, + I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | + GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); +} - /* WaDisableGafsUnitClkGating:kbl */ +static void glk_gt_workarounds_apply(struct drm_i915_private *dev_priv) +{ + gen9_gt_workarounds_apply(dev_priv); +} + +static void cfl_gt_workarounds_apply(struct drm_i915_private *dev_priv) +{ + gen9_gt_workarounds_apply(dev_priv); + + /* WaEnableGapsTsvCreditFix:cfl */ + I915_WRITE(GEN8_GARBCNTL, + I915_READ(GEN8_GARBCNTL) | GEN9_GAPS_TSV_CREDIT_DISABLE); + + /* WaDisableGafsUnitClkGating:cfl */ I915_WRITE(GEN7_UCGCTL4, I915_READ(GEN7_UCGCTL4) | GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE); - /* WaDisableSbeCacheDispatchPortSharing:kbl */ - WA_SET_BIT_MASKED(GEN7_HALF_SLICE_CHICKEN1, - GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); + /* WaInPlaceDecompressionHang:cfl */ + I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, + I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | + GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); +} - /* WaInPlaceDecompressionHang:kbl */ +static void cnl_gt_workarounds_apply(struct drm_i915_private *dev_priv) +{ + /* WaDisableI2mCycleOnWRPort:cnl (pre-prod) */ + if (IS_CNL_REVID(dev_priv, CNL_REVID_B0, CNL_REVID_B0)) + I915_WRITE(GAMT_CHKN_BIT_REG, + I915_READ(GAMT_CHKN_BIT_REG) | + GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT); + + /* WaInPlaceDecompressionHang:cnl */ I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | - GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); + GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); - /* WaDisableLSQCROPERFforOCL:kbl */ + /* WaEnablePreemptionGranularityControlByUMD:cnl */ + I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, + _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); +} + +void intel_gt_workarounds_apply(struct drm_i915_private *dev_priv) +{ + if (INTEL_GEN(dev_priv) < 8) + return; + else if (IS_BROADWELL(dev_priv)) + bdw_gt_workarounds_apply(dev_priv); + else if (IS_CHERRYVIEW(dev_priv)) + chv_gt_workarounds_apply(dev_priv); + else if (IS_SKYLAKE(dev_priv)) + skl_gt_workarounds_apply(dev_priv); + else if (IS_BROXTON(dev_priv)) + bxt_gt_workarounds_apply(dev_priv); + else if (IS_KABYLAKE(dev_priv)) + kbl_gt_workarounds_apply(dev_priv); + else if (IS_GEMINILAKE(dev_priv)) + glk_gt_workarounds_apply(dev_priv); + else if (IS_COFFEELAKE(dev_priv)) + cfl_gt_workarounds_apply(dev_priv); + else if (IS_CANNONLAKE(dev_priv)) + cnl_gt_workarounds_apply(dev_priv); + else + MISSING_CASE(INTEL_GEN(dev_priv)); +} + +static int wa_ring_whitelist_reg(struct intel_engine_cs *engine, + i915_reg_t reg) +{ + struct drm_i915_private *dev_priv = engine->i915; + struct i915_workarounds *wa = &dev_priv->workarounds; + const unsigned int index = wa->hw_whitelist_count[engine->id]; + + if (WARN_ON(index >= RING_MAX_NONPRIV_SLOTS)) + return -EINVAL; + + I915_WRITE(RING_FORCE_TO_NONPRIV(engine->mmio_base, index), + i915_mmio_reg_offset(reg)); + wa->hw_whitelist_count[engine->id]++; + + return 0; +} + +static int bdw_whitelist_workarounds_apply(struct intel_engine_cs *engine) +{ + return 0; +} + +static int chv_whitelist_workarounds_apply(struct intel_engine_cs *engine) +{ + return 0; +} + +static int gen9_whitelist_workarounds_apply(struct intel_engine_cs *engine) +{ + int ret; + + /* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt,glk,cfl */ + ret = wa_ring_whitelist_reg(engine, GEN9_CTX_PREEMPT_REG); + if (ret) + return ret; + + /* WaEnablePreemptionGranularityControlByUMD:skl,bxt,kbl,cfl,[cnl] */ + ret = wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1); + if (ret) + return ret; + + /* WaAllowUMDToModifyHDCChicken1:skl,bxt,kbl,glk,cfl */ + ret = wa_ring_whitelist_reg(engine, GEN8_HDC_CHICKEN1); + if (ret) + return ret; + + return 0; +} + +static int skl_whitelist_workarounds_apply(struct intel_engine_cs *engine) +{ + int ret; + + ret = gen9_whitelist_workarounds_apply(engine); + if (ret) + return ret; + + /* WaDisableLSQCROPERFforOCL:skl */ ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4); if (ret) return ret; @@ -561,126 +752,105 @@ static int kbl_init_workarounds(struct intel_engine_cs *engine) return 0; } -static int glk_init_workarounds(struct intel_engine_cs *engine) +static int bxt_whitelist_workarounds_apply(struct intel_engine_cs *engine) { - struct drm_i915_private *dev_priv = engine->i915; int ret; - ret = gen9_init_workarounds(engine); + ret = gen9_whitelist_workarounds_apply(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); + return 0; +} + +static int kbl_whitelist_workarounds_apply(struct intel_engine_cs *engine) +{ + int ret; + + ret = gen9_whitelist_workarounds_apply(engine); if (ret) return ret; - /* WaToEnableHwFixForPushConstHWBug:glk */ - WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, - GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); + /* WaDisableLSQCROPERFforOCL:kbl */ + ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4); + if (ret) + return ret; return 0; } -static int cfl_init_workarounds(struct intel_engine_cs *engine) +static int glk_whitelist_workarounds_apply(struct intel_engine_cs *engine) { - struct drm_i915_private *dev_priv = engine->i915; int ret; - ret = gen9_init_workarounds(engine); + ret = gen9_whitelist_workarounds_apply(engine); if (ret) return ret; - /* WaEnableGapsTsvCreditFix:cfl */ - I915_WRITE(GEN8_GARBCNTL, - I915_READ(GEN8_GARBCNTL) | GEN9_GAPS_TSV_CREDIT_DISABLE); + /* 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:cfl */ - WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, - GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); + return 0; +} - /* WaDisableGafsUnitClkGating:cfl */ - I915_WRITE(GEN7_UCGCTL4, - I915_READ(GEN7_UCGCTL4) | GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE); +static int cfl_whitelist_workarounds_apply(struct intel_engine_cs *engine) +{ + int ret; - /* WaDisableSbeCacheDispatchPortSharing:cfl */ - WA_SET_BIT_MASKED(GEN7_HALF_SLICE_CHICKEN1, - GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); + ret = gen9_whitelist_workarounds_apply(engine); + if (ret) + return ret; - /* WaInPlaceDecompressionHang:cfl */ - I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, - I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | - GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); + return 0; +} + +static int cnl_whitelist_workarounds_apply(struct intel_engine_cs *engine) +{ + int ret; + + /* WaEnablePreemptionGranularityControlByUMD:cnl */ + ret = wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1); + if (ret) + return ret; return 0; } -int init_workarounds_ring(struct intel_engine_cs *engine) +int intel_whitelist_workarounds_apply(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; - int err; + int err = 0; - if (GEM_WARN_ON(engine->id != RCS)) - return -EINVAL; + WARN_ON(engine->id != RCS); - dev_priv->workarounds.count = 0; dev_priv->workarounds.hw_whitelist_count[engine->id] = 0; - if (IS_BROADWELL(dev_priv)) - err = bdw_init_workarounds(engine); + if (INTEL_GEN(dev_priv) < 8) + err = 0; + else if (IS_BROADWELL(dev_priv)) + err = bdw_whitelist_workarounds_apply(engine); else if (IS_CHERRYVIEW(dev_priv)) - err = chv_init_workarounds(engine); + err = chv_whitelist_workarounds_apply(engine); else if (IS_SKYLAKE(dev_priv)) - err = skl_init_workarounds(engine); + err = skl_whitelist_workarounds_apply(engine); else if (IS_BROXTON(dev_priv)) - err = bxt_init_workarounds(engine); + err = bxt_whitelist_workarounds_apply(engine); else if (IS_KABYLAKE(dev_priv)) - err = kbl_init_workarounds(engine); + err = kbl_whitelist_workarounds_apply(engine); else if (IS_GEMINILAKE(dev_priv)) - err = glk_init_workarounds(engine); + err = glk_whitelist_workarounds_apply(engine); else if (IS_COFFEELAKE(dev_priv)) - err = cfl_init_workarounds(engine); + err = cfl_whitelist_workarounds_apply(engine); else if (IS_CANNONLAKE(dev_priv)) - err = cnl_init_workarounds(engine); + err = cnl_whitelist_workarounds_apply(engine); else - err = 0; + MISSING_CASE(INTEL_GEN(dev_priv)); if (err) return err; - DRM_DEBUG_DRIVER("%s: Number of context specific w/a: %d\n", - engine->name, dev_priv->workarounds.count); - return 0; -} - -int intel_ring_workarounds_emit(struct i915_request *rq) -{ - struct i915_workarounds *w = &rq->i915->workarounds; - u32 *cs; - int ret, i; - - if (w->count == 0) - return 0; - - ret = rq->engine->emit_flush(rq, EMIT_BARRIER); - if (ret) - return ret; - - cs = intel_ring_begin(rq, w->count * 2 + 2); - if (IS_ERR(cs)) - return PTR_ERR(cs); - - *cs++ = MI_LOAD_REGISTER_IMM(w->count); - for (i = 0; i < w->count; i++) { - *cs++ = i915_mmio_reg_offset(w->reg[i].addr); - *cs++ = w->reg[i].value; - } - *cs++ = MI_NOOP; - - intel_ring_advance(rq, cs); - - ret = rq->engine->emit_flush(rq, EMIT_BARRIER); - if (ret) - return ret; - + DRM_DEBUG_DRIVER("%s: Number of whitelist w/a: %d\n", engine->name, + dev_priv->workarounds.hw_whitelist_count[engine->id]); return 0; } diff --git a/drivers/gpu/drm/i915/intel_workarounds.h b/drivers/gpu/drm/i915/intel_workarounds.h index 2afea73aeeae..d9b0cc5afb4a 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.h +++ b/drivers/gpu/drm/i915/intel_workarounds.h @@ -7,7 +7,11 @@ #ifndef _I915_WORKAROUNDS_H_ #define _I915_WORKAROUNDS_H_ -int init_workarounds_ring(struct intel_engine_cs *engine); -int intel_ring_workarounds_emit(struct i915_request *rq); +int intel_ctx_workarounds_init(struct drm_i915_private *dev_priv); +int intel_ctx_workarounds_emit(struct i915_request *rq); + +void intel_gt_workarounds_apply(struct drm_i915_private *dev_priv); + +int intel_whitelist_workarounds_apply(struct intel_engine_cs *engine); #endif -- cgit v1.2.3 From f212bf9abe5de9f938fecea7df07046e74052dde Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 11 Apr 2018 16:15:18 +0300 Subject: drm/i915/bios: filter out invalid DDC pins from VBT child devices The VBT contains the DDC pin to use for specific ports. Alas, sometimes the field appears to contain bogus data, and while we check for it later on in intel_gmbus_get_adapter() we fail to check the returned NULL on errors. Oops results. The simplest approach seems to be to catch and ignore the bogus DDC pins already at the VBT parsing phase, reverting to fixed per port default pins. This doesn't guarantee display working, but at least it prevents the oops. And we continue to be fuzzed by VBT. One affected machine is Dell Latitude 5590 where a BIOS upgrade added invalid DDC pins. Typical backtrace: [ 35.461411] WARN_ON(!intel_gmbus_is_valid_pin(dev_priv, pin)) [ 35.461432] WARNING: CPU: 6 PID: 411 at drivers/gpu/drm/i915/intel_i2c.c:844 intel_gmbus_get_adapter+0x32/0x37 [i915] [ 35.461437] Modules linked in: i915 ahci libahci dm_snapshot dm_bufio dm_raid raid456 async_raid6_recov async_pq raid6_pq async_xor xor async_memcpy async_tx [ 35.461445] CPU: 6 PID: 411 Comm: kworker/u16:2 Not tainted 4.16.0-rc7.x64-g1cda370ffded #1 [ 35.461447] Hardware name: Dell Inc. Latitude 5590/0MM81M, BIOS 1.1.9 03/13/2018 [ 35.461450] Workqueue: events_unbound async_run_entry_fn [ 35.461465] RIP: 0010:intel_gmbus_get_adapter+0x32/0x37 [i915] [ 35.461467] RSP: 0018:ffff9b4e43d47c40 EFLAGS: 00010286 [ 35.461469] RAX: 0000000000000000 RBX: ffff98f90639f800 RCX: ffffffffae051960 [ 35.461471] RDX: 0000000000000001 RSI: 0000000000000092 RDI: 0000000000000246 [ 35.461472] RBP: ffff98f905410000 R08: 0000004d062a83f6 R09: 00000000000003bd [ 35.461474] R10: 0000000000000031 R11: ffffffffad4eda58 R12: ffff98f905410000 [ 35.461475] R13: ffff98f9064c1000 R14: ffff9b4e43d47cf0 R15: ffff98f905410000 [ 35.461477] FS: 0000000000000000(0000) GS:ffff98f92e580000(0000) knlGS:0000000000000000 [ 35.461479] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 35.461481] CR2: 00007f5682359008 CR3: 00000001b700c005 CR4: 00000000003606e0 [ 35.461483] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 35.461484] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 35.461486] Call Trace: [ 35.461501] intel_hdmi_set_edid+0x37/0x27f [i915] [ 35.461515] intel_hdmi_detect+0x7c/0x97 [i915] [ 35.461518] drm_helper_probe_single_connector_modes+0xe1/0x6c0 [ 35.461521] drm_setup_crtcs+0x129/0xa6a [ 35.461523] ? __switch_to_asm+0x34/0x70 [ 35.461525] ? __switch_to_asm+0x34/0x70 [ 35.461527] ? __switch_to_asm+0x40/0x70 [ 35.461528] ? __switch_to_asm+0x34/0x70 [ 35.461529] ? __switch_to_asm+0x40/0x70 [ 35.461531] ? __switch_to_asm+0x34/0x70 [ 35.461532] ? __switch_to_asm+0x40/0x70 [ 35.461534] ? __switch_to_asm+0x34/0x70 [ 35.461536] __drm_fb_helper_initial_config_and_unlock+0x34/0x46f [ 35.461538] ? __switch_to_asm+0x40/0x70 [ 35.461541] ? _cond_resched+0x10/0x33 [ 35.461557] intel_fbdev_initial_config+0xf/0x1c [i915] [ 35.461560] async_run_entry_fn+0x2e/0xf5 [ 35.461563] process_one_work+0x15b/0x364 [ 35.461565] worker_thread+0x2c/0x3a0 [ 35.461567] ? process_one_work+0x364/0x364 [ 35.461568] kthread+0x10c/0x122 [ 35.461570] ? _kthread_create_on_node+0x5d/0x5d [ 35.461572] ret_from_fork+0x35/0x40 [ 35.461574] Code: 74 16 89 f6 48 8d 04 b6 48 c1 e0 05 48 29 f0 48 8d 84 c7 e8 11 00 00 c3 48 c7 c6 b0 19 1e c0 48 c7 c7 64 8a 1c c0 e8 47 88 ed ec <0f> 0b 31 c0 c3 8b 87 a4 04 00 00 80 e4 fc 09 c6 89 b7 a4 04 00 [ 35.461604] WARNING: CPU: 6 PID: 411 at drivers/gpu/drm/i915/intel_i2c.c:844 intel_gmbus_get_adapter+0x32/0x37 [i915] [ 35.461606] ---[ end trace 4fe1e63e2dd93373 ]--- [ 35.461609] BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 [ 35.461613] IP: i2c_transfer+0x4/0x86 [ 35.461614] PGD 0 P4D 0 [ 35.461616] Oops: 0000 [#1] SMP PTI [ 35.461618] Modules linked in: i915 ahci libahci dm_snapshot dm_bufio dm_raid raid456 async_raid6_recov async_pq raid6_pq async_xor xor async_memcpy async_tx [ 35.461624] CPU: 6 PID: 411 Comm: kworker/u16:2 Tainted: G W 4.16.0-rc7.x64-g1cda370ffded #1 [ 35.461625] Hardware name: Dell Inc. Latitude 5590/0MM81M, BIOS 1.1.9 03/13/2018 [ 35.461628] Workqueue: events_unbound async_run_entry_fn [ 35.461630] RIP: 0010:i2c_transfer+0x4/0x86 [ 35.461631] RSP: 0018:ffff9b4e43d47b30 EFLAGS: 00010246 [ 35.461633] RAX: ffff9b4e43d47b6e RBX: 0000000000000005 RCX: 0000000000000001 [ 35.461635] RDX: 0000000000000002 RSI: ffff9b4e43d47b80 RDI: 0000000000000000 [ 35.461636] RBP: ffff9b4e43d47bd8 R08: 0000004d062a83f6 R09: 00000000000003bd [ 35.461638] R10: 0000000000000031 R11: ffffffffad4eda58 R12: 0000000000000002 [ 35.461639] R13: 0000000000000001 R14: ffff9b4e43d47b6f R15: ffff9b4e43d47c07 [ 35.461641] FS: 0000000000000000(0000) GS:ffff98f92e580000(0000) knlGS:0000000000000000 [ 35.461643] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 35.461645] CR2: 0000000000000010 CR3: 00000001b700c005 CR4: 00000000003606e0 [ 35.461646] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 35.461647] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 35.461649] Call Trace: [ 35.461652] drm_do_probe_ddc_edid+0xb3/0x128 [ 35.461654] drm_get_edid+0xe5/0x38d [ 35.461669] intel_hdmi_set_edid+0x45/0x27f [i915] [ 35.461684] intel_hdmi_detect+0x7c/0x97 [i915] [ 35.461687] drm_helper_probe_single_connector_modes+0xe1/0x6c0 [ 35.461689] drm_setup_crtcs+0x129/0xa6a [ 35.461691] ? __switch_to_asm+0x34/0x70 [ 35.461693] ? __switch_to_asm+0x34/0x70 [ 35.461694] ? __switch_to_asm+0x40/0x70 [ 35.461696] ? __switch_to_asm+0x34/0x70 [ 35.461697] ? __switch_to_asm+0x40/0x70 [ 35.461698] ? __switch_to_asm+0x34/0x70 [ 35.461700] ? __switch_to_asm+0x40/0x70 [ 35.461701] ? __switch_to_asm+0x34/0x70 [ 35.461703] __drm_fb_helper_initial_config_and_unlock+0x34/0x46f [ 35.461705] ? __switch_to_asm+0x40/0x70 [ 35.461707] ? _cond_resched+0x10/0x33 [ 35.461724] intel_fbdev_initial_config+0xf/0x1c [i915] [ 35.461727] async_run_entry_fn+0x2e/0xf5 [ 35.461729] process_one_work+0x15b/0x364 [ 35.461731] worker_thread+0x2c/0x3a0 [ 35.461733] ? process_one_work+0x364/0x364 [ 35.461734] kthread+0x10c/0x122 [ 35.461736] ? _kthread_create_on_node+0x5d/0x5d [ 35.461738] ret_from_fork+0x35/0x40 [ 35.461739] Code: 5c fa e1 ad 48 89 df e8 ea fb ff ff e9 2a ff ff ff 0f 1f 44 00 00 31 c0 e9 43 fd ff ff 31 c0 45 31 e4 e9 c5 fd ff ff 41 54 55 53 <48> 8b 47 10 48 83 78 10 00 74 70 41 89 d4 48 89 f5 48 89 fb 65 [ 35.461756] RIP: i2c_transfer+0x4/0x86 RSP: ffff9b4e43d47b30 [ 35.461757] CR2: 0000000000000010 [ 35.461759] ---[ end trace 4fe1e63e2dd93374 ]--- Based on a patch by Fei Li. v2: s/reverting/sticking/ (Chris) Cc: stable@vger.kernel.org Cc: Fei Li Co-developed-by: Fei Li Reported-by: Pavel Nakonechnyi Reported-and-tested-by: Seweryn Kokot Reported-and-tested-by: Laszlo Valko Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105549 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105961 Reviewed-by: Chris Wilson Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180411131519.9091-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_bios.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 6aae88c4df52..0f25cecb942f 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1256,7 +1256,6 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, return; aux_channel = child->aux_channel; - ddc_pin = child->ddc_pin; is_dvi = child->device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING; is_dp = child->device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT; @@ -1296,9 +1295,15 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, DRM_DEBUG_KMS("Port %c is internal DP\n", port_name(port)); if (is_dvi) { - info->alternate_ddc_pin = map_ddc_pin(dev_priv, ddc_pin); - - sanitize_ddc_pin(dev_priv, port); + ddc_pin = map_ddc_pin(dev_priv, child->ddc_pin); + if (intel_gmbus_is_valid_pin(dev_priv, ddc_pin)) { + info->alternate_ddc_pin = ddc_pin; + sanitize_ddc_pin(dev_priv, port); + } else { + DRM_DEBUG_KMS("Port %c has invalid DDC pin %d, " + "sticking to defaults\n", + port_name(port), ddc_pin); + } } if (is_dp) { -- cgit v1.2.3 From e53a1058395435b8801591361b2be18adda869ff Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 11 Apr 2018 16:15:19 +0300 Subject: drm/i915/bios: reduce the scope of some local variables in parse_ddi_port() No functional changes. Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180411131519.9091-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_bios.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 0f25cecb942f..702d3fab97fc 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1215,10 +1215,8 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, { struct child_device_config *it, *child = NULL; struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port]; - uint8_t hdmi_level_shift; int i, j; bool is_dvi, is_hdmi, is_dp, is_edp, is_crt; - uint8_t aux_channel, ddc_pin; /* Each DDI port can have more than one value on the "DVO Port" field, * so look for all the possible values for each port. */ @@ -1255,8 +1253,6 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, if (!child) return; - aux_channel = child->aux_channel; - is_dvi = child->device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING; is_dp = child->device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT; is_crt = child->device_type & DEVICE_TYPE_ANALOG_OUTPUT; @@ -1295,6 +1291,8 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, DRM_DEBUG_KMS("Port %c is internal DP\n", port_name(port)); if (is_dvi) { + u8 ddc_pin; + ddc_pin = map_ddc_pin(dev_priv, child->ddc_pin); if (intel_gmbus_is_valid_pin(dev_priv, ddc_pin)) { info->alternate_ddc_pin = ddc_pin; @@ -1307,14 +1305,14 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, } if (is_dp) { - info->alternate_aux_channel = aux_channel; + info->alternate_aux_channel = child->aux_channel; sanitize_aux_ch(dev_priv, port); } if (bdb_version >= 158) { /* The VBT HDMI level shift values match the table we have. */ - hdmi_level_shift = child->hdmi_level_shifter_value; + u8 hdmi_level_shift = child->hdmi_level_shifter_value; DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n", port_name(port), hdmi_level_shift); -- cgit v1.2.3 From 61bf9719fa170cd73b1937770d08cb062e070958 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 12 Apr 2018 17:58:02 +0300 Subject: drm/i915/cnl: Use mmio access to context status buffer Evidence indicates that Cannonlake HWSP is not coherent as it should. Revert to using mmio access for now. Testcase: igt/gem_ctx_switch References: https://bugs.freedesktop.org/show_bug.cgi?id=105888 Cc: Chris Wilson Cc: Rafael Antognolli Cc: Rodrigo Vivi Signed-off-by: Mika Kuoppala Acked-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180412145802.23313-1-mika.kuoppala@linux.intel.com --- drivers/gpu/drm/i915/intel_engine_cs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 68898d58dd1e..1a8370779bbb 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -475,6 +475,9 @@ static bool csb_force_mmio(struct drm_i915_private *i915) if (intel_vgpu_active(i915) && !intel_vgpu_has_hwsp_emulation(i915)) return true; + if (IS_CANNONLAKE(i915)) + return true; + return false; } -- cgit v1.2.3 From fadec6eefe232696c5c471b40df33e6db616e854 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 13 Apr 2018 12:20:58 +0300 Subject: drm/i915: Update DRIVER_DATE to 20180413 Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 649c0f2f3bae..e50d9589d6e3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -84,8 +84,8 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20180308" -#define DRIVER_TIMESTAMP 1520513379 +#define DRIVER_DATE "20180413" +#define DRIVER_TIMESTAMP 1523611258 /* 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 -- cgit v1.2.3