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 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=42923 Tested-by: Manoj Iyer <manoj.iyer@canonical.com> Tested-by: Robert Hooker <robert.hooker@canonical.com> Tested-by: Keith Packard <keithp@keithp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Keith Packard <keithp@keithp.com>
This commit is contained in:
parent
f10cdea68b
commit
8d715f0024
|
@ -328,7 +328,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;
|
int count;
|
||||||
|
|
||||||
|
@ -344,6 +344,22 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
|
||||||
udelay(10);
|
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,
|
* 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
|
* if some sequence requires the GT to not power down then this function should
|
||||||
|
@ -356,15 +372,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 */
|
/* Forcewake is atomic in case we get in here without the lock */
|
||||||
if (atomic_add_return(1, &dev_priv->forcewake_count) == 1)
|
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);
|
I915_WRITE_NOTRACE(FORCEWAKE, 0);
|
||||||
POSTING_READ(FORCEWAKE);
|
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()
|
* see gen6_gt_force_wake_get()
|
||||||
*/
|
*/
|
||||||
|
@ -373,7 +395,7 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
|
||||||
WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
|
WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
|
||||||
|
|
||||||
if (atomic_dec_and_test(&dev_priv->forcewake_count))
|
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)
|
void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
|
||||||
|
@ -904,7 +926,8 @@ MODULE_LICENSE("GPL and additional rights");
|
||||||
#define NEEDS_FORCE_WAKE(dev_priv, reg) \
|
#define NEEDS_FORCE_WAKE(dev_priv, reg) \
|
||||||
(((dev_priv)->info->gen >= 6) && \
|
(((dev_priv)->info->gen >= 6) && \
|
||||||
((reg) < 0x40000) && \
|
((reg) < 0x40000) && \
|
||||||
((reg) != FORCEWAKE))
|
((reg) != FORCEWAKE) && \
|
||||||
|
((reg) != ECOBUS))
|
||||||
|
|
||||||
#define __i915_read(x, y) \
|
#define __i915_read(x, y) \
|
||||||
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
|
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
|
||||||
|
|
|
@ -107,6 +107,7 @@ struct opregion_header;
|
||||||
struct opregion_acpi;
|
struct opregion_acpi;
|
||||||
struct opregion_swsci;
|
struct opregion_swsci;
|
||||||
struct opregion_asle;
|
struct opregion_asle;
|
||||||
|
struct drm_i915_private;
|
||||||
|
|
||||||
struct intel_opregion {
|
struct intel_opregion {
|
||||||
struct opregion_header *header;
|
struct opregion_header *header;
|
||||||
|
@ -221,6 +222,8 @@ struct drm_i915_display_funcs {
|
||||||
struct drm_i915_gem_object *obj);
|
struct drm_i915_gem_object *obj);
|
||||||
int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
||||||
int x, int y);
|
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 */
|
/* clock updates for mode set */
|
||||||
/* cursor updates */
|
/* cursor updates */
|
||||||
/* render clock increase/decrease */
|
/* 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 void intel_detect_pch(struct drm_device *dev);
|
||||||
extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
|
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 */
|
/* overlay */
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
|
extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
|
||||||
|
@ -1353,7 +1361,8 @@ void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
|
||||||
#define NEEDS_FORCE_WAKE(dev_priv, reg) \
|
#define NEEDS_FORCE_WAKE(dev_priv, reg) \
|
||||||
(((dev_priv)->info->gen >= 6) && \
|
(((dev_priv)->info->gen >= 6) && \
|
||||||
((reg) < 0x40000) && \
|
((reg) < 0x40000) && \
|
||||||
((reg) != FORCEWAKE))
|
((reg) != FORCEWAKE) && \
|
||||||
|
((reg) != ECOBUS))
|
||||||
|
|
||||||
#define __i915_read(x, y) \
|
#define __i915_read(x, y) \
|
||||||
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg);
|
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg);
|
||||||
|
|
|
@ -3449,6 +3449,10 @@
|
||||||
|
|
||||||
#define FORCEWAKE 0xA18C
|
#define FORCEWAKE 0xA18C
|
||||||
#define FORCEWAKE_ACK 0x130090
|
#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_FREE_ENTRIES 0x120008
|
||||||
#define GT_FIFO_NUM_RESERVED_ENTRIES 20
|
#define GT_FIFO_NUM_RESERVED_ENTRIES 20
|
||||||
|
|
|
@ -8491,6 +8491,28 @@ static void intel_init_display(struct drm_device *dev)
|
||||||
|
|
||||||
/* For FIFO watermark updates */
|
/* For FIFO watermark updates */
|
||||||
if (HAS_PCH_SPLIT(dev)) {
|
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))
|
if (HAS_PCH_IBX(dev))
|
||||||
dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating;
|
dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating;
|
||||||
else if (HAS_PCH_CPT(dev))
|
else if (HAS_PCH_CPT(dev))
|
||||||
|
|
Loading…
Reference in a new issue