Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d715f00 authored by Keith Packard's avatar Keith Packard
Browse files

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: default avatarManoj Iyer <manoj.iyer@canonical.com>
Tested-by: default avatarRobert Hooker <robert.hooker@canonical.com>
Tested-by: default avatarKeith Packard <keithp@keithp.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarKeith Packard <keithp@keithp.com>
parent f10cdea6
Loading
Loading
Loading
Loading
+29 −6
Original line number Diff line number Diff line
@@ -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;

@@ -344,6 +344,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
@@ -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 */
	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()
 */
@@ -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));

	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)
@@ -904,7 +926,8 @@ MODULE_LICENSE("GPL and additional rights");
#define NEEDS_FORCE_WAKE(dev_priv, reg) \
	(((dev_priv)->info->gen >= 6) && \
	 ((reg) < 0x40000) &&		 \
	((reg) != FORCEWAKE))
	 ((reg) != FORCEWAKE) &&	 \
	 ((reg) != ECOBUS))

#define __i915_read(x, y) \
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
+11 −2
Original line number Diff line number Diff line
@@ -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);
@@ -1353,7 +1361,8 @@ void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
#define NEEDS_FORCE_WAKE(dev_priv, reg) \
	(((dev_priv)->info->gen >= 6) && \
	 ((reg) < 0x40000) &&		 \
	((reg) != FORCEWAKE))
	 ((reg) != FORCEWAKE) &&	 \
	 ((reg) != ECOBUS))

#define __i915_read(x, y) \
	u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg);
+4 −0
Original line number Diff line number Diff line
@@ -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
+22 −0
Original line number Diff line number Diff line
@@ -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))