On Sat, Nov 19, 2011 at 12:33 AM, Keith Packard <keithp at keithp.com> wrote: > On Fri, 18 Nov 2011 14:48:39 -0800, Jesse Barnes <jbarnes at virtuousgeek.org> wrote: > >> So the ECOBUS reg *is* in the GT power well. ?Which means in order to >> read it we have to disable RC6 altogether, forcibly, using the 0xa090 >> reg, set up force wake, then re-enable RC6. > > Here's what I cooked up -- it uses the MT version of the force wake code > to make the ECOBUS value visible. Seems to work for me, but additional > testing is encouraged. In particular, it'd be good to test on your > existing machine which *isn't* using MT forcewake. > > From b23581d5c978c96266f690239cc0d5f19480df98 Mon Sep 17 00:00:00 2001 > From: Keith Packard <keithp at keithp.com> > Date: Fri, 18 Nov 2011 20:39:01 -0800 > Subject: [PATCH 1/2] drm/i915: add multi-threaded forcewake support > > On IVB C0+ with newer BIOSes, the forcewake handshake has changed. ?There's > now a bitfield for different driver components to keep the GT powered > on. ?On Linux, we centralize forcewake handling in one place, so we > still just need a single bit, but we need to use the new registers if MT > forcewake is enabled. > > This needs testing on affected machines. ?Please reply with your > tested-by if you had problems after a BIOS upgrade and this patch fixes > them. > > v2: force MT mode. shift by 16 > v3: set MT force wake bits then check ECOBUS > > Tested-by: Keith Packard <keithp at keithp.com> > Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org> > Signed-off-by: Keith Packard <keithp at keithp.com> > --- > ?drivers/gpu/drm/i915/i915_drv.c ? ? ?| ? 35 ++++++++++++++++++++++++++++----- > ?drivers/gpu/drm/i915/i915_drv.h ? ? ?| ? 13 ++++++++++- > ?drivers/gpu/drm/i915/i915_reg.h ? ? ?| ? ?4 +++ > ?drivers/gpu/drm/i915/intel_display.c | ? 22 +++++++++++++++++++++ > ?4 files changed, 66 insertions(+), 8 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c > index 13488be..bd82ef0 100644 > --- a/drivers/gpu/drm/i915/i915_drv.c > +++ b/drivers/gpu/drm/i915/i915_drv.c > @@ -327,7 +327,7 @@ void intel_detect_pch(struct drm_device *dev) > ? ? ? ?} > ?} > > -static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) > +void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) > ?{ > ? ? ? ?int count; > > @@ -343,6 +343,22 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) > ? ? ? ? ? ? ? ?udelay(10); > ?} > > +void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) > +{ > + ? ? ? int count; > + > + ? ? ? count = 0; > + ? ? ? while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_MT_ACK) & 1)) > + ? ? ? ? ? ? ? udelay(10); > + > + ? ? ? I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 1); > + ? ? ? POSTING_READ(FORCEWAKE_MT); > + > + ? ? ? count = 0; > + ? ? ? while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_MT_ACK) & 1) == 0) > + ? ? ? ? ? ? ? udelay(10); > +} > + > ?/* > ?* Generally this is called implicitly by the register read function. However, > ?* if some sequence requires the GT to not power down then this function should > @@ -355,15 +371,21 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) > > ? ? ? ?/* Forcewake is atomic in case we get in here without the lock */ > ? ? ? ?if (atomic_add_return(1, &dev_priv->forcewake_count) == 1) > - ? ? ? ? ? ? ? __gen6_gt_force_wake_get(dev_priv); > + ? ? ? ? ? ? ? dev_priv->display.force_wake_get(dev_priv); > ?} > > -static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) > +void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) > ?{ > ? ? ? ?I915_WRITE_NOTRACE(FORCEWAKE, 0); > ? ? ? ?POSTING_READ(FORCEWAKE); > ?} > > +void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv) > +{ > + ? ? ? I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 0); > + ? ? ? POSTING_READ(FORCEWAKE_MT); > +} > + > ?/* > ?* see gen6_gt_force_wake_get() > ?*/ > @@ -372,7 +394,7 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) > ? ? ? ?WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); > > ? ? ? ?if (atomic_dec_and_test(&dev_priv->forcewake_count)) > - ? ? ? ? ? ? ? __gen6_gt_force_wake_put(dev_priv); > + ? ? ? ? ? ? ? dev_priv->display.force_wake_put(dev_priv); > ?} > > ?void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) > @@ -902,8 +924,9 @@ MODULE_LICENSE("GPL and additional rights"); > ?/* We give fast paths for the really cool registers */ > ?#define NEEDS_FORCE_WAKE(dev_priv, reg) \ > ? ? ? ?(((dev_priv)->info->gen >= 6) && \ > - ? ? ? ((reg) < 0x40000) && \ > - ? ? ? ((reg) != FORCEWAKE)) > + ? ? ? ?((reg) < 0x40000) && ? ? ? ? ? ?\ > + ? ? ? ?((reg) != FORCEWAKE) && ? ? ? ? \ > + ? ? ? ?((reg) != ECOBUS)) > > ?#define __i915_read(x, y) \ > ?u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index 4a9c1b9..8ba88cf 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -107,6 +107,7 @@ struct opregion_header; > ?struct opregion_acpi; > ?struct opregion_swsci; > ?struct opregion_asle; > +struct drm_i915_private; > > ?struct intel_opregion { > ? ? ? ?struct opregion_header *header; > @@ -221,6 +222,8 @@ struct drm_i915_display_funcs { > ? ? ? ? ? ? ? ? ? ? ? ? ?struct drm_i915_gem_object *obj); > ? ? ? ?int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb, > ? ? ? ? ? ? ? ? ? ? ? ? ? ?int x, int y); > + ? ? ? void (*force_wake_get)(struct drm_i915_private *dev_priv); > + ? ? ? void (*force_wake_put)(struct drm_i915_private *dev_priv); > ? ? ? ?/* clock updates for mode set */ > ? ? ? ?/* cursor updates */ > ? ? ? ?/* render clock increase/decrease */ > @@ -1308,6 +1311,11 @@ extern void gen6_set_rps(struct drm_device *dev, u8 val); > ?extern void intel_detect_pch(struct drm_device *dev); > ?extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); > > +extern void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); > +extern void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv); > +extern void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); > +extern void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv); > + > ?/* overlay */ > ?#ifdef CONFIG_DEBUG_FS > ?extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); > @@ -1352,8 +1360,9 @@ void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv); > ?/* We give fast paths for the really cool registers */ > ?#define NEEDS_FORCE_WAKE(dev_priv, reg) \ > ? ? ? ?(((dev_priv)->info->gen >= 6) && \ > - ? ? ? ((reg) < 0x40000) && \ > - ? ? ? ((reg) != FORCEWAKE)) > + ? ? ? ?((reg) < 0x40000) && ? ? ? ? ? ?\ > + ? ? ? ?((reg) != FORCEWAKE) && ? ? ? ? \ > + ? ? ? ?((reg) != ECOBUS)) > > ?#define __i915_read(x, y) \ > ? ? ? ?u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg); > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > index b080cc8..8990057 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -3449,6 +3449,10 @@ > > ?#define ?FORCEWAKE ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0xA18C > ?#define ?FORCEWAKE_ACK ? ? ? ? ? ? ? ? ? ? ? ? 0x130090 > +#define ?FORCEWAKE_MT ? ? ? ? ? ? ? ? ? ? ? ? ?0xa188 /* multi-threaded */ > +#define ?FORCEWAKE_MT_ACK ? ? ? ? ? ? ? ? ? ? ?0x130040 > +#define ?ECOBUS ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0xa180 > +#define ? ?FORCEWAKE_MT_ENABLE ? ? ? ? ? ? ? ? (1<<5) > > ?#define ?GT_FIFO_FREE_ENTRIES ? ? ? ? ? ? ? ? ?0x120008 > ?#define ? ?GT_FIFO_NUM_RESERVED_ENTRIES ? ? ? ? ? ? ? ?20 > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c > index e77a863..633c693 100644 > --- a/drivers/gpu/drm/i915/intel_display.c > +++ b/drivers/gpu/drm/i915/intel_display.c > @@ -8491,6 +8491,28 @@ static void intel_init_display(struct drm_device *dev) > > ? ? ? ?/* For FIFO watermark updates */ > ? ? ? ?if (HAS_PCH_SPLIT(dev)) { > + ? ? ? ? ? ? ? dev_priv->display.force_wake_get = __gen6_gt_force_wake_get; > + ? ? ? ? ? ? ? dev_priv->display.force_wake_put = __gen6_gt_force_wake_put; > + > + ? ? ? ? ? ? ? /* IVB configs may use multi-threaded forcewake */ > + ? ? ? ? ? ? ? if (IS_IVYBRIDGE(dev)) { > + ? ? ? ? ? ? ? ? ? ? ? u32 ? ? ecobus; > + > + ? ? ? ? ? ? ? ? ? ? ? mutex_lock(&dev->struct_mutex); > + ? ? ? ? ? ? ? ? ? ? ? __gen6_gt_force_wake_mt_get(dev_priv); > + ? ? ? ? ? ? ? ? ? ? ? ecobus = I915_READ(ECOBUS); > + ? ? ? ? ? ? ? ? ? ? ? __gen6_gt_force_wake_mt_put(dev_priv); > + ? ? ? ? ? ? ? ? ? ? ? mutex_unlock(&dev->struct_mutex); > + > + ? ? ? ? ? ? ? ? ? ? ? if (ecobus & FORCEWAKE_MT_ENABLE) { > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DRM_DEBUG_KMS("Using MT version of forcewake\n"); > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dev_priv->display.force_wake_get = > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? __gen6_gt_force_wake_mt_get; > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dev_priv->display.force_wake_put = > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? __gen6_gt_force_wake_mt_put; > + ? ? ? ? ? ? ? ? ? ? ? } > + ? ? ? ? ? ? ? } > + > ? ? ? ? ? ? ? ?if (HAS_PCH_IBX(dev)) > ? ? ? ? ? ? ? ? ? ? ? ?dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating; > ? ? ? ? ? ? ? ?else if (HAS_PCH_CPT(dev)) > -- > 1.7.7.3 > > -- > keith.packard at intel.com > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx at lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx > > Keith's version works here as well on 2 ivybridge platforms, thank you! Tested-by: Robert Hooker <robert.hooker at canonical.com>