aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2011-11-18 23:39:01 -0500
committerKeith Packard <keithp@keithp.com>2011-11-23 16:07:11 -0500
commit8d715f0024f64ad1b1be85d8c081cf577944c847 (patch)
tree4a0d1f1f36769c60b81fa3deb67ea791d5acc9bf
parentf10cdea68b70bd85706baed0decab59618f9c353 (diff)
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>
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c35
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h13
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h4
-rw-r--r--drivers/gpu/drm/i915/intel_display.c22
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 15bfa9145d2..28836fe7221 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -328,7 +328,7 @@ void intel_detect_pch(struct drm_device *dev)
328 } 328 }
329} 329}
330 330
331static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) 331void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
332{ 332{
333 int count; 333 int count;
334 334
@@ -344,6 +344,22 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
344 udelay(10); 344 udelay(10);
345} 345}
346 346
347void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
348{
349 int count;
350
351 count = 0;
352 while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_MT_ACK) & 1))
353 udelay(10);
354
355 I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 1);
356 POSTING_READ(FORCEWAKE_MT);
357
358 count = 0;
359 while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_MT_ACK) & 1) == 0)
360 udelay(10);
361}
362
347/* 363/*
348 * Generally this is called implicitly by the register read function. However, 364 * Generally this is called implicitly by the register read function. However,
349 * if some sequence requires the GT to not power down then this function should 365 * 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)
356 372
357 /* Forcewake is atomic in case we get in here without the lock */ 373 /* Forcewake is atomic in case we get in here without the lock */
358 if (atomic_add_return(1, &dev_priv->forcewake_count) == 1) 374 if (atomic_add_return(1, &dev_priv->forcewake_count) == 1)
359 __gen6_gt_force_wake_get(dev_priv); 375 dev_priv->display.force_wake_get(dev_priv);
360} 376}
361 377
362static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) 378void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
363{ 379{
364 I915_WRITE_NOTRACE(FORCEWAKE, 0); 380 I915_WRITE_NOTRACE(FORCEWAKE, 0);
365 POSTING_READ(FORCEWAKE); 381 POSTING_READ(FORCEWAKE);
366} 382}
367 383
384void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
385{
386 I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 0);
387 POSTING_READ(FORCEWAKE_MT);
388}
389
368/* 390/*
369 * see gen6_gt_force_wake_get() 391 * see gen6_gt_force_wake_get()
370 */ 392 */
@@ -373,7 +395,7 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
373 WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); 395 WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
374 396
375 if (atomic_dec_and_test(&dev_priv->forcewake_count)) 397 if (atomic_dec_and_test(&dev_priv->forcewake_count))
376 __gen6_gt_force_wake_put(dev_priv); 398 dev_priv->display.force_wake_put(dev_priv);
377} 399}
378 400
379void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) 401void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
@@ -903,8 +925,9 @@ MODULE_LICENSE("GPL and additional rights");
903/* We give fast paths for the really cool registers */ 925/* We give fast paths for the really cool registers */
904#define NEEDS_FORCE_WAKE(dev_priv, reg) \ 926#define NEEDS_FORCE_WAKE(dev_priv, reg) \
905 (((dev_priv)->info->gen >= 6) && \ 927 (((dev_priv)->info->gen >= 6) && \
906 ((reg) < 0x40000) && \ 928 ((reg) < 0x40000) && \
907 ((reg) != FORCEWAKE)) 929 ((reg) != FORCEWAKE) && \
930 ((reg) != ECOBUS))
908 931
909#define __i915_read(x, y) \ 932#define __i915_read(x, y) \
910u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ 933u##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 4a9c1b97980..8ba88cfc36d 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -107,6 +107,7 @@ struct opregion_header;
107struct opregion_acpi; 107struct opregion_acpi;
108struct opregion_swsci; 108struct opregion_swsci;
109struct opregion_asle; 109struct opregion_asle;
110struct drm_i915_private;
110 111
111struct intel_opregion { 112struct intel_opregion {
112 struct opregion_header *header; 113 struct opregion_header *header;
@@ -221,6 +222,8 @@ struct drm_i915_display_funcs {
221 struct drm_i915_gem_object *obj); 222 struct drm_i915_gem_object *obj);
222 int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb, 223 int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
223 int x, int y); 224 int x, int y);
225 void (*force_wake_get)(struct drm_i915_private *dev_priv);
226 void (*force_wake_put)(struct drm_i915_private *dev_priv);
224 /* clock updates for mode set */ 227 /* clock updates for mode set */
225 /* cursor updates */ 228 /* cursor updates */
226 /* render clock increase/decrease */ 229 /* render clock increase/decrease */
@@ -1308,6 +1311,11 @@ extern void gen6_set_rps(struct drm_device *dev, u8 val);
1308extern void intel_detect_pch(struct drm_device *dev); 1311extern void intel_detect_pch(struct drm_device *dev);
1309extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); 1312extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
1310 1313
1314extern void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
1315extern void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv);
1316extern void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
1317extern void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv);
1318
1311/* overlay */ 1319/* overlay */
1312#ifdef CONFIG_DEBUG_FS 1320#ifdef CONFIG_DEBUG_FS
1313extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); 1321extern 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);
1352/* We give fast paths for the really cool registers */ 1360/* We give fast paths for the really cool registers */
1353#define NEEDS_FORCE_WAKE(dev_priv, reg) \ 1361#define NEEDS_FORCE_WAKE(dev_priv, reg) \
1354 (((dev_priv)->info->gen >= 6) && \ 1362 (((dev_priv)->info->gen >= 6) && \
1355 ((reg) < 0x40000) && \ 1363 ((reg) < 0x40000) && \
1356 ((reg) != FORCEWAKE)) 1364 ((reg) != FORCEWAKE) && \
1365 ((reg) != ECOBUS))
1357 1366
1358#define __i915_read(x, y) \ 1367#define __i915_read(x, y) \
1359 u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg); 1368 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 b080cc82400..8990057e384 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3449,6 +3449,10 @@
3449 3449
3450#define FORCEWAKE 0xA18C 3450#define FORCEWAKE 0xA18C
3451#define FORCEWAKE_ACK 0x130090 3451#define FORCEWAKE_ACK 0x130090
3452#define FORCEWAKE_MT 0xa188 /* multi-threaded */
3453#define FORCEWAKE_MT_ACK 0x130040
3454#define ECOBUS 0xa180
3455#define FORCEWAKE_MT_ENABLE (1<<5)
3452 3456
3453#define GT_FIFO_FREE_ENTRIES 0x120008 3457#define GT_FIFO_FREE_ENTRIES 0x120008
3454#define GT_FIFO_NUM_RESERVED_ENTRIES 20 3458#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 e77a863a383..633c6936538 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)
8491 8491
8492 /* For FIFO watermark updates */ 8492 /* For FIFO watermark updates */
8493 if (HAS_PCH_SPLIT(dev)) { 8493 if (HAS_PCH_SPLIT(dev)) {
8494 dev_priv->display.force_wake_get = __gen6_gt_force_wake_get;
8495 dev_priv->display.force_wake_put = __gen6_gt_force_wake_put;
8496
8497 /* IVB configs may use multi-threaded forcewake */
8498 if (IS_IVYBRIDGE(dev)) {
8499 u32 ecobus;
8500
8501 mutex_lock(&dev->struct_mutex);
8502 __gen6_gt_force_wake_mt_get(dev_priv);
8503 ecobus = I915_READ(ECOBUS);
8504 __gen6_gt_force_wake_mt_put(dev_priv);
8505 mutex_unlock(&dev->struct_mutex);
8506
8507 if (ecobus & FORCEWAKE_MT_ENABLE) {
8508 DRM_DEBUG_KMS("Using MT version of forcewake\n");
8509 dev_priv->display.force_wake_get =
8510 __gen6_gt_force_wake_mt_get;
8511 dev_priv->display.force_wake_put =
8512 __gen6_gt_force_wake_mt_put;
8513 }
8514 }
8515
8494 if (HAS_PCH_IBX(dev)) 8516 if (HAS_PCH_IBX(dev))
8495 dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating; 8517 dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating;
8496 else if (HAS_PCH_CPT(dev)) 8518 else if (HAS_PCH_CPT(dev))