diff options
author | Keith Packard <keithp@keithp.com> | 2011-11-18 23:39:01 -0500 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2011-11-23 16:07:11 -0500 |
commit | 8d715f0024f64ad1b1be85d8c081cf577944c847 (patch) | |
tree | 4a0d1f1f36769c60b81fa3deb67ea791d5acc9bf /drivers | |
parent | f10cdea68b70bd85706baed0decab59618f9c353 (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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 35 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 4 | ||||
-rw-r--r-- | 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 15bfa9145d2b..28836fe72211 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 | ||
331 | static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) | 331 | void __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 | ||
347 | void __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 | ||
362 | static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) | 378 | void __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 | ||
384 | void __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 | ||
379 | void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) | 401 | void __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) \ |
910 | u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ | 933 | 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 4a9c1b979804..8ba88cfc36de 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -107,6 +107,7 @@ struct opregion_header; | |||
107 | struct opregion_acpi; | 107 | struct opregion_acpi; |
108 | struct opregion_swsci; | 108 | struct opregion_swsci; |
109 | struct opregion_asle; | 109 | struct opregion_asle; |
110 | struct drm_i915_private; | ||
110 | 111 | ||
111 | struct intel_opregion { | 112 | struct 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); | |||
1308 | extern void intel_detect_pch(struct drm_device *dev); | 1311 | extern void intel_detect_pch(struct drm_device *dev); |
1309 | extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); | 1312 | extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); |
1310 | 1313 | ||
1314 | extern void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); | ||
1315 | extern void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv); | ||
1316 | extern void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); | ||
1317 | extern 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 |
1313 | extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); | 1321 | 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); | |||
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 b080cc824001..8990057e384c 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 e77a863a3833..633c69365388 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)) |